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.

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