#include #include #include template 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 // Set clock to 50kHz (actualy 49.6kHz seems to work better) #define SOUND (byte)0x52 // Sound controller (device ID 82). Write to 0xA4, read from 0xA5. #define BUTTON (byte)0x50 // Button controller (device ID 80). Write to 0xA0, read from 0xA1. #define MOTOR (byte)0x55 // Motor controller (device ID 85). Write to 0xAA, read from 0xAB. 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 queue; byte attempts; callback display_callback; void take_control() { digitalWrite(SDA, LOW); digitalWrite(SCL, LOW); display_callback(WAITING); while (analogRead(0) < 512); // Wait until we see voltage on A0 pin 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); // Data wire on My Keepon pinMode(SCL, OUTPUT); // Clock wire on My Keepon 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; // we have 30 vertical pixels int height = power[x] * 30 / max_value; for (int o=0;o 5) { keepon.pan(attention); keepon.tilt(meditation); samples_delay=0; uView.setCursor(5,0);uView.print("sent"); } } if (ku) { keepon.send(); } uView.display(); } }