can now interface with eeprom; improved computer communication
This commit is contained in:
parent
3dda949846
commit
89aaa0c91a
5
dac.hpp
5
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) {
|
||||
|
|
165
data.cpp
165
data.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
14
data.hpp
14
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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
};
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
namespace indicator {
|
||||
|
||||
void init();
|
||||
void reset();
|
||||
void update();
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
};
|
||||
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue