can now interface with eeprom; improved computer communication

This commit is contained in:
Jay Robson 2024-08-28 13:10:57 +10:00
parent 3dda949846
commit 89aaa0c91a
13 changed files with 265 additions and 121 deletions

View File

@ -7,6 +7,11 @@ namespace dac {
inline void init() {
DDRD = 0xff;
PORTD = 127;
}
inline void reset() {
PORTD = 127;
}
inline void set(int v) {

165
data.cpp
View File

@ -1,112 +1,101 @@
#include <Arduino.h>
#include <SoftwareSerial.h>
#include <avr/pgmspace.h>
#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;
}

View File

@ -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);
};

41
eeprom.cpp Normal file
View File

@ -0,0 +1,41 @@
#include <Wire.h>
#include <Arduino.h>
#include <SparkFun_External_EEPROM.h>
#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);
}

15
eeprom.hpp Normal file
View File

@ -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();
};

View File

@ -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));
}

View File

@ -4,6 +4,7 @@
namespace indicator {
void init();
void reset();
void update();
};

View File

@ -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;
}

View File

@ -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();
};

72
serial.cpp Normal file
View File

@ -0,0 +1,72 @@
#include <Arduino.h>
#include <SoftwareSerial.h>
#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;
}
}

22
serial.hpp Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include <SoftwareSerial.h>
#include <avr/pgmspace.h>
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();
};

View File

@ -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();

View File

@ -2,7 +2,6 @@
#pragma once
#include <inttypes.h>
#include <avr/pgmspace.h>
struct Tone {
uint32_t phase;