Compare commits

...

2 Commits

Author SHA1 Message Date
Jay Robson f71b07f499 improvements 2024-09-30 23:25:16 +10:00
Jay Robson 376a2ef6de added song skipping 2024-09-29 18:07:58 +10:00
9 changed files with 139 additions and 86 deletions

View File

@ -8,7 +8,8 @@
#include "indicator.hpp" #include "indicator.hpp"
const int PIN_NEXT = 8; const int PIN_NEXT = 8;
bool state_next = 1;
static uint32_t addr_next = 0;
void buttons::init() { void buttons::init() {
pinMode(PIN_NEXT, INPUT_PULLUP); pinMode(PIN_NEXT, INPUT_PULLUP);
@ -19,6 +20,7 @@ static void on_next() {
case scheduler::State::play: case scheduler::State::play:
scheduler::state = scheduler::State::skip; scheduler::state = scheduler::State::skip;
indicator::reset(); indicator::reset();
data::jump(addr_next);
tones::clear_all(); tones::clear_all();
dac::reset(); dac::reset();
break; break;
@ -29,16 +31,15 @@ static void on_next() {
} }
void buttons::update() { void buttons::update() {
if(!digitalRead(PIN_NEXT)) {
if(!digitalRead(PIN_NEXT) && state_next) {
delay(1); delay(1);
state_next = 0; while(!digitalRead(PIN_NEXT)) {}
}
else if(digitalRead(PIN_NEXT) && !state_next) {
delay(1); delay(1);
on_next(); on_next();
state_next = 1;
} }
} }
void buttons::set_addr_next(uint32_t addr) {
addr_next = addr;
}

View File

@ -4,5 +4,6 @@
namespace buttons { namespace buttons {
void init(); void init();
void update(); void update();
void set_addr_next(uint32_t addr);
}; };

View File

@ -62,7 +62,7 @@ void data::update() {
scheduler::reset(); scheduler::reset();
break; break;
} }
} else if(mode != Mode::local) { } else {
mode = Mode::local; mode = Mode::local;
eeprom::jump(0); eeprom::jump(0);
scheduler::state = scheduler::State::pause; scheduler::state = scheduler::State::pause;
@ -87,3 +87,23 @@ unsigned data::read(char* data, unsigned len) {
return count; return count;
} }
bool data::jump(uint32_t addr) {
switch(mode) {
case Mode::local:
eeprom::jump(addr);
break;
default:
return false;
}
return true;
}
uint32_t data::get_addr() {
switch(mode) {
case Mode::local:
return eeprom::get_addr();
default:
return 0;
}
}

View File

@ -12,5 +12,7 @@ namespace data {
void update(); void update();
unsigned read(char* data, unsigned len); unsigned read(char* data, unsigned len);
bool jump(uint32_t addr);
uint32_t get_addr();
}; };

View File

