#include <MicroView.h>
#include <Brain.h>
#include <Wire.h>
template <class E, int Len=10> class Queue {
private:
E queue[Len];
byte qHead,qTail;
public:
Queue() : qHead(0), qTail(0) { }
bool empty() {
return length()==0;
}
bool full() {
return length()==Len-1;
}
int length() {
return (qTail+Len-qHead)%Len;
}
E* current() {
return &queue[qHead];
}
void remove() {
if (empty()) return;
qHead++;
qHead %= Len;
}
void add(const E &value) {
if (full()) return;
queue[qTail] = value;
qTail++;
qTail %= Len;
}
};
class Keepon {
public:
enum State { WAITING=1, MASTERING, READY, QFULL };
typedef void (*callback)(State,int);
private:
static const int maxAttempts = 50;
static const long MK_FREQ = 49600L;
static const byte SOUND = 0x52;
static const byte BUTTON = 0x50;
static const byte MOTOR = 0x55;
struct Command {
byte device;
byte command;
byte arg;
};
Queue<Command,10> queue;
byte attempts;
callback display_callback;
State current_state;
int last_time;
void set_state(State value,int n) {
current_state = value;
display_callback(value,n);
}
void check_state() {
int r = analogRead(0);
int t = millis() - last_time;
if (r <= 512) {
digitalWrite(SDA, LOW);
digitalWrite(SCL, LOW);
set_state(WAITING,r);
}
else if (current_state == WAITING) {
last_time = millis();
set_state(MASTERING,0);
}
else if (current_state == MASTERING && t > 1000) {
Wire.begin();
TWBR = ((F_CPU / MK_FREQ) - 16) / 2;
set_state(READY,t/10);
}
}
public:
Keepon(callback x) : attempts(0), display_callback(x) { }
void begin() {
pinMode(SDA, OUTPUT);
pinMode(SCL, OUTPUT);
check_state();
}
void update() {
check_state();
if (current_state != READY) return;
if (attempts > maxAttempts) {
attempts = 0;
queue.remove();
}
if (queue.empty()) return;
Command* current = queue.current();
Wire.beginTransmission(current->device);
Wire.write(current->command);
Wire.write(current->arg);
int result = (int)Wire.endTransmission();
if (result == 0) {
queue.remove();
display_callback(current_state,queue.length());
attempts = 0;
}
else {
attempts++;
}
}
void add(const Command&c) {
if (queue.full()) {
display_callback(QFULL,queue.length());
return;
}
queue.add(c);
display_callback(current_state,queue.length());
}
void pan(byte pos) {
add(Command{MOTOR,4,pos});
}
void tilt(byte pos) {
add(Command{MOTOR,2,pos});
}
};
Brain brain(Serial);
void kscan_callback(Keepon::State s, int n) {
if (s == Keepon::WAITING) {
uView.setCursor(25,0);uView.print("K?");
}
else if (s == Keepon::MASTERING){
uView.setCursor(25,0);uView.print("K..");
}
else if (s == Keepon::READY){
uView.setCursor(25,0);uView.print("K!");
}
else if (s == Keepon::QFULL){
uView.setCursor(25,0);uView.print("KO");
}
uView.setCursor(40,0);uView.print(n);
}
Keepon keepon(&kscan_callback);
void setup() {
Serial.begin(9600);
uView.begin();
uView.clear(ALL);
uView.setFontType(0);
keepon.begin();
}
const int hist_width=3;
const int hist_pad=1;
int samples_delay;
byte attention, meditation, quality;
int hist_height[8];
void loop() {
uView.clear(PAGE);
keepon.update();
if (brain.update()) {
quality=brain.readSignalQuality();
attention=brain.readAttention();
meditation=brain.readMeditation();
const uint32_t* power = brain.readPowerArray();
uint32_t max_value=0;
for (int x=0;x<8;++x) {
if (power[x] > max_value) {
max_value = power[x];
}
}
for (int x=0;x<8;++x) {
hist_height[x] = power[x] * 30 / max_value;
}
if (quality < 10 && ++samples_delay > 5) {
keepon.pan(attention);
keepon.tilt(meditation);
samples_delay=0;
uView.setCursor(5,0);uView.print("sent");
}
}
uView.setCursor(0,0); uView.print(quality=brain.readSignalQuality());
uView.setCursor(0,9); uView.print(attention=brain.readAttention());
uView.setCursor(18,9); uView.print(meditation=brain.readMeditation());
for (int x=0;x<8;++x) {
int x0 = (hist_width + hist_pad) * x;
for (int o=0;o<hist_width;++o) {
uView.lineV(x0+o,47-hist_height[x],hist_height[x]);
}
}
uView.display();
}