From 89aaa0c91aa6d20543bc91fa3991ce484a9a36f7 Mon Sep 17 00:00:00 2001 From: Jay Robson Date: Wed, 28 Aug 2024 13:10:57 +1000 Subject: [PATCH] can now interface with eeprom; improved computer communication --- dac.hpp | 5 ++ data.cpp | 165 +++++++++++++++++++++------------------------ data.hpp | 14 ++-- eeprom.cpp | 41 +++++++++++ eeprom.hpp | 15 +++++ indicator.cpp | 10 ++- indicator.hpp | 1 + scheduler.cpp | 22 ++---- scheduler.hpp | 4 +- serial.cpp | 72 ++++++++++++++++++++ serial.hpp | 22 ++++++ tone-generator.ino | 14 ++-- tone.hpp | 1 - 13 files changed, 265 insertions(+), 121 deletions(-) create mode 100644 eeprom.cpp create mode 100644 eeprom.hpp create mode 100644 serial.cpp create mode 100644 serial.hpp diff --git a/dac.hpp b/dac.hpp index eb487a3..55b2f8b 100644 --- a/dac.hpp +++ b/dac.hpp @@ -7,6 +7,11 @@ namespace dac { inline void init() { DDRD = 0xff; + PORTD = 127; + } + + inline void reset() { + PORTD = 127; } inline void set(int v) { diff --git a/data.cpp b/data.cpp index c623e48..908820a 100644 --- a/data.cpp +++ b/data.cpp @@ -1,112 +1,101 @@ #include -#include #include -#include "midi_data.hpp" #include "data.hpp" +#include "serial.hpp" +#include "eeprom.hpp" +#include "scheduler.hpp" +#include "indicator.hpp" +#include "dac.hpp" -const int SERIAL_RX = A4; -const int SERIAL_TX = A5; +using namespace data; -enum Mode : uint8_t { - none, - ready, - local, - serial, - read, - jump, -}; +static Mode mode = Mode::none; -static char buff[64]; -static bool buff_full = false; -static unsigned buff_at = 0; -static unsigned address = 0; -static SoftwareSerial serial_dev(SERIAL_RX, SERIAL_TX); -static Mode mode = Mode::local; +static void flash_data() { + char buff[128]; + unsigned count; + unsigned at = 0; + unsigned max_len = eeprom::length(); -void data::init() { - pinMode(SERIAL_RX, INPUT); - pinMode(SERIAL_TX, OUTPUT); - serial_dev.begin(57600); - serial_dev.listen(); - serial_dev.write(Mode::ready); + for(;;) { + unsigned count = sizeof(buff); + unsigned end = at + count; - unsigned long ts_end = millis() + 1000; - while(ts_end > millis()) { - if(check()) { + if(end <= at) { + break; + } + if(end >= max_len) { + unsigned l = end - max_len; + if(count < l) { + break; + } + count -= l; + } + + count = serial::read(buff, count); + eeprom::write(at, buff, count); + at += count; + + if(count != sizeof(buff)) { break; } } -} -bool data::check() { - if(serial_dev.available()) { - mode = serial_dev.read(); - return true; - } else { - return false; + while(serial::read(buff, sizeof(buff) == sizeof(buff))) { } } -void data::jump(unsigned long loc) { +void data::update() { + static int last = 2; + int now = serial::is_connected() ? 1 : 0; + if(last == now) { + return; + } + dac::reset(); + indicator::reset(); + last = now; + if(now) { + while(serial::dev.available()) { + serial::get(); + } + delay(10); + serial::write("\x19\xc1\x6c\x19\x5b\x6f\xd2\x44", 8); + mode = serial::get(); + switch(mode) { + case Mode::flash: + flash_data(); + mode = Mode::none; + break; + case Mode::local: + eeprom::jump(0); + scheduler::reset(); + break; + case Mode::stream: + scheduler::reset(); + break; + } + } else { + mode = Mode::local; + eeprom::jump(0); + scheduler::reset(); + } +} + +unsigned data::read(char* data, unsigned len) { + unsigned count = 0; switch(mode) { case Mode::local: - address = loc; + eeprom::read(data, len); + count = len; break; - case Mode::serial: - serial_dev.write(Mode::jump); - serial_dev.write(loc >> 24); - serial_dev.write(loc >> 16); - serial_dev.write(loc >> 8); - serial_dev.write(loc); + case Mode::stream: + count = serial::read(data, len); break; } -} - -inline uint8_t proc_len(uint8_t len) { - if(address + len >= sizeof(MIDI)) { - return sizeof(MIDI) - address; - } else { - return len; + for(unsigned i = count; i < len; i++) { + data[i] = 0; } -} - -static void fill_buffer() { - serial_dev.write(Mode::read); - serial_dev.write(sizeof(buff)); - for(int i = 0; i < sizeof(buff); i++) { - while(!serial_dev.available()) {} - buff[i] = serial_dev.read(); - } - buff_at = 0; - buff_full = true; -} - -void data::read(void* data, uint8_t len) { - char* bytes = (char*)data; - switch(mode) { - case Mode::local: - len = proc_len(len); - memcpy_P(bytes, &MIDI[address], len); - address += len; - break; - case Mode::serial: - if(!buff_full) { - fill_buffer(); - } - while(sizeof(buff) - buff_at < len) { - auto l = sizeof(buff) - buff_at; - memcpy(bytes, buff + buff_at, l); - bytes += l; - len -= l; - fill_buffer(); - } - memcpy(bytes, buff + buff_at, len); - buff_at += len; - break; - } -} - -void data::write(const void* data, uint8_t len) { + return count; } diff --git a/data.hpp b/data.hpp index f68a40b..8a34cf8 100644 --- a/data.hpp +++ b/data.hpp @@ -2,11 +2,15 @@ #pragma once namespace data { + + enum Mode : uint8_t { + none, + local, + stream, + flash, + }; - void init(); - bool check(); - void jump(unsigned long loc = 0); - void read(void* data, uint8_t len); - void write(const void* data, uint8_t len); + void update(); + unsigned read(char* data, unsigned len); }; diff --git a/eeprom.cpp b/eeprom.cpp new file mode 100644 index 0000000..1af64cd --- /dev/null +++ b/eeprom.cpp @@ -0,0 +1,41 @@ + +#include +#include +#include +#include "eeprom.hpp" + +constexpr uint8_t ADDR = 0x50; +constexpr unsigned DELAY = 100; + +static ExternalEEPROM mem; + +static unsigned at = 0; + +void eeprom::init() { + Wire.setClock(400000); + Wire.begin(); + mem.setMemoryType(1025); + mem.begin(); +} + +unsigned eeprom::length() { + return mem.length(); +} + +void eeprom::jump(unsigned loc) { + at = loc; +} + +void eeprom::read(char* data, unsigned len) { + mem.read(at, data, len); + at += len; +} + +void eeprom::read(unsigned loc, char* data, unsigned len) { + mem.read(loc, data, len); +} + +void eeprom::write(unsigned loc, const char* data, unsigned len) { + mem.write(loc, data, len); +} + diff --git a/eeprom.hpp b/eeprom.hpp new file mode 100644 index 0000000..d328cfd --- /dev/null +++ b/eeprom.hpp @@ -0,0 +1,15 @@ + +#pragma once + +namespace eeprom { + + constexpr unsigned char PAGE_SIZE = 128; + + void init(); + void jump(unsigned addr); + void read(char* data, unsigned len); + void read(unsigned addr, char* data, unsigned len); + void write(unsigned addr, const char* data, unsigned len); + unsigned length(); +}; + diff --git a/indicator.cpp b/indicator.cpp index 53e4c91..830e14b 100644 --- a/indicator.cpp +++ b/indicator.cpp @@ -3,10 +3,14 @@ #include "indicator.hpp" #include "tones.hpp" -#define LED_INDICATOR 10 +constexpr int PIN = 10; void indicator::init() { - pinMode(LED_INDICATOR, OUTPUT); + pinMode(PIN, OUTPUT); +} + +void indicator::reset() { + analogWrite(PIN, 0); } void indicator::update() { @@ -14,6 +18,6 @@ void indicator::update() { for(int i = 0; i < tones::active; i++) { v += tones::all[i].amplitude; } - analogWrite(LED_INDICATOR, min(v, 255)); + analogWrite(PIN, min(v, 255)); } diff --git a/indicator.hpp b/indicator.hpp index 7dcc8fd..bbab926 100644 --- a/indicator.hpp +++ b/indicator.hpp @@ -4,6 +4,7 @@ namespace indicator { void init(); + void reset(); void update(); }; diff --git a/scheduler.cpp b/scheduler.cpp index 474f248..bc6c23b 100644 --- a/scheduler.cpp +++ b/scheduler.cpp @@ -7,6 +7,8 @@ #include "tones.hpp" #include "util.hpp" +using namespace scheduler; + static uint32_t ts_init = 0; static uint32_t ts_last = 0; struct { @@ -24,24 +26,19 @@ constexpr uint64_t bm(int n) { return ((uint64_t)1 << n) - 1; } -void scheduler::init() { - data::jump(0); +void scheduler::reset() { tones::clear_all(); ts_init = micros(); running = true; } -void scheduler::do_next() { +static void do_next() { int i = 1; - if(running) { - if(next.active) { - tones::set(next.index, next.frequency, next.amplitude); - next.active = false; - } - } else { - init(); + if(next.active) { + tones::set(next.index, next.frequency, next.amplitude); + next.active = false; } uint64_t v = 0; @@ -117,8 +114,3 @@ void scheduler::do_all() { tones::recalc(); } -void scheduler::clear() { - data::jump(0); - ts_last = 0; -} - diff --git a/scheduler.hpp b/scheduler.hpp index d44f009..fbf51df 100644 --- a/scheduler.hpp +++ b/scheduler.hpp @@ -6,9 +6,7 @@ namespace scheduler { inline uint32_t timestamp = 0; inline bool running = false; - void init(); - void do_next(); + void reset(); void do_all(); - void clear(); }; diff --git a/serial.cpp b/serial.cpp new file mode 100644 index 0000000..8d3d136 --- /dev/null +++ b/serial.cpp @@ -0,0 +1,72 @@ + +#include +#include +#include "serial.hpp" + +constexpr int DTR = A0; +constexpr int CTS = A3; + +struct CTSGuard { + CTSGuard() { + digitalWrite(CTS, 0); + } + ~CTSGuard() { + digitalWrite(CTS, 1); + } +}; + +void serial::init() { + pinMode(DTR, INPUT_PULLUP); + pinMode(CTS, OUTPUT); + pinMode(RXD, INPUT_PULLUP); + pinMode(TXD, OUTPUT); + digitalWrite(CTS, 1); + dev.begin(57600); + dev.listen(); +} + +bool serial::is_connected() { + return digitalRead(DTR) == 0; +} + +static bool wait_until() { + while(!serial::dev.available()) { + if(!serial::is_connected()) { + return false; + } + } + return true; +} + +unsigned serial::read(char* data, unsigned len) { + CTSGuard guard; + + for(unsigned i = 0; i < len; i++) { + if(!wait_until()) { + return i; + } + data[i] = dev.read(); + } + + return len; +} + +void serial::write(const char* data, unsigned len) { + for(unsigned i = 0; i < len; i++) { + dev.write(data[i]); + } +} + +void serial::put(char ch) { + dev.write(ch); +} + +int serial::get() { + unsigned char ch; + if(read(&ch, 1)) { + return ch; + } else { + return -1; + } +} + diff --git a/serial.hpp b/serial.hpp new file mode 100644 index 0000000..c140f5c --- /dev/null +++ b/serial.hpp @@ -0,0 +1,22 @@ + +#pragma once + +#include +#include + +namespace serial { + + constexpr int RXD = A2; + constexpr int TXD = A1; + + inline SoftwareSerial dev(RXD, TXD); + + void init(); + bool is_connected(); + bool wait_until_available(); + unsigned read(char* data, unsigned len); + void write(const char* data, unsigned len); + void put(char ch); + int get(); +}; + diff --git a/tone-generator.ino b/tone-generator.ino index 4b52e93..c71b1ca 100644 --- a/tone-generator.ino +++ b/tone-generator.ino @@ -6,6 +6,8 @@ #include "util.hpp" #include "scheduler.hpp" #include "indicator.hpp" +#include "serial.hpp" +#include "eeprom.hpp" #include "data.hpp" static unsigned long int micros_at = 0; @@ -21,23 +23,23 @@ inline unsigned long micros_diff() { void setup() { Tone::init(); dac::init(); - data::init(); + serial::init(); + eeprom::init(); tones::init(); - scheduler::init(); indicator::init(); + scheduler::reset(); } void loop() { + if(scheduler::running) { if(timing::at >= scheduler::timestamp) { + data::update(); scheduler::do_all(); indicator::update(); } } else { - if(data::check()) { - scheduler::do_next(); - tones::recalc(); - } + data::update(); } timing::update(); diff --git a/tone.hpp b/tone.hpp index bee904b..f318f33 100644 --- a/tone.hpp +++ b/tone.hpp @@ -2,7 +2,6 @@ #pragma once #include -#include struct Tone { uint32_t phase;