diff --git a/UIThread.cpp b/UIThread.cpp index 24398fa..e02ee3d 100644 --- a/UIThread.cpp +++ b/UIThread.cpp @@ -60,13 +60,15 @@ void readEncoder() { void saveGridToEEPROM() { if (!globalSynth) return; - uint8_t buf[SynthEngine::SERIALIZED_GRID_SIZE]; - globalSynth->exportGrid(buf); + uint8_t buf[SynthEngine::MAX_SERIALIZED_GRID_SIZE]; + size_t size = globalSynth->exportGrid(buf); EEPROM.write(0, 'N'); EEPROM.write(1, 'S'); - for (size_t i = 0; i < sizeof(buf); i++) { - EEPROM.write(2 + i, buf[i]); + EEPROM.write(2, (size >> 8) & 0xFF); + EEPROM.write(3, size & 0xFF); + for (size_t i = 0; i < size; i++) { + EEPROM.write(4 + i, buf[i]); } EEPROM.commit(); } @@ -74,11 +76,14 @@ void saveGridToEEPROM() { void loadGridFromEEPROM() { if (!globalSynth) return; if (EEPROM.read(0) == 'N' && EEPROM.read(1) == 'S') { - uint8_t buf[SynthEngine::SERIALIZED_GRID_SIZE]; - for (size_t i = 0; i < sizeof(buf); i++) { - buf[i] = EEPROM.read(2 + i); + size_t size = (EEPROM.read(2) << 8) | EEPROM.read(3); + if (size > SynthEngine::MAX_SERIALIZED_GRID_SIZE) size = SynthEngine::MAX_SERIALIZED_GRID_SIZE; + + uint8_t buf[SynthEngine::MAX_SERIALIZED_GRID_SIZE]; + for (size_t i = 0; i < size; i++) { + buf[i] = EEPROM.read(4 + i); } - globalSynth->importGrid(buf); + globalSynth->importGrid(buf, size); } else { globalSynth->loadPreset(1); // Default to preset 1 } @@ -104,7 +109,7 @@ void setupUI() { display.display(); // Initialize EEPROM - EEPROM.begin(512); + EEPROM.begin(1024); // Check for safety clear (Button held on startup) if (digitalRead(PIN_ENC_SW) == LOW) { @@ -269,13 +274,14 @@ void drawUI() { } void checkSerial() { - static int state = 0; // 0: Header, 1: Data + static int state = 0; // 0: Header, 1: Count, 2: Data, 3: EndCount static int headerIdx = 0; static const char* header = "NSGRID"; static int loadHeaderIdx = 0; static const char* loadHeader = "NSLOAD"; - static uint8_t buffer[SynthEngine::SERIALIZED_GRID_SIZE]; + static uint8_t buffer[SynthEngine::MAX_SERIALIZED_GRID_SIZE]; static int bufferIdx = 0; + static uint8_t elementCount = 0; while (Serial.available()) { uint8_t b = Serial.read(); @@ -283,7 +289,7 @@ void checkSerial() { if (b == header[headerIdx]) { headerIdx++; if (headerIdx == 6) { - state = 1; + state = 1; // Expect count next bufferIdx = 0; headerIdx = 0; loadHeaderIdx = 0; @@ -298,10 +304,10 @@ void checkSerial() { loadHeaderIdx++; if (loadHeaderIdx == 6) { if (globalSynth) { - uint8_t buf[SynthEngine::SERIALIZED_GRID_SIZE]; - globalSynth->exportGrid(buf); + static uint8_t exportBuf[SynthEngine::MAX_SERIALIZED_GRID_SIZE]; + size_t size = globalSynth->exportGrid(exportBuf); Serial.write("NSGRID", 6); - Serial.write(buf, sizeof(buf)); + Serial.write(exportBuf, size); Serial.flush(); } loadHeaderIdx = 0; @@ -312,11 +318,29 @@ void checkSerial() { if (b == 'N') loadHeaderIdx = 1; } } - } else if (state == 1) { + } else if (state == 1) { // Count + elementCount = b; + if (1 + elementCount * 5 > sizeof(buffer)) { + state = 0; + bufferIdx = 0; + Serial.println(F("ERROR: Grid too large")); + } else { + buffer[bufferIdx++] = b; + state = 2; + } + } else if (state == 2) { // Data buffer[bufferIdx++] = b; - if (bufferIdx == SynthEngine::SERIALIZED_GRID_SIZE) { - if (globalSynth) { - globalSynth->importGrid(buffer); + if (bufferIdx == 1 + elementCount * 5) { + state = 3; + } + } else if (state == 3) { // End Count + buffer[bufferIdx++] = b; + if (globalSynth) { + int result = globalSynth->importGrid(buffer, bufferIdx); + if (result != 0) { + Serial.print("CRC ERROR "); Serial.println(result); + globalSynth->clearGrid(); + } else { saveGridToEEPROM(); Serial.println(F("OK: Grid Received")); } diff --git a/simulator/main.cpp b/simulator/main.cpp index 1135f92..c863aa4 100644 --- a/simulator/main.cpp +++ b/simulator/main.cpp @@ -15,6 +15,7 @@ #if !defined(_WIN32) #include #include +#include #endif // --- Configuration --- @@ -98,37 +99,60 @@ void checkSerialInput(FILE* serialPort) { return; #endif - printf("Grid import maybe?\n"); - static int state = 0; static int headerIdx = 0; static const char* header = "NSGRID"; - static uint8_t buffer[SynthEngine::SERIALIZED_GRID_SIZE]; + static uint8_t buffer[SynthEngine::MAX_SERIALIZED_GRID_SIZE]; static int bufferIdx = 0; + static uint8_t elementCount = 0; for (ssize_t i = 0; i < n; ++i) { uint8_t b = buf[i]; if (state == 0) { - if (b == header[headerIdx]) { + if (b == (uint8_t)header[headerIdx]) { headerIdx++; if (headerIdx == 6) { - state = 1; + state = 1; // Expect count bufferIdx = 0; headerIdx = 0; printf("Grid import starting.\n"); } } else { + if (headerIdx > 0) { + printf("Header mismatch at index %d. Received: %02X\n", headerIdx, b); + } + headerIdx = 0; if (b == 'N') headerIdx = 1; } - } else if (state == 1) { - buffer[bufferIdx++] = b; - if (bufferIdx == SynthEngine::SERIALIZED_GRID_SIZE) { - engine.importGrid(buffer); - printf("Grid imported from serial.\n"); + } else if (state == 1) { // Count + elementCount = b; + printf("Grid element count: %d\n", elementCount); + if (1 + elementCount * 5 + 1 > sizeof(buffer)) { state = 0; bufferIdx = 0; + printf("ERROR: Grid too large (count: %d)\n", elementCount); + } else { + buffer[bufferIdx++] = b; + state = (elementCount == 0) ? 3 : 2; } + } else if (state == 2) { // Data + buffer[bufferIdx++] = b; + if (bufferIdx == 1 + elementCount * 5) { + state = 3; + } + } else if (state == 3) { // End Count + buffer[bufferIdx++] = b; + printf("Grid import finishing. Total bytes: %d. End count: %d\n", bufferIdx, b); + int result = engine.importGrid(buffer, bufferIdx); + if (result != 0) { + printf("Grid import failed: CRC ERROR %d\n", result); + engine.clearGrid(); + } else { + printf("Grid imported from serial successfully.\n"); + } + state = 0; + bufferIdx = 0; } } } @@ -986,7 +1010,45 @@ int main(int argc, char* argv[]) { if (argc > 1) { serialPort = fopen(argv[1], "r+b"); - if (serialPort) printf("Opened serial port: %s\n", argv[1]); + if (serialPort) { + printf("Opened serial port: %s\n", argv[1]); +#if !defined(_WIN32) + int fd = fileno(serialPort); + struct termios tty; + if (tcgetattr(fd, &tty) != 0) { + printf("Error from tcgetattr\n"); + } else { + cfsetospeed(&tty, B115200); + cfsetispeed(&tty, B115200); + + tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common) + tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common) + tty.c_cflag &= ~CSIZE; // Clear all bits that set the data size + tty.c_cflag |= CS8; // 8 bits per byte (most common) + tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common) + tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1) + + tty.c_lflag &= ~ICANON; // Disable canonical mode + tty.c_lflag &= ~ECHO; // Disable echo + tty.c_lflag &= ~ECHOE; // Disable erasure + tty.c_lflag &= ~ECHONL; // Disable new-line echo + tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP + + tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes + + tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars) + tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed + + tty.c_cc[VTIME] = 0; // No blocking with timeout + tty.c_cc[VMIN] = 0; // Non-blocking read + + if (tcsetattr(fd, TCSANOW, &tty) != 0) { + printf("Error from tcsetattr\n"); + } + } +#endif + } else printf("Failed to open serial port: %s\n", argv[1]); } @@ -1230,10 +1292,10 @@ int main(int argc, char* argv[]) { my >= exportButtonRect.y && my <= exportButtonRect.y + exportButtonRect.h) { if (serialPort) { - uint8_t buf[SynthEngine::SERIALIZED_GRID_SIZE]; - engine.exportGrid(buf); + uint8_t buf[SynthEngine::MAX_SERIALIZED_GRID_SIZE]; + size_t size = engine.exportGrid(buf); fwrite("NSGRID", 1, 6, serialPort); - fwrite(buf, 1, sizeof(buf), serialPort); + fwrite(buf, 1, size, serialPort); fflush(serialPort); printf("Grid exported to serial. Waiting for response...\n"); diff --git a/synth_engine.cpp b/synth_engine.cpp index ceb6937..b12a3a2 100644 --- a/synth_engine.cpp +++ b/synth_engine.cpp @@ -42,37 +42,77 @@ SynthEngine::SynthEngine(uint32_t sampleRate) SynthEngine::~SynthEngine() { } -void SynthEngine::exportGrid(uint8_t* buffer) { +size_t SynthEngine::exportGrid(uint8_t* buffer) { SynthLockGuard lock(gridMutex); - size_t idx = 0; + uint8_t count = 0; for(int y=0; y lock(gridMutex); size_t idx = 0; + buffer[idx++] = count; + for(int y=0; y lock(gridMutex); + + // Clear grid first + for (int x = 0; x < GRID_W; ++x) { + for (int y = 0; y < GRID_H; ++y) { + GridCell& c = grid[x][y]; + if (c.type == GridCell::SINK) continue; + c.type = GridCell::EMPTY; + c.param = 0.5f; + c.rotation = 0; + c.value = 0.0f; + c.phase = 0.0f; + c.next_value = 0.0f; + } + } + + size_t idx = 1; + for(int i=0; i