#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 qHead == qTail;
}
bool full() {
return ((qHead+Len-1)%Len) == qTail;
}
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;
}
};
#define MK_FREQ 49600L
#define SOUND (byte)0x52
#define BUTTON (byte)0x50
#define MOTOR (byte)0x55
class Keepon {
public:
enum State { WAITING=1, READY, QFULL };
typedef void (*callback)(State);
private:
static const int maxAttempts = 50;
struct Command {
byte device;
byte command;
byte arg;
};
Queue<Command,10> queue;
byte attempts;
callback display_callback;
void take_control() {
digitalWrite(SDA, LOW);
digitalWrite(SCL, LOW);
display_callback(WAITING);
while (analogRead(0) < 512);
display_callback(READY);
delay(1000);
Wire.begin();
TWBR = ((F_CPU / MK_FREQ) - 16) / 2;
}
void check_connection() {
if (analogRead(0) > 512) return;
take_control();
}
public:
Keepon(callback x) : attempts(0), display_callback(x) { }
void begin() {
pinMode(SDA, OUTPUT);
pinMode(SCL, OUTPUT);
digitalWrite(SDA, LOW);
digitalWrite(SCL, LOW);
}
bool update() {
if (queue.empty()) return false;
return true;
}
void send() {
check_connection();
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();
attempts = 0;
}
else {
attempts++;
}
}
void add(const Command&c) {
if (queue.full()) {
display_callback(QFULL);
return;
}
queue.add(c);
}
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) {
if (s == Keepon::WAITING) {
uView.setCursor(25,0);uView.println("K?");
}
else if (s == Keepon::READY){
uView.setCursor(25,0);uView.println("K!");
}
else if (s == Keepon::QFULL){
uView.setCursor(25,0);uView.println("K+");
}
}
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;
void loop() {
byte attention, meditation, quality;
bool bu = brain.update(); bool ku = keepon.update();
if (bu || ku) {
uView.clear(PAGE);
if (bu) {
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());
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) {
int x0 = (hist_width + hist_pad) * x;
int height = power[x] * 30 / max_value;
for (int o=0;o<hist_width;++o) {
uView.lineV(x0+o,47-height,height);
}
}
if (quality < 10 && ++samples_delay > 5) {
keepon.pan(attention);
keepon.tilt(meditation);
samples_delay=0;
uView.setCursor(5,0);uView.print("sent");
}
}
if (ku) {
keepon.send();
}
uView.display();
}
}