#include "config.h"
#include <rust_types.h>
#include <keyboard.hpp>

#include <LiquidCrystal.h>
#include "lcd_font.h"
#include "mk61emu_core.h"
#include "mk61_mk52_cross_hal.h"

#define CUSTOM_CHARS 8

#define CUSTOM_CHAR_BUF_SIZE    8

const uint8_t customCharGlyphs_for_mk52[CUSTOM_CHARS][CUSTOM_CHAR_BUF_SIZE] = {
  {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F}, // #0
  {0x0F, 0x1F, 0x1F, 0x17, 0x07, 0x07, 0x07, 0x07}, // #1
  {0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07}, // #2
  {0x07, 0x0F, 0x1F, 0x1F, 0x1E, 0x1C, 0x18, 0x10}, // #3
  {0x10, 0x18, 0x1C, 0x1E, 0x1F, 0x1F, 0x0F, 0x07}, // #4
  {0x1F, 0x1F, 0x1F, 0,  0,    0,    0,    0},      // #5
  {0,    0,    0,    0,    0,    0x1F, 0x1F, 0x1F}, // #6
  {0x1F, 0x1F, 0x1F, 0,    0,    0,    0x1F, 0x1F}  // #7
};

const uint8_t customCharGlyphs_for_mk61[CUSTOM_CHARS][CUSTOM_CHAR_BUF_SIZE] = {
  { 0x07, 0x0F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }, // 0
  { 0x07, 0x0F, 0x1F, 0x1F, 0x1F, 0x17, 0x07, 0x07 }, // 1
  { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }, // 2
  { 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 }, // 3
  { 0x03, 0x07, 0x0F, 0x1F, 0x1E, 0x1C, 0x18, 0x10 }, // 4
  { 0x10, 0x18, 0x1C, 0x1E, 0x1F, 0x0F, 0x07, 0x03 }, // 5
  { 0x1F, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x1F, 0x1F }, // 6
  { 0x1F, 0x1F, 0x1F, 0x07, 0x07, 0x0F, 0x1E, 0x1C }  // 7
};

uint8_t mk52_glyph_L1[16] = {0, 1, 1, ' ', 0, 3, ' ', 0, 5, ' ', 5, 0, ' ', 0, 7, 7};
uint8_t mk52_glyph_L2[16] = {0, 2, 2, ' ', 0, 4, ' ', 6, 0, ' ', 0, 6, ' ', 6, 6, 0};
uint8_t mk61_glyph_L1[16] = {0, 1, 1, ' ', 0, 4, ' ', 0, 6, ' ', 4, 2, ' ', 0, 6, 6}; 
uint8_t mk61_glyph_L2[16] = {2, 3, 3, ' ', 2, 5, ' ', 2, 7, ' ', ' ', 2, ' ', 6, 6, 7};

#ifdef CDU
  LiquidCrystal lcd(PB9, PB8, PB5, PB4, PB3, PA15);
#else  
  LiquidCrystal lcd(PB9, PB8, PB5, PB4, PB3, PA15);
#endif

enum enum_core61_stage {START, NEXT};

struct TFieldLCD {
  u8 x, y;
};

const   TFieldLCD MNEMO_LCD = {.x=13, .y=0};

static  class_keyboard      keyboard;
static  u32                 exeq;
static  enum_core61_stage   core_stage;

#ifdef SERIAL_OUTPUT
  const   u8                  CR = 0x0D;
  static  u8                  input_from_serial[16];
  static  u8*                 recive_char;
#endif  


                              //0123456789ABCD
static char display_text[14]; //-12345678 -12
 
void mk61_display_refresh(void) {
    const bool changed = !MK61Emu_ReadIndicator(&display_text[0]); 
    if(changed) {
      lcd.setCursor(0, 1); lcd.print(display_text);
      #ifdef SERIAL_OUTPUT
        Serial.println(display_text);
      #endif
    }
}

void debug_key_info(i32 keycode) {
  const TMK61_cross_key cross_key = KeyPairs[keycode];
  #ifdef SERIAL_OUTPUT
    Serial.print(keycode);
    Serial.print("H (");
    Serial.print(cross_key.x);
    Serial.write(',');
    Serial.print(cross_key.y);
    Serial.println(") key -> mk61s");
  #endif
}

void /* __attribute__((optimize("O0"))) */ output_version(void){
  #ifdef SERIAL_OUTPUT
    Serial.print("MK52s ver. ");
    Serial.print(__DATE__);
    Serial.write('(');
    Serial.print(__TIME__);
    Serial.println(')');
  #endif
}

