#include #include #include template class Queue { private: E queue[Len]; byte qHead,qLen; public: Queue() : qHead(0), qLen(0) { } bool empty() { return length()==0; } bool full() { return length()==Len; } int length() { return qLen; } E* current() { return &queue[qHead]; } void remove() { if (empty()) return; ++qHead;--qLen; qHead %= Len; } void add(const E &value) { if (full()) return; queue[(qHead+qLen)%Len] = value; ++qLen; } }; class Keepon { public: enum State { WAITING=1, MASTERING, READY, QFULL }; typedef void (*callback)(State,int); private: static const int maxAttempts = 50; // Set clock to 50kHz (actualy 49.6kHz seems to work better) static const long MK_FREQ = 49600L; // Sound controller (device ID 82). Write to 0xA4, read from 0xA5. static const byte SOUND = 0x52; // Button controller (device ID 80). Write to 0xA0, read from 0xA1. static const byte BUTTON = 0x50; // Motor controller (device ID 85). Write to 0xAA, read from 0xAB. static const byte MOTOR = 0x55; struct Command { byte device; byte command; byte arg; }; Queue 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 v; if ((v=analogRead(0)) <= 512) { digitalWrite(SDA, LOW); digitalWrite(SCL, LOW); current_state = WAITING; } else if (current_state == WAITING) { last_time = millis(); digitalWrite(SDA, LOW); digitalWrite(SCL, LOW); current_state = MASTERING; v=0; } else if (current_state == MASTERING && (v=millis()-last_time) < 1000) { v/=100; } else if (current_state == MASTERING) { Wire.begin(); TWBR = ((F_CPU / MK_FREQ) - 16) / 2; current_state = READY; v = queue.length(); } else if (current_state == READY) { v = queue.length(); } display_callback(current_state,v); } 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 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) { uView.setCursor(25,0); if (s == Keepon::WAITING) { uView.print("K?"); } else if (s == Keepon::MASTERING){ uView.print("K.."); } else if (s == Keepon::READY){ uView.print("K!"); } else if (s == Keepon::QFULL){ 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; 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) { // we have 30 vertical pixels hist_height[x] = power[x] * 30 / max_value; } if (quality < 10) { keepon.pan(attention); keepon.tilt(meditation); 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