diff --git a/libraries/Bridge/examples/SpacebrewYun/input_output/input_output.ino b/libraries/Bridge/examples/SpacebrewYun/input_output/input_output.ino new file mode 100644 index 0000000..e95457f --- /dev/null +++ b/libraries/Bridge/examples/SpacebrewYun/input_output/input_output.ino @@ -0,0 +1,98 @@ +#include +#include + +/** + * Arduino Yun Spacebrew Library Example + * + * This example code is in the public domain. + * + * @date July 16, 2013 + * @author Julio Terra + * + */ + +SpacebrewYun sb = SpacebrewYun("aYun", "Arduino Yun spacebrew test"); + +int counter = 0; +long last = 0; +int interval = 2000; + +void setup() { + + Serial.begin(57600); + delay(4000); + while (!Serial) { Serial.println("connecting"); } + + + //Initialize Console and wait for port to open: + Bridge.begin(); + Serial.println("Bridge Started"); + + Serial.println("Configuring Spacebrew Client"); + sb.verbose(true); + sb.addPublish("string test", "string"); + sb.addPublish("range test", "range"); + sb.addPublish("boolean test", "boolean"); + sb.addPublish("custom test", "crazy"); + sb.addSubscribe("string test", "string"); + sb.addSubscribe("range test", "range"); + sb.addSubscribe("boolean test", "boolean"); + sb.addSubscribe("custom test", "crazy"); + sb.onRangeMessage(handleRange); + sb.onStringMessage(handleString); + sb.onBooleanMessage(handleBoolean); + sb.onCustomMessage(handleCustom); + sb.connect("sandbox.spacebrew.cc"); + +} + + +void loop() { + sb.monitor(); + if ( sb.connected() ) { + if ( (millis() - last) > interval ) { + String test_str_msg = "testing, testing, "; + test_str_msg += counter; + counter ++; + + sb.send("string test", test_str_msg); + sb.send("range test", 500); + sb.send("boolean test", true); + sb.send("custom test", "youre loco"); + + last = millis(); + + } + } +} + +void handleRange (String route, int value) { + Serial.print("Range msg "); + Serial.print(route); + Serial.print(", value "); + Serial.println(value); +} + +void handleString (String route, String value) { + Serial.print("String msg "); + Serial.print(route); + Serial.print(", value "); + Serial.println(value); +} + +void handleBoolean (String route, boolean value) { + Serial.print("Boolen msg "); + Serial.print(route); + Serial.print(", value "); + Serial.println(value ? "true" : "false"); +} + +void handleCustom (String route, String value, String type) { + Serial.print("Custom msg "); + Serial.print(route); + Serial.print(" of type "); + Serial.print(type); + Serial.print(", value "); + Serial.println(value); +} + diff --git a/libraries/SpacebrewYun/SpacebrewYun.cpp b/libraries/SpacebrewYun/SpacebrewYun.cpp new file mode 100644 index 0000000..a2d04a5 --- /dev/null +++ b/libraries/SpacebrewYun/SpacebrewYun.cpp @@ -0,0 +1,356 @@ +#include "SpacebrewYun.h" + + +SpacebrewYun::SpacebrewYun(const String& _name, const String& _description) { + name = _name; + description = _description; + + server = "sandbox.spacebrew.cc"; + port = 9000; + + _connected = false; + _verbose = false; + _error_msg = false; + + sub_name = ""; + sub_msg = ""; + sub_type = ""; + + read_name = false; + read_msg = false; + sub_name_max = 25; + sub_msg_max = 50; + + for ( int i = 0; i < pidLength; i++ ) { + pid [i] = '\0'; + } + + for ( int i = 0; i < sbPidsLen; i++ ) { + sbPids [i] = '\0'; + } + + Console.buffer(64); + +} + +// boolean SpacebrewYun::_connected = false; +SpacebrewYun::OnBooleanMessage SpacebrewYun::_onBooleanMessage = NULL; +SpacebrewYun::OnRangeMessage SpacebrewYun::_onRangeMessage = NULL; +SpacebrewYun::OnStringMessage SpacebrewYun::_onStringMessage = NULL; +SpacebrewYun::OnCustomMessage SpacebrewYun::_onCustomMessage = NULL; +SpacebrewYun::OnSBOpen SpacebrewYun::_onOpen = NULL; +SpacebrewYun::OnSBClose SpacebrewYun::_onClose = NULL; +SpacebrewYun::OnSBError SpacebrewYun::_onError = NULL; + +void SpacebrewYun::onOpen(OnSBOpen function){ + _onOpen = function; +} +void SpacebrewYun::onClose(OnSBClose function){ + _onClose = function; +} +void SpacebrewYun::onRangeMessage(OnRangeMessage function){ + _onRangeMessage = function; +} +void SpacebrewYun::onStringMessage(OnStringMessage function){ + _onStringMessage = function; +} +void SpacebrewYun::onBooleanMessage(OnBooleanMessage function){ + _onBooleanMessage = function; +} +void SpacebrewYun::onCustomMessage(OnCustomMessage function){ + _onCustomMessage = function; +} +void SpacebrewYun::onError(OnSBError function){ + _onError = function; +} + +void SpacebrewYun::addPublish(const String& name, const String& type) { + Publisher *p = new Publisher(); + 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); + + if (publishers == NULL){ + publishers = p; + } else { + Publisher *curr = publishers; + while(curr->next != NULL){ + curr = curr->next; + } + curr->next = p; + } +} + +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); + + if (subscribers == NULL){ + subscribers = p; + } + + else { + Subscriber *curr = subscribers; + while(curr->next != NULL){ + curr = curr->next; + } + curr->next = p; + } +} + +void SpacebrewYun::connect(String _server, int _port) { + server = _server; + port = _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.addParameter("--server"); + brew.addParameter(server); + brew.addParameter("--port"); + brew.addParameter(String(port)); + brew.addParameter("-n"); + brew.addParameter(name); + brew.addParameter("-d"); + brew.addParameter(description); + + if (subscribers != NULL) { + Subscriber *curr = subscribers; + while(curr != NULL){ + if (_verbose) { + Serial.print(F("Creating subcribers: ")); + Serial.println(curr->name); + } + + brew.addParameter("-s"); // 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; + } + } + if (publishers != NULL) { + Publisher *curr = publishers; + while(curr != NULL){ + if (_verbose) { + Serial.print(F("Creating publishers: ")); + Serial.println(curr->name); + } + 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; + } + } + + Console.begin(); + brew.runAsynchronously(); + while (!Console) { ; } +} + +void SpacebrewYun::monitor() { + while (Console.available() > 0) { + 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); + Serial.print(F("Application name set to: ")); + Serial.println(name); + } + if (_onOpen != NULL){ + _onOpen(); + } + } + else if (c == char(CONNECTION_END) && _connected) { + _connected = false; + if (_verbose) { + Serial.print(F("Disconnected from spacebrew server at: ")); + Serial.println(server); + } + if (_onClose != NULL){ + _onClose(); + } + } + + if (_verbose) { + if (c == char(CONNECTION_ERROR)) { + _error_msg = true; + Serial.println(F("ERROR :: with Spacebrew.py Connection ::")); + } + else if (_error_msg && c == char(MSG_END)) { + _error_msg = false; + Serial.println(); + } + if (_error_msg) { + Serial.print(c); + } + } + + if (_connected) { + if (c == char(MSG_START)) { + read_name = true; + } 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 (read_name == true) { + sub_name += c; + } else if (read_msg == true) { + sub_msg += c; + } + else if (_verbose) { + Serial.print(c); + } + } + } + } +} + +boolean SpacebrewYun::connected() { + return SpacebrewYun::_connected; +} + +void SpacebrewYun::verbose(boolean verbose = true) { + _verbose = verbose; +} + +void SpacebrewYun::onMessage() { + if (subscribers != NULL) { + 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; + } + } + + if ( sub_type.equals("range") ) { + if (_onRangeMessage != NULL) { + _onRangeMessage( sub_name, int(sub_msg.toInt()) ); + } else { + Serial.println(F("ERROR :: Range message received, no callback method is registered")); + } + } else if ( sub_type.equals("boolean") ) { + if (_onBooleanMessage != NULL) { + _onBooleanMessage( sub_name, ( sub_msg.equals("false") ? false : true ) ); + } else { + Serial.println(F("ERROR :: Boolean message received, no callback method is registered")); + } + } else if ( sub_type.equals("string") ) { + if (_onStringMessage != NULL) { + _onStringMessage( sub_name, sub_msg ); + } else { + Serial.println(F("ERROR :: String message received, no callback method is registered")); + } + } else { + if (_onCustomMessage != NULL) { + _onCustomMessage( sub_name, sub_msg, sub_type ); + } else { + Serial.println(F("ERROR :: Custom message received, no callback method is registered")); + } + } + + sub_name = ""; + sub_msg = ""; + sub_type = ""; +} + + +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(); + + true; +} + + +/** + * method that gets the pid of all spacebrew.py instances running on the linino. + */ +void SpacebrewYun::getPids() { + + // request the pid of all python processes + pids.begin("python"); + pids.addParameter("/usr/lib/python2.7/spacebrew/getProcPid.py"); // Process should launch the "curl" command + pids.run(); + + if (_verbose) { + Serial.println(F("Checking if spacebrew process already running")); + } + + int sbPidsIndex = 0; + int pidCharIndex = 0; + char c = '\0'; + + while ( pids.available() > 0 ) { + + c = pids.read(); + + if ( c >= '0' && c <= '9' ) { + pid[pidCharIndex] = c; + pidCharIndex = (pidCharIndex + 1) % pidLength; + } + + else if ( (c == ' ' || c == '\n') && pidCharIndex > 0) { + sbPids[sbPidsIndex] = atoi(pid); + if ( sbPidsIndex < (sbPidsLen - 1) ) sbPidsIndex = (sbPidsIndex + 1); + + for( int i = 0; i < pidLength; i++ ){ + pid[i] = '\0'; + pidCharIndex = 0; + } + } + } +} + +/** + * method that kills all of the spacebrew.py instances that are running + * on the linino. + */ +void SpacebrewYun::killPids() { + getPids(); + delay(400); + + for (int i = 0; i < sbPidsLen; i ++) { + if (sbPids[i] > 0) { + char * newPID = itoa(sbPids[i], pid, 10); + + if (_verbose) { + Serial.print(F("Stopping existing spacebrew processes with pids: ")); + Serial.println(newPID); + } + + Process p; + p.begin("kill"); + p.addParameter("-9"); + p.addParameter(newPID); // Process should launch the "curl" command + p.run(); // Run the process and wait for its termination + + delay(400); + } + } +} + + diff --git a/libraries/SpacebrewYun/SpacebrewYun.h b/libraries/SpacebrewYun/SpacebrewYun.h new file mode 100644 index 0000000..8fd7bd2 --- /dev/null +++ b/libraries/SpacebrewYun/SpacebrewYun.h @@ -0,0 +1,122 @@ + +#ifndef YUNSPACEBREW_H +#define YUNSPACEBREW_H + +#include "Arduino.h" +#include +#include +#include + +enum SBmsg { + CONNECTION_START = char(28), + CONNECTION_END = char(27), + CONNECTION_ERROR = char(26), + MSG_START = char(29), + MSG_DIV = char(30), + MSG_END = char(31) +}; + +struct Publisher { + char *name; + char *type; + char *defaultValue; + Publisher * next; +}; + +struct Subscriber{ + char *name; + char *type; + Subscriber * next; +}; + +int const pidLength = 6; +int const sbPidsLen = 4; + +class SpacebrewYun { + + public: + + SpacebrewYun(const String&, const String&); + void addPublish(const String&, const String&); + void addSubscribe(const String&, const String&); + + void connect(String, int); + void connect() { connect(server, port); }; + void connect(String _server) { connect(String(_server), port); }; + + void monitor(); + void onMessage(); + + 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, 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)); }; + + void verbose(boolean); + + typedef void (*OnBooleanMessage)(String name, boolean value); + typedef void (*OnRangeMessage)(String name, int value); + typedef void (*OnStringMessage)(String name, String value); + typedef void (*OnCustomMessage)(String name, String value, String type); + typedef void (*OnSBOpen)(); + typedef void (*OnSBClose)(); + typedef void (*OnSBError)(int code, String message); + + void onOpen(OnSBOpen function); + void onClose(OnSBClose function); + void onRangeMessage(OnRangeMessage function); + void onStringMessage(OnStringMessage function); + void onBooleanMessage(OnBooleanMessage function); + void onCustomMessage(OnCustomMessage function); + void onError(OnSBError function); + + private: + + Process brew; + String name; + String server; + String description; + boolean _connected; + boolean _error_msg; + boolean _verbose; + int port; + + /**Output should be at least 5 cells**/ + static OnBooleanMessage _onBooleanMessage; + static OnRangeMessage _onRangeMessage; + static OnStringMessage _onStringMessage; + static OnCustomMessage _onCustomMessage; + static OnSBOpen _onOpen; + static OnSBClose _onClose; + static OnSBError _onError; + + Subscriber * subscribers; + Publisher * publishers; + String sub_name; + String sub_msg; + String sub_type; + + boolean read_name; + boolean read_msg; + int sub_name_max; + int sub_msg_max; + + Process pids; + char pid [6]; + int sbPids [4]; + + void killPids(); + void getPids(); + + static char * createString(int len){ + char * out = ( char * )malloc( len + 1 ); + return out; + } + +}; + +#endif diff --git a/libraries/SpacebrewYun/keywords.txt b/libraries/SpacebrewYun/keywords.txt new file mode 100644 index 0000000..4494c2b --- /dev/null +++ b/libraries/SpacebrewYun/keywords.txt @@ -0,0 +1,15 @@ +SpacebrewYun KEYWORD1 +addPublish KEYWORD2 +addSubscribe KEYWORD2 +connect KEYWORD2 +verbose KEYWORD2 +monitor KEYWORD2 +onMessage KEYWORD2 +send KEYWORD2 +onRangeMessage KEYWORD2 +onStringMessage KEYWORD2 +onBooleanMessage KEYWORD2 +onCustomMessage KEYWORD2 +onOpen KEYWORD2 +onClose KEYWORD2 +onError KEYWORD2 \ No newline at end of file