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

View File

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

View File

@ -62,7 +62,7 @@ void data::update() {
scheduler::reset();
break;
}
} else if(mode != Mode::local) {
} else {
mode = Mode::local;
eeprom::jump(0);
scheduler::state = scheduler::State::pause;
@ -87,3 +87,23 @@ unsigned data::read(char* data, unsigned len) {
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();
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 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) {
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) {
uint8_t i2c_addr = ADDR;
if(at > 0xffff) {
i2c_addr |= 1;
}
return i2c_addr;
return ADDR ^ (at >> 16);
}
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) {
last_block_end = 0;
at = p_at;
}
@ -48,11 +46,16 @@ void eeprom::read(char* data, uint16_t data_size) {
uint16_t recorded = 0;
while(recorded < data_size && at < LENGTH) {
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 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.read(data + recorded, read_len, true);
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.end();
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 uint32_t BLOCK_SIZE = 0x10000;
constexpr uint32_t LENGTH = 0x20000;
constexpr uint32_t LENGTH = 0x80000;
inline SoftTWI mem(A4, A5);
@ -16,5 +16,6 @@ namespace eeprom {
void jump(uint32_t addr);
void read(char* data, uint16_t len);
void page_write(uint32_t at, const char* data);
uint32_t get_addr();
};

View File

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

View File

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

View File

@ -13,6 +13,17 @@ inline void swap(T& a, T& b) {
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]))