From aa7d03ba9c6d61597b10d06804bfee7d53b45ce2 Mon Sep 17 00:00:00 2001 From: Federico Fissore Date: Wed, 7 Aug 2013 17:16:13 +0200 Subject: [PATCH] spacebrew update --- .../inputOutput.ino} | 64 ++++-- .../spacebrewBoolean/spacebrewBoolean.ino | 89 +++++++++ .../spacebrewRange/spacebrewRange.ino | 86 ++++++++ .../spacebrewString/spacebrewString.ino | 84 ++++++++ libraries/SpacebrewYun/SpacebrewYun.cpp | 185 ++++++++++++++---- libraries/SpacebrewYun/SpacebrewYun.h | 29 ++- 6 files changed, 473 insertions(+), 64 deletions(-) rename libraries/Bridge/examples/SpacebrewYun/{input_output/input_output.ino => inputOutput/inputOutput.ino} (58%) create mode 100644 libraries/Bridge/examples/SpacebrewYun/spacebrewBoolean/spacebrewBoolean.ino create mode 100644 libraries/Bridge/examples/SpacebrewYun/spacebrewRange/spacebrewRange.ino create mode 100644 libraries/Bridge/examples/SpacebrewYun/spacebrewString/spacebrewString.ino diff --git a/libraries/Bridge/examples/SpacebrewYun/input_output/input_output.ino b/libraries/Bridge/examples/SpacebrewYun/inputOutput/inputOutput.ino similarity index 58% rename from libraries/Bridge/examples/SpacebrewYun/input_output/input_output.ino rename to libraries/Bridge/examples/SpacebrewYun/inputOutput/inputOutput.ino index e95457f..be22850 100644 --- a/libraries/Bridge/examples/SpacebrewYun/input_output/input_output.ino +++ b/libraries/Bridge/examples/SpacebrewYun/inputOutput/inputOutput.ino @@ -1,35 +1,54 @@ +/* + Input Output + + Demonstrates how to create a sketch that sends and receives all standard + spacebrew data types, and a custom data type. Every time data is + received it is output to the Serial monitor. + + Make sure that your Yun is connected to the internet for this example + to function properly. + + The circuit: + - No circuit required + + created 2013 + by Julio Terra + + This example code is in the public domain. + + More information about Spacebrew is available at: + http://spacebrew.cc/ + + */ + #include #include -/** - * Arduino Yun Spacebrew Library Example - * - * This example code is in the public domain. - * - * @date July 16, 2013 - * @author Julio Terra - * - */ - +// create a variable of type SpacebrewYun and initialize it with the constructor SpacebrewYun sb = SpacebrewYun("aYun", "Arduino Yun spacebrew test"); -int counter = 0; +// create variables to manage interval between each time we send a string long last = 0; int interval = 2000; +int counter = 0; + void setup() { + // start the serial port Serial.begin(57600); + + // for debugging, wait until a serial console is connected delay(4000); - while (!Serial) { Serial.println("connecting"); } + while (!Serial) { ; } - - //Initialize Console and wait for port to open: + // start-up the bridge Bridge.begin(); - Serial.println("Bridge Started"); - Serial.println("Configuring Spacebrew Client"); + // configure the spacebrew object to print status messages to serial sb.verbose(true); + + // configure the spacebrew publisher and subscriber sb.addPublish("string test", "string"); sb.addPublish("range test", "range"); sb.addPublish("boolean test", "boolean"); @@ -38,18 +57,27 @@ void setup() { sb.addSubscribe("range test", "range"); sb.addSubscribe("boolean test", "boolean"); sb.addSubscribe("custom test", "crazy"); + + // register the string message handler method sb.onRangeMessage(handleRange); sb.onStringMessage(handleString); sb.onBooleanMessage(handleBoolean); sb.onCustomMessage(handleCustom); + + // connect to cloud spacebrew server at "sandbox.spacebrew.cc" sb.connect("sandbox.spacebrew.cc"); } void loop() { + // monitor spacebrew connection for new data sb.monitor(); + + // connected to spacebrew then send a string every 2 seconds if ( sb.connected() ) { + + // check if it is time to send a new message if ( (millis() - last) > interval ) { String test_str_msg = "testing, testing, "; test_str_msg += counter; @@ -66,6 +94,8 @@ void loop() { } } +// define handler methods, all standard data type handlers take two appropriate arguments + void handleRange (String route, int value) { Serial.print("Range msg "); Serial.print(route); @@ -87,6 +117,8 @@ void handleBoolean (String route, boolean value) { Serial.println(value ? "true" : "false"); } +// custom data type handlers takes three String arguments + void handleCustom (String route, String value, String type) { Serial.print("Custom msg "); Serial.print(route); diff --git a/libraries/Bridge/examples/SpacebrewYun/spacebrewBoolean/spacebrewBoolean.ino b/libraries/Bridge/examples/SpacebrewYun/spacebrewBoolean/spacebrewBoolean.ino new file mode 100644 index 0000000..0f068aa --- /dev/null +++ b/libraries/Bridge/examples/SpacebrewYun/spacebrewBoolean/spacebrewBoolean.ino @@ -0,0 +1,89 @@ +/* + Spacebrew Boolean + + Demonstrates how to create a sketch that sends and receives a + boolean value to and from Spacebrew. Every time the buttton is + pressed (or other digital input component) a spacebrew message + is sent. The sketch also accepts analog range messages from + other Spacebrew apps. + + Make sure that your Yun is connected to the internet for this example + to function properly. + + The circuit: + - Button connected to Yun, using the Arduino's internal pullup resistor. + + created 2013 + by Julio Terra + + This example code is in the public domain. + + More information about Spacebrew is available at: + http://spacebrew.cc/ + + */ + +#include +#include + +// create a variable of type SpacebrewYun and initialize it with the constructor +SpacebrewYun sb = SpacebrewYun("spacebrewYun Boolean", "Boolean sender and receiver"); + +// variable that holds the last potentiometer value +int last_value = 0; + +// create variables to manage interval between each time we send a string +void setup() { + + // start the serial port + Serial.begin(57600); + + // for debugging, wait until a serial console is connected + delay(4000); + while (!Serial) { ; } + + // start-up the bridge + Bridge.begin(); + + // configure the spacebrew object to print status messages to serial + sb.verbose(true); + + // configure the spacebrew publisher and subscriber + sb.addPublish("physical button", "boolean"); + sb.addSubscribe("virtual button", "boolean"); + + // register the string message handler method + sb.onBooleanMessage(handleBoolean); + + // connect to cloud spacebrew server at "sandbox.spacebrew.cc" + sb.connect("sandbox.spacebrew.cc"); + + pinMode(3, INPUT); + digitalWrite(3, HIGH); +} + + +void loop() { + // monitor spacebrew connection for new data + sb.monitor(); + + // connected to spacebrew then send a new value whenever the pot value changes + if ( sb.connected() ) { + int cur_value = digitalRead(3); + if ( last_value != cur_value ) { + if (cur_value == HIGH) sb.send("physical button", false); + else sb.send("physical button", true); + last_value = cur_value; + } + } +} + +// handler method that is called whenever a new string message is received +void handleBoolean (String route, boolean value) { + // print the message that was received + Serial.print("From "); + Serial.print(route); + Serial.print(", received msg: "); + Serial.println(value ? "true" : "false"); +} + diff --git a/libraries/Bridge/examples/SpacebrewYun/spacebrewRange/spacebrewRange.ino b/libraries/Bridge/examples/SpacebrewYun/spacebrewRange/spacebrewRange.ino new file mode 100644 index 0000000..6dcbff8 --- /dev/null +++ b/libraries/Bridge/examples/SpacebrewYun/spacebrewRange/spacebrewRange.ino @@ -0,0 +1,86 @@ +/* + Spacebrew Range + + Demonstrates how to create a sketch that sends and receives analog + range value to and from Spacebrew. Every time the state of the + potentiometer (or other analog input component) change a spacebrew + message is sent. The sketch also accepts analog range messages from + other Spacebrew apps. + + Make sure that your Yun is connected to the internet for this example + to function properly. + + The circuit: + - Potentiometer connected to Yun. Middle pin connected to analog pin A0, + other pins connected to 5v and GND pins. + + created 2013 + by Julio Terra + + This example code is in the public domain. + + More information about Spacebrew is available at: + http://spacebrew.cc/ + + */ + +#include +#include + +// create a variable of type SpacebrewYun and initialize it with the constructor +SpacebrewYun sb = SpacebrewYun("spacebrewYun Range", "Range sender and receiver"); + +// variable that holds the last potentiometer value +int last_value = 0; + +// create variables to manage interval between each time we send a string +void setup() { + + // start the serial port + Serial.begin(57600); + + // for debugging, wait until a serial console is connected + delay(4000); + while (!Serial) { ; } + + // start-up the bridge + Bridge.begin(); + + // configure the spacebrew object to print status messages to serial + sb.verbose(true); + + // configure the spacebrew publisher and subscriber + sb.addPublish("physical pot", "range"); + sb.addSubscribe("virtual pot", "range"); + + // register the string message handler method + sb.onRangeMessage(handleRange); + + // connect to cloud spacebrew server at "sandbox.spacebrew.cc" + sb.connect("sandbox.spacebrew.cc"); +} + + +void loop() { + // monitor spacebrew connection for new data + sb.monitor(); + + // connected to spacebrew then send a new value whenever the pot value changes + if ( sb.connected() ) { + int cur_value = analogRead(A0); + if ( last_value != cur_value ) { + sb.send("physical pot", cur_value); + last_value = cur_value; + } + } +} + +// handler method that is called whenever a new string message is received +void handleRange (String route, int value) { + // print the message that was received + Serial.print("From "); + Serial.print(route); + Serial.print(", received msg: "); + Serial.println(value); +} + diff --git a/libraries/Bridge/examples/SpacebrewYun/spacebrewString/spacebrewString.ino b/libraries/Bridge/examples/SpacebrewYun/spacebrewString/spacebrewString.ino new file mode 100644 index 0000000..8c8f1c7 --- /dev/null +++ b/libraries/Bridge/examples/SpacebrewYun/spacebrewString/spacebrewString.ino @@ -0,0 +1,84 @@ +/* + Spacebrew String + + Demonstrates how to create a sketch that sends and receives strings + to and from Spacebrew. Every time string data is received it + is output to the Serial monitor. + + Make sure that your Yun is connected to the internet for this example + to function properly. + + The circuit: + - No circuit required + + created 2013 + by Julio Terra + + This example code is in the public domain. + + More information about Spacebrew is available at: + http://spacebrew.cc/ + + */ + +#include +#include + +// create a variable of type SpacebrewYun and initialize it with the constructor +SpacebrewYun sb = SpacebrewYun("spacebrewYun Strings", "String sender and receiver"); + +// create variables to manage interval between each time we send a string +long last_time = 0; +int interval = 2000; + +void setup() { + + // start the serial port + Serial.begin(57600); + + // for debugging, wait until a serial console is connected + delay(4000); + while (!Serial) { ; } + + // start-up the bridge + Bridge.begin(); + + // configure the spacebrew object to print status messages to serial + sb.verbose(true); + + // configure the spacebrew publisher and subscriber + sb.addPublish("speak", "string"); + sb.addSubscribe("listen", "string"); + + // register the string message handler method + sb.onStringMessage(handleString); + + // connect to cloud spacebrew server at "sandbox.spacebrew.cc" + sb.connect("sandbox.spacebrew.cc"); +} + + +void loop() { + // monitor spacebrew connection for new data + sb.monitor(); + + // connected to spacebrew then send a string every 2 seconds + if ( sb.connected() ) { + + // check if it is time to send a new message + if ( (millis() - last_time) > interval ) { + sb.send("speak", "is anybody out there?"); + last_time = millis(); + } + } +} + +// handler method that is called whenever a new string message is received +void handleString (String route, String value) { + // print the message that was received + Serial.print("From "); + Serial.print(route); + Serial.print(", received msg: "); + Serial.println(value); +} + diff --git a/libraries/SpacebrewYun/SpacebrewYun.cpp b/libraries/SpacebrewYun/SpacebrewYun.cpp index a2d04a5..7c848e7 100644 --- a/libraries/SpacebrewYun/SpacebrewYun.cpp +++ b/libraries/SpacebrewYun/SpacebrewYun.cpp @@ -4,6 +4,8 @@ SpacebrewYun::SpacebrewYun(const String& _name, const String& _description) { name = _name; description = _description; + subscribers = NULL; + publishers = NULL; server = "sandbox.spacebrew.cc"; port = 9000; @@ -18,8 +20,6 @@ SpacebrewYun::SpacebrewYun(const String& _name, const String& _description) { read_name = false; read_msg = false; - sub_name_max = 25; - sub_msg_max = 50; for ( int i = 0; i < pidLength; i++ ) { pid [i] = '\0'; @@ -33,7 +33,10 @@ SpacebrewYun::SpacebrewYun(const String& _name, const String& _description) { } -// boolean SpacebrewYun::_connected = false; +int SpacebrewYun::sub_msg_int_max = 6; +int SpacebrewYun::sub_msg_bool_max = 5; +int SpacebrewYun::sub_msg_str_max = 50; +int SpacebrewYun::sub_name_max = 20; SpacebrewYun::OnBooleanMessage SpacebrewYun::_onBooleanMessage = NULL; SpacebrewYun::OnRangeMessage SpacebrewYun::_onRangeMessage = NULL; SpacebrewYun::OnStringMessage SpacebrewYun::_onStringMessage = NULL; @@ -65,40 +68,57 @@ void SpacebrewYun::onError(OnSBError function){ } void SpacebrewYun::addPublish(const String& name, const String& type) { - Publisher *p = new Publisher(); + struct Publisher *p = new Publisher(); p->name = createString(name.length() + 1); p->type = createString(type.length() + 1); + p->confirmed = false; + p->time = 0; + if (type == "range") { + p->lastMsg = createString(sub_msg_int_max); + emptyString(p->lastMsg, sub_msg_int_max); + } + else if (type == "boolean") { + p->lastMsg = createString(sub_msg_bool_max); + emptyString(p->lastMsg, sub_msg_bool_max); + } + else { + p->lastMsg = createString(sub_msg_str_max); + emptyString(p->lastMsg, sub_msg_str_max); + } name.toCharArray(p->name, name.length() + 1); type.toCharArray(p->type, type.length() + 1); if (publishers == NULL){ publishers = p; - } else { - Publisher *curr = publishers; + } + else { + struct Publisher *curr = publishers; + int counter = 1; while(curr->next != NULL){ curr = curr->next; + counter++; } curr->next = p; } + p->next = NULL; } void SpacebrewYun::addSubscribe(const String& name, const String& type) { - Subscriber *p = new Subscriber(); - p->name = createString(name.length() + 1); - p->type = createString(type.length() + 1); - name.toCharArray(p->name, name.length() + 1); - type.toCharArray(p->type, type.length() + 1); + Subscriber *s = new Subscriber(); + s->name = createString(name.length() + 1); + s->type = createString(type.length() + 1); + name.toCharArray(s->name, name.length() + 1); + type.toCharArray(s->type, type.length() + 1); if (subscribers == NULL){ - subscribers = p; + subscribers = s; } - else { - Subscriber *curr = subscribers; + struct Subscriber *curr = subscribers; while(curr->next != NULL){ curr = curr->next; } - curr->next = p; + curr->next = s; } } @@ -108,8 +128,9 @@ void SpacebrewYun::connect(String _server, int _port) { killPids(); - brew.begin("python"); // Process should launch the "curl" command - brew.addParameter("/usr/lib/python2.7/spacebrew/spacebrew.py"); // Process should launch the "curl" command + brew.begin("run-spacebrew"); // Process should launch the "curl" command + // brew.begin("python"); // Process should launch the "curl" command + // brew.addParameter("/usr/lib/python2.7/spacebrew/spacebrew.py"); // Process should launch the "curl" command brew.addParameter("--server"); brew.addParameter(server); brew.addParameter("--port"); @@ -120,11 +141,13 @@ void SpacebrewYun::connect(String _server, int _port) { brew.addParameter(description); if (subscribers != NULL) { - Subscriber *curr = subscribers; + struct Subscriber *curr = subscribers; while(curr != NULL){ if (_verbose) { - Serial.print(F("Creating subcribers: ")); - Serial.println(curr->name); + Serial.print(F("Creating subscribers: ")); + Serial.print(curr->name); + Serial.print(F(" of type: ")); + Serial.println(curr->type); } brew.addParameter("-s"); // Add the URL parameter to "curl" @@ -132,29 +155,40 @@ void SpacebrewYun::connect(String _server, int _port) { brew.addParameter(","); // Add the URL parameter to "curl" brew.addParameter(curr->type); // Add the URL parameter to "curl" - if (curr->next == NULL) curr = NULL; - else curr = curr->next; + // if (curr->next == NULL) curr = NULL; + // else curr = curr->next; + + curr = curr->next; } } if (publishers != NULL) { - Publisher *curr = publishers; + struct Publisher *curr = publishers; while(curr != NULL){ if (_verbose) { Serial.print(F("Creating publishers: ")); - Serial.println(curr->name); + Serial.print(curr->name); + Serial.print(F(" of type: ")); + Serial.println(curr->type); } brew.addParameter("-p"); // Add the URL parameter to "curl" brew.addParameter(curr->name); // Add the URL parameter to "curl" brew.addParameter(","); // Add the URL parameter to "curl" brew.addParameter(curr->type); // Add the URL parameter to "curl" - if (curr->next == NULL) curr = NULL; - else curr = curr->next; + curr = curr->next; } } Console.begin(); + if (_verbose) { + Serial.println(F("Console started ")); + } + brew.runAsynchronously(); + + if (_verbose) { + Serial.println(F("Brew started ")); + } while (!Console) { ; } } @@ -163,7 +197,6 @@ void SpacebrewYun::monitor() { char c = Console.read(); if (c == char(CONNECTION_START) && !_connected) { - _connected = true; if (_verbose) { Serial.print(F("Connected to spacebrew server at: ")); Serial.println(server); @@ -173,6 +206,7 @@ void SpacebrewYun::monitor() { if (_onOpen != NULL){ _onOpen(); } + _connected = true; } else if (c == char(CONNECTION_END) && _connected) { _connected = false; @@ -205,12 +239,24 @@ void SpacebrewYun::monitor() { } else if (c == char(MSG_DIV) || sub_name.length() > sub_name_max) { read_name = false; read_msg = true; - } else if (c == char(MSG_END) || sub_msg.length() > sub_msg_max) { - read_msg = false; - onMessage(); + } else if (c == char(MSG_END) || sub_msg.length() > sub_msg_str_max) { + if (read_msg == true) { + read_msg = false; + onMessage(); + // delay(2); + } + if (read_confirm == true) { + read_confirm = false; + onConfirm(); + delay(2); + } + } else if (c == char(MSG_CONFIRM)) { + read_confirm = true; } else { if (read_name == true) { sub_name += c; + } else if (read_confirm == true) { + sub_name += c; } else if (read_msg == true) { sub_msg += c; } @@ -220,6 +266,43 @@ void SpacebrewYun::monitor() { } } } + + if (publishers != NULL) { + struct Publisher *curr = publishers; + while((curr != NULL)){ + + if ( (curr->confirmed == 0) && ((millis() - curr->time) > 50) ) { + if (_verbose) { + Serial.print(F("resending msg: ")); + Serial.println(curr->name); + } + send(curr->name, curr->lastMsg); + } + curr = curr->next; + } + } + +} + +void SpacebrewYun::onConfirm() { + if (publishers != NULL) { + struct Publisher *curr = publishers; + while((curr != NULL)){ + if (sub_name.equals(curr->name) == true) { + curr->confirmed = true; + // if (_verbose) { + // Serial.print(F("confirmed ")); + // Serial.println(curr->name); + // } + break; + } + curr = curr->next; + } + } + + sub_name = ""; + sub_msg = ""; + sub_type = ""; } boolean SpacebrewYun::connected() { @@ -232,13 +315,12 @@ void SpacebrewYun::verbose(boolean verbose = true) { void SpacebrewYun::onMessage() { if (subscribers != NULL) { - Subscriber *curr = subscribers; + struct Subscriber *curr = subscribers; while((curr != NULL) && (sub_type == "")){ if (sub_name.equals(curr->name) == true) { sub_type = curr->type; } - if (curr->next == NULL) curr = NULL; - else curr = curr->next; + curr = curr->next; } } @@ -275,14 +357,34 @@ void SpacebrewYun::onMessage() { void SpacebrewYun::send(const String& name, const String& value){ - Console.print(char(29)); - Console.print(name); - Console.print(char(30)); - Console.print(value); - Console.print(char(31)); - Console.flush(); + if (publishers != NULL) { - true; + Console.print(char(29)); + Console.print(name); + Console.print(char(30)); + Console.print(value); + Console.print(char(31)); + Console.flush(); + + struct Publisher *curr = publishers; + while(curr != NULL){ + if (name.equals(curr->name) == true) { + int msg_len = 0; + + if (curr->type == "range") msg_len = sub_msg_int_max; + else if (curr->type == "boolean") msg_len = sub_msg_bool_max; + else msg_len = sub_msg_str_max; + + if (value.length() < msg_len) msg_len = value.length() + 1; + value.toCharArray(curr->lastMsg, msg_len); + + curr->confirmed = false; + curr->time = millis(); + + } + curr = curr->next; + } + } } @@ -292,8 +394,9 @@ void SpacebrewYun::send(const String& name, const String& value){ void SpacebrewYun::getPids() { // request the pid of all python processes + // brew.begin("run-getsbpids"); // Process should launch the "curl" command pids.begin("python"); - pids.addParameter("/usr/lib/python2.7/spacebrew/getProcPid.py"); // Process should launch the "curl" command + pids.addParameter("/usr/lib/python2.7/spacebrew/getprocpid.py"); // Process should launch the "curl" command pids.run(); if (_verbose) { diff --git a/libraries/SpacebrewYun/SpacebrewYun.h b/libraries/SpacebrewYun/SpacebrewYun.h index 8fd7bd2..df608c1 100644 --- a/libraries/SpacebrewYun/SpacebrewYun.h +++ b/libraries/SpacebrewYun/SpacebrewYun.h @@ -11,6 +11,7 @@ enum SBmsg { CONNECTION_START = char(28), CONNECTION_END = char(27), CONNECTION_ERROR = char(26), + MSG_CONFIRM = char(7), MSG_START = char(29), MSG_DIV = char(30), MSG_END = char(31) @@ -19,14 +20,16 @@ enum SBmsg { struct Publisher { char *name; char *type; - char *defaultValue; - Publisher * next; + char *lastMsg; + Publisher *next; + int confirmed; + long time; }; struct Subscriber{ char *name; char *type; - Subscriber * next; + Subscriber *next; }; int const pidLength = 6; @@ -46,12 +49,13 @@ class SpacebrewYun { void monitor(); void onMessage(); + void onConfirm(); boolean connected(); void send(const String&, const String&); void send(const String& name, char * value) { send(name, String(value)); } - void send(const String& name, bool value){ send(name, (value ? "true" : "false")); }; + void send(const String& name, bool value){ send(name, (value ? String("true") : String("false"))); }; void send(const String& name, int value) { send(name, String(value)); }; void send(const String& name, long value) { send(name, String(value)); }; void send(const String& name, float value) { send(name, String(value)); }; @@ -102,8 +106,13 @@ class SpacebrewYun { boolean read_name; boolean read_msg; - int sub_name_max; - int sub_msg_max; + boolean read_confirm; + static int sub_name_max; + static int sub_msg_str_max; + static int sub_msg_int_max; + static int sub_msg_bool_max; + // int sub_name_max; + // int sub_msg_str_max; Process pids; char pid [6]; @@ -113,10 +122,16 @@ class SpacebrewYun { void getPids(); static char * createString(int len){ - char * out = ( char * )malloc( len + 1 ); + char * out = ( char * ) malloc ( len + 1 ); return out; } + static void emptyString(char * str, int len){ + for (int i = 0; i < len; i++) { + str[i] = '\0'; + } + } + }; #endif