You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

171 lines
4.3 KiB

  1. /**
  2. * Video Terminal
  3. * VT100 emulated by ESP32 + TV display + LK201 keyboard
  4. *
  5. * TinTTY main sketch
  6. * by Nick Matantsev 2017
  7. *
  8. * Original reference: VT100 emulation code written by Martin K. Schroeder
  9. * and modified by Peter Scargill.
  10. */
  11. #include <SPI.h>
  12. #include <Adafruit_GFX.h>
  13. #include "tintty.h"
  14. #define SerialTty Serial1
  15. #define SerialKbd Serial2
  16. #include "Keyboard.h"
  17. #include "Display.h"
  18. Display display;
  19. int16_t scrolled = 0;
  20. uint16_t make_bw_color(uint16_t color) {
  21. return ((color >> 8) | (color & 0xFF)) & 0xFF + 0xFF00;
  22. }
  23. #define FONT_W display.font_w
  24. #define FONT_H display.font_h
  25. struct tintty_display composite_display = {
  26. display.vw, // width
  27. display.vh, // height
  28. display.vw / display.font_w, // chars horizontal
  29. display.vh / display.font_h, // chars vertical
  30. // fill rect
  31. [=](int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){
  32. display.fill_rect(x*FONT_W + display.ow, y*FONT_H + display.oh, w*FONT_W, h*FONT_H, make_bw_color(color));
  33. },
  34. // draw pixels
  35. [=](int16_t x, int16_t y, int16_t w, int16_t h, uint16_t *pixels){
  36. //tft.setAddrWindow(x, y, x + w - 1, y + h - 1);
  37. //tft.pushColors(pixels, w * h, 1);
  38. for (int px = 0; px < w; px++) {
  39. for (int py = 0; py < h; py++) {
  40. int i = py*w + px;
  41. //display.pixel(x + display.ow + px, y + display.oh + py, pixels[i]);
  42. //display.fill_rect(x*FONT_SCALE + display.ow + px*FONT_SCALE, y*FONT_SCALE + display.oh + py*FONT_SCALE, FONT_SCALE, FONT_SCALE, make_bw_color(pixels[i]));
  43. }
  44. }
  45. },
  46. // print character
  47. [=](int16_t col, int16_t row, uint16_t fg_color, uint16_t bg_color, char character){
  48. display.print_character(col, row - scrolled, make_bw_color(0), make_bw_color(0), ' ');
  49. display.print_character(col, row - scrolled, make_bw_color(fg_color), make_bw_color(bg_color), character);
  50. },
  51. // print cursor
  52. [=](int16_t col, int16_t row, uint16_t color){
  53. display.fill_rect(col*display.font_w + display.ow, (row+1 - scrolled)*display.font_h-1 + display.oh, display.font_w, 1, make_bw_color(color));
  54. //display.print_character(col, row, make_bw_color(color), 0, '_');
  55. },
  56. // scroll
  57. [=](int16_t offset){
  58. //tft.vertScroll(0, (ILI9341_HEIGHT - KEYBOARD_HEIGHT), offset);
  59. int16_t rows = display.vh / display.font_h;
  60. int16_t diff = (rows + offset - (scrolled % rows)) % rows;
  61. display.scroll(diff*display.font_h);
  62. scrolled += diff;
  63. }
  64. };
  65. /**
  66. * Keyboard callbacks.
  67. */
  68. struct tintty_keyboard lk201_keyboard = {
  69. [=]() {
  70. Serial.print("<BELL RING> ");
  71. SerialKbd.print((char)LK_RING_BELL);
  72. }
  73. };
  74. void tty_keyboard_process()
  75. {
  76. // read keyboard and send it to the host
  77. if (SerialKbd.available() > 0) {
  78. int key = SerialKbd.read();
  79. keyboard_handle_key(key);
  80. }
  81. }
  82. // buffer to test various input sequences
  83. char *test_buffer = "-- \e[1mTinTTY\e[m --\r\n";
  84. uint8_t test_buffer_cursor = 0;
  85. void input_init() {};
  86. void input_idle() {};
  87. void setup() {
  88. // Debug port
  89. Serial.begin(115200);
  90. Serial.println("Running!");
  91. // TTY host
  92. SerialTty.begin(9600, SERIAL_8N1, 18, 19, false, 100);
  93. // LK201 keyboard connected to pins 16 and 17
  94. SerialKbd.begin(4800);
  95. display.setup();
  96. //uint16_t tftID = tft.readID();
  97. //tft.begin(tftID);
  98. input_init();
  99. tintty_run(
  100. [=](){
  101. // peek idle loop
  102. while (true) {
  103. // first peek from the test buffer
  104. if (test_buffer[test_buffer_cursor]) {
  105. return test_buffer[test_buffer_cursor];
  106. }
  107. tty_keyboard_process();
  108. // fall back to normal blocking serial input
  109. if (SerialTty.available() > 0) {
  110. return (char)SerialTty.peek();
  111. }
  112. // idle logic only after peeks failed
  113. tintty_idle(&composite_display);
  114. input_idle();
  115. }
  116. },
  117. [=](){
  118. while(true) {
  119. // process at least one idle loop first to allow input to happen
  120. tintty_idle(&composite_display);
  121. input_idle();
  122. tty_keyboard_process();
  123. // first read from the test buffer
  124. if (test_buffer[test_buffer_cursor]) {
  125. return test_buffer[test_buffer_cursor++];
  126. }
  127. // fall back to normal blocking serial input
  128. if (SerialTty.available() > 0) {
  129. return (char)SerialTty.read();
  130. }
  131. }
  132. },
  133. [=](char ch){ SerialTty.print(ch); },
  134. &composite_display,
  135. &lk201_keyboard
  136. );
  137. }
  138. void loop() {
  139. }