/** * \file cimdit.ino * \brief main functions * \author GrumpyDeveloper (Sascha Nitsch) * \copyright 2022 Sascha Nitsch * Licensed under MIT license * */ // defines #include "defines.h" // library includes #include #ifdef HAVE_DISPLAY #include "cimditssd1306.h" #endif // own includes #include "cimdithal.h" #include "cimditprofile.h" /// our hardware abstraction layer CimditHAL hal; /// flag if the rotary interrupt has been triggered volatile bool outstandingRotInterrupt = false; /// interrupt service routine for rotatry change interrupt void rotInt() { outstandingRotInterrupt = true; } /// next update time in ms uint32_t nextUpdate = 0; #ifdef HAVE_DISPLAY /// our display CimditSSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_ADDRESS); #endif // our profile handling class CimditProfile profile; /// initial setup void setup() { Serial.begin(115200); hal.begin(); attachInterrupt(digitalPinToInterrupt(7), rotInt, RISING); // initialize USB related things Keyboard.begin(); Mouse.begin(); Gamepad.begin(); Wire.begin(); Wire.setClock(400000); #ifdef HAVE_DISPLAY // init display display.begin(); display.clearDisplay(); display.setTextSize(2,2); display.setCursor(28, 8); display.write("cimdit"); display.display(); #endif profile.begin(); } /// protection string const char protectString[] = "cimdit:"; /// current position in protection string uint8_t protectPos = 0; /// main loop void loop() { hal.readFromHardware(outstandingRotInterrupt); if (outstandingRotInterrupt) { outstandingRotInterrupt = false; return; } profile.tick(); if (Serial.available()) { // incoming message uint8_t in; while ((in = Serial.read()) != 255) { if (protectString[protectPos++] != in) { protectPos = 0; continue; } if (protectPos == sizeof(protectString) - 1) { // good, something for us protectPos = 0; // every line has to start with cimdit: or it will be ignored uint8_t cmd = Serial.read(); switch (cmd) { case 'd': profile.userDisplay(); break; case 'p': { // print something on display uint8_t timeout = 0; // read number for time to display do { cmd = Serial.read(); if (cmd != ',') { timeout = timeout * 10 + cmd - '0'; } } while (cmd != ','); char tmp[43] = {0}; uint8_t pos = 0; // now we expect the string, terminated by \n do { cmd = Serial.read(); if (cmd != '\n') { tmp[pos++] = cmd; } } while (cmd != '\n' && pos < 43 && cmd != 255); profile.setUserString(timeout, tmp); } break; case 'f': // read flash profile.printFlash(); break; case 'F': // write flash profile.writeFlash(); break; } } } } if (hal.m_millis < nextUpdate && hal.m_millis > ROLLOVER_INTERVAL) return; nextUpdate = hal.m_millis + UPDATE_INTERVAL; uint8_t rotaryChanged = hal.rotaryChanged(); if (rotaryChanged) { for (uint8_t i = 0; i < 8; ++i) { if (rotaryChanged & 1) { int8_t delta = hal.getEncoder(i); profile.rotaryAction(i, delta); } rotaryChanged >>= 1; } } uint16_t analogChanged = hal.analogChanged(); if (analogChanged) { for (uint8_t i = 0; i < 4; ++i) { if (analogChanged & 1) { uint16_t analog = hal.getAnalog(i); profile.axisAction(i, analog); } analogChanged >>= 1; } Gamepad.write(); } uint64_t buttonsChanged = hal.buttonsChanged(); if (buttonsChanged) { for (uint8_t i = 0; i < 64; ++i) { if (buttonsChanged & 0xFF) { // quickcheck for 8 bits at a time if (buttonsChanged & 1) { bool pressed = hal.getButton(i); profile.buttonAction(i, pressed); } buttonsChanged >>= 1; } else { buttonsChanged >>= 8; i += 7; } } } }