void setup() {
  #ifdef SERIAL_OUTPUT
    Serial.begin(115200);
    recive_char = (u8*)((u32)(&input_from_serial[0]) - 1);
  #endif
  output_version();
  keyboard.Init();
  memset(display_text, 0, sizeof(display_text));

  for(int i=0; i < CUSTOM_CHARS; i++) {
    lcd.createChar(i, (uint8_t*) &customCharGlyphs_for_mk61[i]);  
  }

  lcd.begin(16, 2);
  lcd.clear();
  lcd.setCursor(0, 0);
  for(int i=0; i<16; i++) {
    lcd.write(mk61_glyph_L1[i]);
  }
  lcd.setCursor(0, 1);
  for(int i=0; i<16; i++) {
    lcd.write(mk61_glyph_L2[i]);
  }

 // Тест ожидания нажатия кнопки на клавиатуре  
  //lcd.setCursor(0,1); lcd.print(" wait key press ");
  keyboard.get_key_wait();
  //lcd.setCursor(0,1); lcd.print("key = "); lcd.print((u8) keycode, HEX); lcd.print("        ");

  lcd.clear();
  lcd.createChar(1, (uint8_t*) &P_ru);
  lcd.createChar(2, (uint8_t*) &B_ru);
  lcd.setCursor(0, 0);
  lcd.print("MK61s");
 
 // Запуск эмулятора MK61
  core_stage = START;
  MK61Emu_ON();
  #ifdef SERIAL_OUTPUT
    Serial.println("ON");
  #endif
}

void loop_1() {
  keyboard.process(millis());

  const i32 keycode = keyboard.get_key(PRESS);
  if(keycode >= 0) {
    debug_key_info(keycode);
  }
}

void key_press_handler(i32 keycode) {
  const TMK61_cross_key cross_key = KeyPairs[keycode];  // трансляция кода клавиши в координаты клавиши mk61

  debug_key_info(keycode);

  keyboard.reset_scan_line();
  lcd.setCursor(MNEMO_LCD.x, MNEMO_LCD.y); lcd.print(mnemo_code[keycode]);

  MK61Emu_SetKeyPress(cross_key.x, cross_key.y); // передача нажатия в MK61s
}

inline void mk61_automate(void) {
/*  
   1. Взять кнопку, если она есть то:
       1.1. преобразовать в x,y координату контака для МК61
       1.2. DoKeyPrees(x,y)
       1.3. DoStep();
   2. exeq очистить
   3. Флаг отображения сбросить - _SetDisplayed(0);
   4. НАЧАЛО ЦИКЛА
   5. _DoStep()
   6. если exeq != 0, это "НЕ ПЕРВЫЕ ШАГИ В РЕЖИМЕ ПРОГРАММА" то:
       6.1. (отображаем это)
       6.2. проверяем в какой позиции запятая _GetComma() если она не в 11 позиции то ВЫХОД
   7. иначе: если posComma позиция запятой равна 11 "ПЕРВЫЙ ШАГ В РЕЖИМЕ ПРОГРАММА" exeq = 1 то:
       7.1. отобразим это  
       7.2. устанавливаем exeq = 1
   8. иначе: "РЕЖИМ АВТО" проверяем флаг _GetDisplayed если он установлен обновляем отображение и ВЫХОД
   9. в НАЧАЛО ЦИКЛА
  */

  i32 keycode;
  switch(core_stage) {
    case  START:
      keycode = keyboard.get_key(PRESS);
      if(keycode >= 0) {
        key_press_handler(keycode);
        MK61Emu_DoStep();
      } 

      exeq = 0;
      MK61Emu_SetDisplayed(0);
      core_stage = NEXT;
      break;
    case  NEXT:
      MK61Emu_DoStep();
      if(exeq != 0) {
        #ifdef SERIAL_OUTPUT
          Serial.println("mk61 next steps on PROGRAMM");
        #endif  

        mk61_display_refresh();
        keycode = keyboard.get_key(PRESS);
        if(keycode >= 0) key_press_handler(keycode);

        if(MK61Emu_GetComma() != 11) { // Останов программы
          #ifdef SERIAL_OUTPUT 
            Serial.println("mk61 STOP PROGRAMM");
          #endif
          core_stage = START;
        }    
      } else if(MK61Emu_GetComma() == 11) {
        #ifdef SERIAL_OUTPUT 
          Serial.println("mk61 first step on PROGRAMM");
        #endif
        exeq = 1;
      } else {
        if(MK61Emu_GetDisplayed() != 0) {
          mk61_display_refresh();
          core_stage = START;
        }
    }
  }
}

void serial_input_handler(void) {
  if(*recive_char == CR) {
    recive_char[0] = 0;
    Serial.println((char*) input_from_serial);

    const u32 token = *(u32*) input_from_serial;
    Serial.println(token, HEX);
    if(token == 0x00726576) {
      output_version();
    }
    recive_char = (u8*)((u32)(&input_from_serial[0]) - 1);
  }
}

void loop() {
  keyboard.next_scan_line();

  mk61_automate();
  
  #ifdef SERIAL_OUTPUT
    serial_input_handler();
  #endif

  keyboard.check_scan_line();
}

#ifdef SERIAL_OUTPUT
void serialEvent() {
  if(Serial.available() && *recive_char != CR) { // В UART что то свалилось и не выставлен флаг нуждается в обработке, принимаем
    const u8 inChar = Serial.read(); // вычитываем один символ
    *++recive_char = inChar;
  }
}
#endif
Loading
stm32-bluepill