summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--eeg.ino178
1 files changed, 107 insertions, 71 deletions
diff --git a/eeg.ino b/eeg.ino
index d55b91f..d8af88b 100644
--- a/eeg.ino
+++ b/eeg.ino
@@ -8,12 +8,16 @@ template <class E, int Len=10> class Queue {
E queue[Len];
byte qHead,qTail;
public:
+
Queue() : qHead(0), qTail(0) { }
bool empty() {
- return qHead == qTail;
+ return length()==0;
}
bool full() {
- return ((qHead+Len-1)%Len) == qTail;
+ return length()==Len-1;
+ }
+ int length() {
+ return (qTail+Len-qHead)%Len;
}
E* current() {
return &queue[qHead];
@@ -33,17 +37,23 @@ template <class E, int Len=10> class Queue {
}
};
-#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);
+ 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;
@@ -54,51 +64,65 @@ class Keepon {
callback display_callback;
- // these two functions need to be loop-friendly! no while, no delay
- 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;
+ 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);
+ }
}
- 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() {
- check_connection();
- if (queue.empty()) return false;
- return true;
+ check_state();
}
- void send() {
- check_connection();
+
+ 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 {
@@ -108,10 +132,11 @@ class Keepon {
void add(const Command&c) {
if (queue.full()) {
- display_callback(QFULL);
+ display_callback(QFULL,queue.length());
return;
}
queue.add(c);
+ display_callback(current_state,queue.length());
}
void pan(byte pos) {
@@ -124,16 +149,20 @@ class Keepon {
Brain brain(Serial);
-void kscan_callback(Keepon::State s) {
+void kscan_callback(Keepon::State s, int n) {
if (s == Keepon::WAITING) {
- uView.setCursor(25,0);uView.println("K?");
+ 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.println("K!");
+ uView.setCursor(25,0);uView.print("K!");
}
else if (s == Keepon::QFULL){
- uView.setCursor(25,0);uView.println("K+");
+ uView.setCursor(25,0);uView.print("KO");
}
+ uView.setCursor(40,0);uView.print(n);
}
Keepon keepon(&kscan_callback);
@@ -152,46 +181,53 @@ const int hist_width=3;
const int hist_pad=1;
int samples_delay;
+byte attention, meditation, quality;
+int hist_height[8];
+
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];
- }
+ 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) {
- int x0 = (hist_width + hist_pad) * x;
- // we have 30 vertical pixels
- int height = power[x] * 30 / max_value;
- for (int o=0;o<hist_width;++o) {
- uView.lineV(x0+o,47-height,height);
- }
- }
+ for (int x=0;x<8;++x) {
+ // we have 30 vertical pixels
+ hist_height[x] = power[x] * 30 / max_value;
+ }
- if (quality < 10 && ++samples_delay > 5) {
- keepon.pan(attention);
- keepon.tilt(meditation);
- samples_delay=0;
+ if (quality < 10 && ++samples_delay > 5) {
+ keepon.pan(attention);
+ keepon.tilt(meditation);
+ samples_delay=0;
- uView.setCursor(5,0);uView.print("sent");
- }
+ uView.setCursor(5,0);uView.print("sent");
}
- if (ku) {
- keepon.send();
+ }
+
+
+ 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();
}
+
+ uView.display();
} \ No newline at end of file