@ -8,7 +8,8 @@ using namespace eeprom;
constexpr uint8_t WRITE_MS = 3; constexpr uint8_t WRITE_MS = 3;
constexpr uint8_t ADDR = 0x50; constexpr uint8_t ADDR = 0x50;
uint32_t at = 0; static uint32_t at = 0;
static uint32_t last_block_end = 0;
static bool is_responsive(uint8_t i2c_addr) { static bool is_responsive(uint8_t i2c_addr) {
bool s = mem.start_write(i2c_addr); bool s = mem.start_write(i2c_addr);
@ -22,11 +23,7 @@ static void wait_for_responsive(uint8_t i2c_addr) {
} }
static uint8_t get_i2c_addr(uint32_t at) { static uint8_t get_i2c_addr(uint32_t at) {
uint8_t i2c_addr = ADDR; return ADDR ^ (at >> 16);
if(at > 0xffff) {
i2c_addr |= 1;
}
return i2c_addr;
} }
static void set_address(uint8_t i2c_addr, uint16_t at) { static void set_address(uint8_t i2c_addr, uint16_t at) {
@ -41,6 +38,7 @@ void eeprom::init() {
} }
void eeprom::jump(uint32_t p_at) { void eeprom::jump(uint32_t p_at) {
last_block_end = 0;
at = p_at; at = p_at;
} }
@ -48,11 +46,16 @@ void eeprom::read(char* data, uint16_t data_size) {
uint16_t recorded = 0; uint16_t recorded = 0;
while(recorded < data_size && at < LENGTH) { while(recorded < data_size && at < LENGTH) {
uint32_t block_end = at / BLOCK_SIZE * BLOCK_SIZE + BLOCK_SIZE; uint32_t block_end = at / BLOCK_SIZE * BLOCK_SIZE + BLOCK_SIZE;
uint8_t read_len = min(min(block_end - at, data_size - recorded), 255); uint8_t read_len = min(min(block_end - at, data_size - recorded), 255);
uint8_t i2c_addr = get_i2c_addr(at); uint8_t i2c_addr = get_i2c_addr(at);
set_address(i2c_addr, at); if(block_end != last_block_end) {
set_address(i2c_addr, at);
last_block_end = block_end;
}
mem.start_read(i2c_addr); mem.start_read(i2c_addr);
mem.read(data + recorded, read_len, true); mem.read(data + recorded, read_len, true);
recorded += read_len; recorded += read_len;
@ -76,5 +79,10 @@ void eeprom::page_write(uint32_t at, const char* data) {
mem.write(data, PAGE_SIZE - (at % PAGE_SIZE)); mem.write(data, PAGE_SIZE - (at % PAGE_SIZE));
mem.end(); mem.end();
delay(WRITE_MS); delay(WRITE_MS);
last_block_end = 0;
}
uint32_t eeprom::get_addr() {
return at;
} }

View File

@ -8,7 +8,7 @@ namespace eeprom {
constexpr uint8_t PAGE_SIZE = 128; constexpr uint8_t PAGE_SIZE = 128;
constexpr uint32_t BLOCK_SIZE = 0x10000; constexpr uint32_t BLOCK_SIZE = 0x10000;
constexpr uint32_t LENGTH = 0x20000; constexpr uint32_t LENGTH = 0x80000;
inline SoftTWI mem(A4, A5); inline SoftTWI mem(A4, A5);
@ -16,5 +16,6 @@ namespace eeprom {
void jump(uint32_t addr); void jump(uint32_t addr);
void read(char* data, uint16_t len); void read(char* data, uint16_t len);
void page_write(uint32_t at, const char* data); void page_write(uint32_t at, const char* data);
uint32_t get_addr();
}; };

View File

@ -9,52 +9,30 @@ struct Checker {
namespace entry { namespace entry {
enum Type : uint8_t { enum Type : uint8_t {
stop, stop = 0,
config, config = 1,
set, set = 2,
set_ts, set_ts = 3,
clear, clear = 4,
clear_ts, clear_ts = 5,
tempo = 6,
}; };
struct Set { enum NextType {
nt_none,
nt_tone,
nt_tempo,
};
struct Tone {
uint8_t index; uint8_t index;
uint16_t frequency;
};
struct Clear {
uint8_t index;
};
struct SetTS {
uint8_t index;
uint32_t ticks;
uint16_t frequency;
};
struct ClearTS {
uint8_t index;
uint32_t ticks;
};
struct Stop {
};
struct Config {
uint32_t us_per_tick;
uint8_t amplitude; uint8_t amplitude;
uint16_t frequency;
}; };
struct Generic { struct Tempo {
Type type; uint32_t ticks;
union { uint32_t us_per_tick;
Set set;
SetTS set_ts;
Clear clear;
ClearTS clear_ts;
Stop stop;
Config config;
};
}; };
inline size_t get_size(Type type) { inline size_t get_size(Type type) {
@ -68,7 +46,9 @@ namespace entry {
case Type::clear_ts: case Type::clear_ts:
return 4; return 4;
case Type::config: case Type::config:
return 5; return 8;
case Type::tempo:
return 7;
case Type::stop: case Type::stop:
default: default:
return 1; return 1;

View File

@ -6,45 +6,63 @@
#include "entry.hpp" #include "entry.hpp"
#include "tones.hpp" #include "tones.hpp"
#include "util.hpp" #include "util.hpp"
#include "buttons.hpp"
using namespace scheduler; using namespace scheduler;
static uint32_t ts_init = 0; static uint32_t ts_init = 0;
static uint32_t ts_last = 0; static uint32_t ts_last = 0;
static uint32_t tick_offset = 0;
struct { struct {
uint8_t amplitude = 1; uint8_t amplitude = 1;
uint32_t us_per_tick = 1; uint32_t us_per_tick = 1;
} config; } config;
struct { struct {
uint8_t index; entry::NextType type = entry::nt_none;
uint8_t amplitude; union {
uint16_t frequency; entry::Tone tone;
bool active = false; entry::Tempo tempo;
};
} next; } next;
void scheduler::reset() { void scheduler::reset() {
tones::clear_all(); tones::clear_all();
ts_init = timestamp = micros(); ts_init = timestamp = micros();
tick_offset = 0;
} }
static void do_next() { static void do_next() {
int i = 1; int i = 1;
if(next.active) { if(state == State::play) {
if(state == State::play) { switch(next.type) {
tones::set(next.index, next.frequency, next.amplitude); case entry::nt_tone:
tones::set(next.tone.index, next.tone.frequency, next.tone.amplitude);
break;
case entry::nt_tempo:
ts_init += next.tempo.ticks * config.us_per_tick;
tick_offset = next.tempo.ticks;
config.us_per_tick = next.tempo.us_per_tick;
break;
} }
next.active = false;
} }
next.type = entry::nt_none;
uint64_t v = 0; uint64_t v = 0;
uint8_t buff[8]; uint8_t buff[8];
data::read(buff, 1);
if(data::read(buff, 1) != 1) {
return;
}
entry::Type type = buff[0] >> 5; entry::Type type = buff[0] >> 5;
int entry_size = entry::get_size(type); int entry_size = entry::get_size(type);
data::read(buff + 1, entry_size - 1);
if(data::read(buff + 1, entry_size - 1) != entry_size - 1) {
return;
}
for(int i = 0; i < entry_size; i++) { for(int i = 0; i < entry_size; i++) {
v = (v << 8) | buff[i]; v = (v << 8) | buff[i];
@ -52,6 +70,8 @@ static void do_next() {
switch(type) { switch(type) {
case entry::Type::config: { case entry::Type::config: {
buttons::set_addr_next((v & bm(24)) + data::get_addr());
v >>= 24;
config.amplitude = v & bm(8); config.amplitude = v & bm(8);
v >>= 8; v >>= 8;
config.us_per_tick = v & bm(29); config.us_per_tick = v & bm(29);
@ -59,41 +79,50 @@ static void do_next() {
scheduler::reset(); scheduler::reset();
break; break;
} }
case entry::Type::tempo: {
next.type = entry::nt_tempo;
v >>= 4;
next.tempo.ticks = (v & bm(20)) - tick_offset;
v >>= 20;
next.tempo.us_per_tick = v & bm(29);
timestamp = next.tempo.ticks * config.us_per_tick + ts_init;
break;
}
case entry::Type::set: { case entry::Type::set: {
v >>= 4; v >>= 4;
next.frequency = v & bm(12); next.type = entry::nt_tone;
next.tone.frequency = v & bm(12);
v >>= 12; v >>= 12;
next.index = v & bm(5); next.tone.index = v & bm(5);
next.amplitude = config.amplitude; next.tone.amplitude = config.amplitude;
next.active = true;
break; break;
} }
case entry::Type::set_ts: { case entry::Type::set_ts: {
next.frequency = v & bm(12); next.type = entry::nt_tone;
next.tone.frequency = v & bm(12);
v >>= 12; v >>= 12;
uint32_t ticks = v & bm(20); uint32_t ticks = (v & bm(20)) - tick_offset;
v >>= 20; v >>= 20;
next.index = v & bm(5); next.tone.index = v & bm(5);
next.amplitude = config.amplitude; next.tone.amplitude = config.amplitude;
next.active = true;
timestamp = ticks * config.us_per_tick + ts_init; timestamp = ticks * config.us_per_tick + ts_init;
break; break;
} }
case entry::Type::clear: { case entry::Type::clear: {
next.index = v & bm(5); next.type = entry::nt_tone;
next.frequency = 0; next.tone.index = v & bm(5);
next.amplitude = 0; next.tone.frequency = 0;
next.active = true; next.tone.amplitude = 0;
break; break;
} }
case entry::Type::clear_ts: { case entry::Type::clear_ts: {
v >>= 4; v >>= 4;
uint32_t ticks = v & bm(20); uint32_t ticks = (v & bm(20)) - tick_offset;
v >>= 20; v >>= 20;
next.index = v & bm(5); next.type = entry::nt_tone;
next.frequency = 0; next.tone.index = v & bm(5);
next.amplitude = 0; next.tone.frequency = 0;
next.active = true; next.tone.amplitude = 0;
timestamp = ticks * config.us_per_tick + ts_init; timestamp = ticks * config.us_per_tick + ts_init;
break; break;
} }

View File

@ -13,6 +13,17 @@ inline void swap(T& a, T& b) {
a = t; a = t;
} }
#define bm(V) (((uint64_t)1 << V) - 1); #ifdef DEBUG_BLINK
inline void debug_blink() {
digitalWrite(9, 0);
delay(120);
digitalWrite(9, 1);
delay(10);
digitalWrite(9, 0);
delay(120);
}
#endif
#define bm(V) (((uint64_t)1 << V) - 1)
#define size(V) (sizeof(V) / sizeof(V[0])) #define size(V) (sizeof(V) / sizeof(V[0]))