/* Triple buffering data structure Example writing: ---------------- DMXTripleBuffer buffer; bytes_written = producer.write( buffer.fill_buffer + buffer.fill_pos, // destination pointer 512 - buffer.fill_pos // maximum allowed ); buffer.fill_pos += bytes_written; if buffer.fill_pos == 512 { buffer.on_fill_complete(); // swap buffers buffer.fill_pos = 0; // reset fill pos } */ struct InternalBuffer { char data[512] = {0}; bool is_fresh = false; }; class DMXTripleBuffer { public: DMXTripleBuffer() { fill_buffer = &_buffers[0]; drain_buffer = &_buffers[1]; off_buffer = &_buffers[2]; } void on_fill_complete() { fill_pos = 0; fill_buffer->is_fresh = true; std::swap(fill_buffer, off_buffer); } void on_drain_complete() { drain_pos = 0; drain_buffer->is_fresh = false; if (off_buffer->is_fresh) { std::swap(drain_buffer, off_buffer); } } InternalBuffer *fill_buffer, *drain_buffer, *off_buffer; size_t fill_pos = 0, drain_pos = 0; private: InternalBuffer _buffers[3]; }; /* Some globals */ unsigned long time_since_last_sync; const unsigned long SYNC_TIMEOUT = 1000; const unsigned int FRAME_TIME = 20; // 20 ms -> 50 FPS DMXTripleBuffer buffer; bool packet_ready = true; unsigned long pkt_count = 0; /* main */ void setup() { Serial.begin(500000); // USB Serial.setRxBufferSize(512); // to fit the full DMX packet. (default is 128) while (!Serial) { // spin until serial is up } Serial1.begin(250000, SERIAL_8N2); // DMX while (!Serial1) { // spin until serial1 is up } Serial.println(); Serial.println("Sync."); time_since_last_sync = millis(); } void loop() { // output if (packet_ready) { send_dmx_header(); packet_ready = false; pkt_count += 1; } size_t n = Serial1.availableForWrite(); size_t written = Serial1.write( buffer.drain_buffer->data + buffer.drain_pos, std::min(n, 512 - buffer.drain_pos)); buffer.drain_pos += written; if (buffer.drain_pos == 512) { buffer.on_drain_complete(); packet_ready = true; } // input n = Serial.available(); unsigned long now = millis(); if (!n) { if (now - time_since_last_sync > 1000) { buffer.fill_pos = 0; Serial.println("Sync."); time_since_last_sync = now; } return; } time_since_last_sync = now; size_t read = Serial.read( buffer.fill_buffer->data + buffer.fill_pos, std::min(n, 512 - buffer.fill_pos)); buffer.fill_pos += read; if (buffer.fill_pos == 512) { buffer.on_fill_complete(); Serial.println("Ack."); } } void send_dmx_header() { Serial1.flush(); Serial1.begin(90000, SERIAL_8N2); // send the break as a "slow" byte Serial1.write(0); // switch back to the original baud rate Serial1.flush(); Serial1.begin(250000, SERIAL_8N2); Serial1.write(0); // Start-Byte }