diff --git a/i2c_protocol.py b/i2c_protocol.py new file mode 100644 index 0000000..58c6772 --- /dev/null +++ b/i2c_protocol.py @@ -0,0 +1,53 @@ +import serial +import struct +import time + +class I2CPCClient: + def __init__(self, port, baudrate=115200, timeout=1): + self.ser = serial.Serial(port=port, baudrate=baudrate, timeout=timeout) + self.ser.write(b"~/") + self.ser.flush() + while not ((d := self.ser.read_all()) and b"\x01\xff" in d): pass + + def _send_packet(self, payload: bytes): + length = len(payload) + self.ser.write(bytes([length]) + payload) + + # Read response length + resp_len_raw = self.ser.read(1) + if not resp_len_raw: + raise TimeoutError("Error") + + resp_len = resp_len_raw[0] + response = self.ser.read(resp_len) + + if len(response) != resp_len: raise TimeoutError("Incomplete response") + + return response + + def set_clock(self, clock_hz: int): + payload = bytes([0]) + struct.pack(">I", clock_hz) + return self._send_packet(payload) + + def write_i2c(self, addr: int, data: bytes): + payload = bytes([1, addr]) + data + return self._send_packet(payload) + + def write_read_i2c(self, addr: int, write_data: bytes, read_len: int): + payload = bytes([2, addr, len(write_data)]) + write_data + bytes([read_len]) + return self._send_packet(payload) + + def version(self): return self._send_packet(bytes([4])) + + def quit(self): return self._send_packet(bytes([3])) + + def reboot(self): return self._send_packet(bytes([5])) + + def set_baudrate(self, baud: int): + payload = bytes([6]) + struct.pack(">I", baud) + out = self._send_packet(payload) + self.ser.baudrate = baud + return out + + def close(self): + self.ser.close() \ No newline at end of file diff --git a/include/comms.h b/include/comms.h index aef0584..5eb1088 100644 --- a/include/comms.h +++ b/include/comms.h @@ -9,6 +9,7 @@ void Communication(); void XDRGTKRoutine(); void passwordcrypt(); void tryWiFi(); +void total_pc_control(); extern void BuildDisplay(); extern void BuildAdvancedRDS(); diff --git a/include/globals.h b/include/globals.h index bc26f95..3ef294b 100644 --- a/include/globals.h +++ b/include/globals.h @@ -336,6 +336,9 @@ extern bool rds_settings_changed; extern const size_t language_totalnumber; extern const size_t language_entrynumber; +extern volatile bool i2c_pc_control; +extern volatile bool i2c_pc_control_init; + extern mem presets[EE_PRESETS_CNT]; extern TEF6686 radio; diff --git a/include/system_console.h b/include/system_console.h index 67a96a2..c066bf1 100644 --- a/include/system_console.h +++ b/include/system_console.h @@ -2,6 +2,8 @@ #include #include +#define CONSOLE_FONT 2 + class Console { public: explicit Console(TFT_eSPI* display) : tft(display), y(0) {} @@ -9,9 +11,9 @@ public: tft->setTextColor(TFT_WHITE, background); tft->setTextDatum(TL_DATUM); auto data = "[" + String(millis() / 1000.0f) + "] " + text; - tft->fillRect(0, y, tft->textWidth(data), tft->fontHeight(2), background); - tft->drawString(data, 0, y, 2); - y += tft->fontHeight(2); + tft->fillRect(0, y, tft->textWidth(data, CONSOLE_FONT), tft->fontHeight(CONSOLE_FONT), background); + tft->drawString(data, 0, y, CONSOLE_FONT); + y += tft->fontHeight(CONSOLE_FONT); } void reset() { y = 0; diff --git a/src/comms.cpp b/src/comms.cpp index fa6ab4d..eec9ba0 100644 --- a/src/comms.cpp +++ b/src/comms.cpp @@ -359,6 +359,11 @@ void Communication() { } } } else if (data_str.startsWith("l") || data_str.startsWith("L")) printLogbookCSV(); + else if(data_str.charAt(0) == '~' && data_str.charAt(1) == '/') { + MuteScreen(true); + i2c_pc_control = i2c_pc_control_init = true; + Serial.flush(); + } } if (RDSSPYUSB && Serial.available()) { @@ -915,4 +920,105 @@ void tryWiFi() { Udp.stop(); WiFi.mode(WIFI_OFF); } +} + +void total_pc_control() { + if(i2c_pc_control_init) { + Serial.write(1); + Serial.write(0xff); + Serial.flush(); + i2c_pc_control_init = false; + } + if(Serial.available()) { + uint8_t userlen = Serial.read(); + if(userlen == '~' && Serial.read() == '/') { + Serial.write(1); + Serial.write(0xff); + Serial.flush(true); + return; + } + + uint8_t *data = (uint8_t*)malloc(userlen); + if(data == NULL) return; + auto len = Serial.read(data, userlen); + if(len != userlen) { + free(data); + return; // Incomplete data + } + switch (data[0]) { + case 0: { // Set clock + if(len < 5) break; + uint32_t clock = ((uint32_t)data[1] << 24) | + ((uint32_t)data[2] << 16) | + ((uint32_t)data[3] << 8) | + ((uint32_t)data[4]); + Wire.setClock(clock); + Serial.write(1); + Serial.write(0); + } break; + case 1: { // Send data + if(len < 3) break; + Wire.beginTransmission(data[1]); + for(int i = 0; i < (len-2); i++) Wire.write(data[2+i]); + auto out = Wire.endTransmission(); + Serial.write(2); + Serial.write(1); + Serial.write(out); + } break; + case 2: { // Send and receive data + if(len < 4) break; // Need at least: cmd, addr, datalen, recvlen + uint8_t addr = data[1]; + uint8_t datalen = data[2]; + + if(len < 3 + datalen + 1) break; // Validate buffer size + + Wire.beginTransmission(addr); + for(int i = 0; i < datalen; i++) Wire.write(data[3+i]); + auto out = Wire.endTransmission(false); + + uint8_t recvlen_requested = data[3+datalen]; + uint8_t recvlen = Wire.requestFrom(addr, recvlen_requested); + + Serial.write(recvlen+2); + Serial.write(2); + Serial.write(out); + while(Wire.available()) Serial.write(Wire.read()); + } break; + case 3: { // Quit + i2c_pc_control = false; + MuteScreen(false); + Serial.write(1); + Serial.write(3); + Serial.flush(); + Serial.updateBaudRate(115200); + } break; + case 4: { // Version + Serial.write(2); + Serial.write(4); + Serial.write(0); + } break; + case 5: { // Reboot + Serial.write(1); + Serial.write(5); + Serial.flush(); + delay(5); + esp_restart(); + } break; + case 6: { // Change baud + if(len < 5) break; + uint32_t clock = ((uint32_t)data[1] << 24) | + ((uint32_t)data[2] << 16) | + ((uint32_t)data[3] << 8) | + ((uint32_t)data[4]); + Serial.write(1); + Serial.write(6); + Serial.flush(true); + Serial.updateBaudRate(clock); + } break; + default: + break; + } + free(data); + Serial.flush(true); + } } \ No newline at end of file diff --git a/src/globals.cpp b/src/globals.cpp index 689076a..1aee8bd 100644 --- a/src/globals.cpp +++ b/src/globals.cpp @@ -324,6 +324,9 @@ bool rds_settings_changed; const size_t language_totalnumber = sizeof(myLanguage) / sizeof(myLanguage[0]); const size_t language_entrynumber = sizeof(myLanguage[0]) / sizeof(myLanguage[0][0]); +volatile bool i2c_pc_control = false; +volatile bool i2c_pc_control_init = false; + mem presets[EE_PRESETS_CNT]; TEF6686 radio; TFT_eSPI tft = TFT_eSPI(); diff --git a/src/main.cpp b/src/main.cpp index ae09d64..be0900d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1130,7 +1130,7 @@ void endMenu() { if (af == 2) radio.rds.afreg = true; else radio.rds.afreg = false; Serial.end(); if (wifi) remoteip = IPAddress (WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], subnetclient); - if (USBmode) Serial.begin(19200); else Serial.begin(115200); + if (USBmode) Serial.updateBaudRate(19200); else Serial.updateBaudRate(115200); leave = true; if (language == LANGUAGE_CHS) PSSprite.setTextFont(3); else PSSprite.setTextFont(2); @@ -1202,7 +1202,6 @@ void MuteScreen(bool setting) { void setup_periph() { Wire.setClock(400000); - Serial.begin(115200); Serial.println(); byte error, address; for (address = 1; address < 108; address++) { @@ -1232,7 +1231,6 @@ void setup_periph() { } Serial.flush(); - Serial.end(); Wire.setClock(100000); } @@ -1305,7 +1303,7 @@ void later_setup_periph() { } else console.print("RX8010SJ is not available at address " + String(RX8010SJ_ADDRESS, HEX)); if(analogRead(BATTERY_PIN) < BATTERY_DETECT_THRESHOLD) batterydetect = false; - else console.print("Battery detected."); + else console.print("Battery detected"); } void read_encoder(); @@ -1325,6 +1323,7 @@ void setup() { EEPROM.begin(EE_TOTAL_CNT); setupmode = true; + Serial.begin(115200); Wire.begin(); Wire.setClock(100000); @@ -1355,7 +1354,7 @@ void setup() { for (int y = 0; y < 5; y++) presets[i].RDSPI[y] = EEPROM.readByte((i * 5) + y + EE_PRESETS_RDSPI_START); } - if (USBmode) Serial.begin(19200); else Serial.begin(115200); + if (USBmode) Serial.updateBaudRate(19200); else Serial.updateBaudRate(115200); if (iMSset && EQset) iMSEQ = 2; if (!iMSset && EQset) iMSEQ = 3; @@ -1633,6 +1632,11 @@ void handleTimers() { } void loop() { + if(i2c_pc_control) { + total_pc_control(); + if(i2c_pc_control) return; + } + handleWiFi(); handleTouch(); Communication();