diff --git a/libraries/Temboo/extras/readme.txt b/libraries/Temboo/extras/readme.txt new file mode 100644 index 000000000..cb8b49718 --- /dev/null +++ b/libraries/Temboo/extras/readme.txt @@ -0,0 +1,31 @@ +Temboo Library for Arduino + +Installation +------------ + +For installation instructions, please visit: + +http://temboo.com/arduino/others/library-installation + +Examples, Tutorials & More +-------------------------- + +You can find lots of examples, tutorials and info about Device Coder (Temboo's tool for automatically generating internet-connected sketch code) at the link below: + +http://temboo.com/arduino/ + +Compatibility +------------- + +This library has been tested with the following Arduino boards: + +* TRE +* Yún +* Due +* Mega +* Uno + +And the following internet shields: + +* Arduino Wifi Shield +* Arduino Ethernet Shield diff --git a/libraries/Temboo/keywords.txt b/libraries/Temboo/keywords.txt index 53af447af..f4565ea31 100644 --- a/libraries/Temboo/keywords.txt +++ b/libraries/Temboo/keywords.txt @@ -24,6 +24,7 @@ setAppKeyName KEYWORD2 setAppKey KEYWORD2 setChoreo KEYWORD2 setCredential KEYWORD2 +setSavedInputs KEYWORD2 addInput KEYWORD2 addOutputFilter KEYWORD2 setSettingsFileToWrite KEYWORD2 diff --git a/libraries/Temboo/library.properties b/libraries/Temboo/library.properties index adb2bc712..4db0feb4c 100644 --- a/libraries/Temboo/library.properties +++ b/libraries/Temboo/library.properties @@ -1,10 +1,9 @@ name=Temboo author=Temboo email=support@temboo.com -sentence=Allows any Arduino with Internet access to connect to web-based resources and services APIs. -paragraph=Temboo is a platform that provides normalized access to 100+ APIs, databases, code utilities and more. This library enables the Yún to connect to Temboo, making it simple to interact with a vast array of web-based resources and services. -url=http://www.temboo.com -architectures=avr -version=1.0 -dependencies= -core-dependencies=arduino (>=1.5.0) +sentence=This library enables calls to Temboo, a platform that connects Arduino boards to 100+ APIs, databases, code utilities and more. +paragraph=Use this library to connect your Arduino board to Temboo, making it simple to interact with a vast array of web-based resources and services. +url=http://www.temboo.com/arduino +architectures=* +version=1.1 +core-dependencies=arduino (>=1.5.0) \ No newline at end of file diff --git a/libraries/Temboo/src/Temboo.cpp b/libraries/Temboo/src/Temboo.cpp index b4a276aac..f7ddaf93e 100644 --- a/libraries/Temboo/src/Temboo.cpp +++ b/libraries/Temboo/src/Temboo.cpp @@ -1,9 +1,9 @@ /* ############################################################################### # -# Temboo Arduino Yún library +# Temboo Arduino library # -# Copyright 2013, Temboo Inc. +# Copyright 2014, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,6 +20,13 @@ ############################################################################### */ + +#if defined (ARDUINO_AVR_YUN) || defined (ARDUINO_AVR_TRE) + +/////////////////////////////////////////////////////// +// BEGIN ARDUINO YUN AND TRE SUPPORT +/////////////////////////////////////////////////////// + #include void TembooChoreo::begin() { @@ -46,6 +53,14 @@ void TembooChoreo::setCredential(const String& credentialName) { addParameter("-e" + credentialName); } +void TembooChoreo::setSavedInputs(const String& savedInputsName) { + addParameter("-e" + savedInputsName); +} + +void TembooChoreo::setProfile(const String& profileName) { + addParameter("-e" + profileName); +} + void TembooChoreo::addInput(const String& inputName, const String& inputValue) { addParameter("-i" + inputName + ":" + inputValue); } @@ -62,3 +77,319 @@ void TembooChoreo::setSettingsFileToRead(const String& filePath) { addParameter("-r" + filePath); } + +#else //ARDUINO_AVR_YUN + +/////////////////////////////////////////////////////// +// BEGIN ARDUINO NON-YUN SUPPORT +/////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "utility/TembooGlobal.h" +#include "utility/TembooSession.h" + +static const char HTTP_CODE[] PROGMEM = "HTTP_CODE\x0A\x1F"; + +TembooChoreo::TembooChoreo(Client& client) : m_client(client) { + m_accountName = NULL; + m_appKeyName = NULL; + m_appKeyValue = NULL; + m_path = NULL; + m_nextChar = NULL; + m_nextState = END; +} + +void TembooChoreo::setAccountName(const String& accountName) { + m_accountName = accountName.c_str(); +} + + +void TembooChoreo::setAccountName(const char* accountName) { + m_accountName = accountName; +} + + +void TembooChoreo::setAppKeyName(const String& appKeyName) { + m_appKeyName = appKeyName.c_str(); +} + + +void TembooChoreo::setAppKeyName(const char* appKeyName) { + m_appKeyName = appKeyName; +} + + +void TembooChoreo::setAppKey(const String& appKeyValue) { + m_appKeyValue = appKeyValue.c_str(); +} + + +void TembooChoreo::setAppKey(const char* appKeyValue) { + m_appKeyValue = appKeyValue; +} + + +void TembooChoreo::setChoreo(const String& path) { + m_path = path.c_str(); +} + + +void TembooChoreo::setChoreo(const char* path) { + m_path = path; +} + + +void TembooChoreo::setSavedInputs(const String& savedInputsName) { + m_preset.put(savedInputsName.c_str()); +} + + +void TembooChoreo::setSavedInputs(const char* savedInputsName) { + m_preset.put(savedInputsName); +} + + +void TembooChoreo::setCredential(const String& credentialName) { + m_preset.put(credentialName.c_str()); +} + + +void TembooChoreo::setCredential(const char* credentialName) { + m_preset.put(credentialName); +} + +void TembooChoreo::setProfile(const String& profileName) { + m_preset.put(profileName.c_str()); +} + + +void TembooChoreo::setProfile(const char* profileName) { + m_preset.put(profileName); +} + + + +void TembooChoreo::addInput(const String& inputName, const String& inputValue) { + m_inputs.put(inputName.c_str(), inputValue.c_str()); +} + + +void TembooChoreo::addInput(const char* inputName, const char* inputValue) { + m_inputs.put(inputName, inputValue); +} + + +void TembooChoreo::addInput(const char* inputName, const String& inputValue) { + m_inputs.put(inputName, inputValue.c_str()); +} + + +void TembooChoreo::addInput(const String& inputName, const char* inputValue) { + m_inputs.put(inputName.c_str(), inputValue); +} + + +void TembooChoreo::addOutputFilter(const char* outputName, const char* filterPath, const char* variableName) { + m_outputs.put(outputName, filterPath, variableName); +} + + +void TembooChoreo::addOutputFilter(const String& outputName, const char* filterPath, const char* variableName) { + m_outputs.put(outputName.c_str(), filterPath, variableName); +} + + +void TembooChoreo::addOutputFilter(const char* outputName, const String& filterPath, const char* variableName) { + m_outputs.put(outputName, filterPath.c_str(), variableName); +} + + +void TembooChoreo::addOutputFilter(const String& outputName, const String& filterPath, const char* variableName) { + m_outputs.put(outputName.c_str(), filterPath.c_str(), variableName); +} + + +void TembooChoreo::addOutputFilter(const char* outputName, const char* filterPath, const String& variableName) { + m_outputs.put(outputName, filterPath, variableName.c_str()); +} + + +void TembooChoreo::addOutputFilter(const String& outputName, const char* filterPath, const String& variableName) { + m_outputs.put(outputName.c_str(), filterPath, variableName.c_str()); +} + + +void TembooChoreo::addOutputFilter(const char* outputName, const String& filterPath, const String& variableName) { + m_outputs.put(outputName, filterPath.c_str(), variableName.c_str()); +} + + +void TembooChoreo::addOutputFilter(const String& outputName, const String& filterPath, const String& variableName) { + m_outputs.put(outputName.c_str(), filterPath.c_str(), variableName.c_str()); +} + + +int TembooChoreo::run() { + return run(INADDR_NONE, 80); +} + + +int TembooChoreo::run(IPAddress addr, uint16_t port) { + + m_nextChar = NULL; + + if (m_accountName == NULL || *m_accountName == '\0') { + return TEMBOO_ERROR_ACCOUNT_MISSING; + } + + if (m_path == NULL || *m_path == '\0') { + return TEMBOO_ERROR_CHOREO_MISSING; + } + + if (m_appKeyName == NULL || *m_appKeyName == '\0') { + return TEMBOO_ERROR_APPKEY_NAME_MISSING; + } + + if (m_appKeyValue == NULL || *m_appKeyValue == '\0') { + return TEMBOO_ERROR_APPKEY_MISSING; + } + + + TembooSession session(m_client, addr, port); + uint16_t httpCode = 0; + + for (int i = 0; i < 2; i++) { + if (0 != session.executeChoreo(m_accountName, m_appKeyName, m_appKeyValue, m_path, m_inputs, m_outputs, m_preset)) { + httpCode = 0; + break; + } + + while(!m_client.available()) { + if (!m_client.connected()) { + TEMBOO_TRACELN("Disconnected"); + return TEMBOO_ERROR_HTTP_ERROR; + } + delay(10); + } + + if (!m_client.find("HTTP/1.1 ")) { + TEMBOO_TRACELN("No HTTP"); + return TEMBOO_ERROR_HTTP_ERROR; + } + + httpCode = (uint16_t)m_client.parseInt(); + + // We expect HTTP response codes to be <= 599, but + // we need to be prepared for anything. + if (httpCode >= 600) { + TEMBOO_TRACELN("Invalid HTTP"); + httpCode = 0; + } + + // if we get an auth error AND there was an x-temboo-time header, + // update the session timeOffset + if ((httpCode == 401) && (i == 0)) { + if (m_client.find("x-temboo-time:")) { + TembooSession::setTime((unsigned long)m_client.parseInt()); + while(m_client.available()) { + m_client.read(); + } + m_client.stop(); + } + } else { + break; + } + } + + uint16toa(httpCode, m_httpCodeStr); + strcat_P(m_httpCodeStr, PSTR("\x0A\x1E")); + m_nextState = START; + m_nextChar = HTTP_CODE; + + if (httpCode < 200 || httpCode >= 300) { + return TEMBOO_ERROR_HTTP_ERROR; + } + + if (!m_client.find("\x0D\x0A\x0D\x0A")) { + return TEMBOO_ERROR_HTTP_ERROR; + } + + return TEMBOO_ERROR_OK; +} + +void TembooChoreo::close() { + m_client.stop(); +} + +int TembooChoreo::available() { + // If we're still sending the HTTP response code, + // report at least one character available. + if (m_nextChar != NULL) { + return m_client.available() + 1; + } + + // Otherwise, return however many characters the client has. + return m_client.available(); +} + + +int TembooChoreo::peek() { + // If we're still sending the HTTP response code, + // return the next character in that sequence. + if (m_nextChar != NULL) { + return (int)*m_nextChar; + } + + // Otherwise, return whatever is in the client buffer. + return m_client.peek(); +} + + +int TembooChoreo::read() { + + int c = 0; + switch(m_nextState) { + case START: + m_nextChar = HTTP_CODE; + c = (int)pgm_read_byte(m_nextChar++); + m_nextState = HTTP_CODE_TAG; + break; + + case HTTP_CODE_TAG: + c = (int)pgm_read_byte(m_nextChar++); + if (pgm_read_byte(m_nextChar) == '\0') { + m_nextState = HTTP_CODE_VALUE; + m_nextChar = m_httpCodeStr; + } + break; + + case HTTP_CODE_VALUE: + c = (int)(*m_nextChar++); + if (*m_nextChar == '\0') { + m_nextState = END; + m_nextChar = NULL; + } + break; + + default: + c = m_client.read(); + } + return c; +} + + +size_t TembooChoreo::write(uint8_t data) { + return m_client.write(data); +} + + +void TembooChoreo::flush() { + m_nextChar = NULL; + m_nextState = END; + m_client.flush(); +} + +#endif //ARDUINO_AVR_YUN diff --git a/libraries/Temboo/src/Temboo.h b/libraries/Temboo/src/Temboo.h index 9656fdb6f..3b1b7ec40 100644 --- a/libraries/Temboo/src/Temboo.h +++ b/libraries/Temboo/src/Temboo.h @@ -1,9 +1,9 @@ /* ############################################################################### # -# Temboo Arduino Yún library +# Temboo Arduino library # -# Copyright 2013, Temboo Inc. +# Copyright 2014, Temboo Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,9 +20,16 @@ ############################################################################### */ -#ifndef _TEMBOO_H -#define _TEMBOO_H +#ifndef TEMBOO_H_ +#define TEMBOO_H_ + #include + +#if defined (ARDUINO_AVR_YUN) || defined (ARDUINO_AVR_TRE) +/////////////////////////////////////////////////////// +// BEGIN ARDUINO YUN AND TRE SUPPORT +/////////////////////////////////////////////////////// + #include class TembooChoreo : public Process { @@ -34,6 +41,8 @@ class TembooChoreo : public Process { void setAppKey(const String& appKey); void setChoreo(const String& choreo); void setCredential(const String& credentialName); + void setSavedInputs(const String& saveInputsName); + void setProfile(const String& profileName); void addInput(const String& inputName, const String& inputValue); void addOutputFilter(const String& filterName, const String& filterPath, const String& variableName); void setSettingsFileToWrite(const String& filePath); @@ -41,4 +50,122 @@ class TembooChoreo : public Process { }; -#endif +#else //ARDUINO_AVR_YUN + +/////////////////////////////////////////////////////// +// BEGIN ARDUINO NON-YUN SUPPORT +/////////////////////////////////////////////////////// + +#include +#include +#include +#include "utility/ChoreoInputSet.h" +#include "utility/ChoreoOutputSet.h" +#include "utility/ChoreoPreset.h" + +#define TEMBOO_ERROR_OK (0) +#define TEMBOO_ERROR_ACCOUNT_MISSING (201) +#define TEMBOO_ERROR_CHOREO_MISSING (203) +#define TEMBOO_ERROR_APPKEY_NAME_MISSING (205) +#define TEMBOO_ERROR_APPKEY_MISSING (207) +#define TEMBOO_ERROR_HTTP_ERROR (223) + +class TembooChoreo : public Stream { + public: + + // Constructor. + // client - an instance of an Arduino Client, usually an EthernetClient + // or a WiFiClient. Used to communicate with Temboo. + TembooChoreo(Client& client); + + // Does nothing. Just for source compatibility with Yun code. + void begin() {}; + + // Sets the account name to use when communicating with Temboo. + // (required) + void setAccountName(const String& accountName); + void setAccountName(const char* accountName); + + // Sets the application key name to use with choreo execution requests. + // (required) + void setAppKeyName(const String& appKeyName); + void setAppKeyName(const char* appKeyName); + + // Sets the application key value to use with choreo execution requests + // (required) + void setAppKey(const String& appKey); + void setAppKey(const char* appKey); + + // sets the name of the choreo to be executed. + // (required) + void setChoreo(const String& choreoPath); + void setChoreo(const char* choreoPath); + + // sets the name of the saved inputs to use when executing the choreo + // (optional) + void setSavedInputs(const String& savedInputsName); + void setSavedInputs(const char* savedInputsName); + + void setCredential(const String& credentialName); + void setCredential(const char* credentialName); + + void setProfile(const String& profileName); + void setProfile(const char* profileName); + + // sets an input to be used when executing a choreo. + // (optional or required, depending on the choreo being executed.) + void addInput(const String& inputName, const String& inputValue); + void addInput(const char* inputName, const char* inputValue); + void addInput(const char* inputName, const String& inputValue); + void addInput(const String& inputName, const char* inputValue); + + // sets an output filter to be used to process the choreo output + // (optional) + void addOutputFilter(const char* filterName, const char* filterPath, const char* variableName); + void addOutputFilter(const String& filterName, const char* filterPath, const char* variableName); + void addOutputFilter(const char* filterName, const String& filterPath, const char* variableName); + void addOutputFilter(const String& filterName, const String& filterPath, const char* variableName); + void addOutputFilter(const char* filterName, const char* filterPath, const String& variableName); + void addOutputFilter(const String& filterName, const char* filterPath, const String& variableName); + void addOutputFilter(const char* filterName, const String& filterPath, const String& variableName); + void addOutputFilter(const String& filterName, const String& filterPath, const String& variableName); + + // run the choreo using the current input info + int run(); + + // run the choreo on the Temboo server at the given IP address and port + // (used only when instructed by Temboo customer support.) + int run(IPAddress addr, uint16_t port); + + void close(); + + // Stream interface - see the Arduino library documentation. + int available(); + int read(); + int peek(); + void flush(); + + //Print interface - see the Arduino library documentation + size_t write(uint8_t data); + + + protected: + ChoreoInputSet m_inputs; + ChoreoOutputSet m_outputs; + ChoreoPreset m_preset; + + const char* m_accountName; + const char* m_appKeyValue; + const char* m_appKeyName; + const char* m_path; + Client& m_client; + char m_httpCodeStr[6]; + const char* m_nextChar; + enum State {START, HTTP_CODE_TAG, HTTP_CODE_VALUE, END}; + State m_nextState; + +}; + +#endif //ARDUINO_AVR_YUN + +#endif //TEMBOO_H_ diff --git a/libraries/Temboo/src/utility/BaseFormatter.cpp b/libraries/Temboo/src/utility/BaseFormatter.cpp new file mode 100644 index 000000000..b9b77db67 --- /dev/null +++ b/libraries/Temboo/src/utility/BaseFormatter.cpp @@ -0,0 +1,96 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#include "BaseFormatter.h" + +char BaseFormatter::escape(char c) { + char outChar = c; + switch(c) { + case '\\': + case '"': + outChar = '\\'; + m_escapedChar = c; + break; + case '\b': + outChar = '\\'; + m_escapedChar = 'b'; + break; + case '\f': + outChar = '\\'; + m_escapedChar = 'f'; + break; + case '\n': + outChar = '\\'; + m_escapedChar = 'n'; + break; + case '\r': + outChar = '\\'; + m_escapedChar = 'r'; + break; + case '\t': + outChar = '\\'; + m_escapedChar = 't'; + break; + default: + m_escapedChar = '\0'; + } + return outChar; +} + +char BaseFormatter::finishEscape() { + char c = m_escapedChar; + m_escapedChar = '\0'; + return c; +} + +char BaseFormatter::readTagChar(int nextState) { + char c = pgm_read_byte(m_nextChar++); + if (pgm_read_byte(m_nextChar) == '\0') { + m_nextState = nextState; + } + return c; +} + +char BaseFormatter::readValueChar(int nextState) { + char c; + if (isEscaping()) { + c = finishEscape(); + if (*m_nextChar == '\0') { + m_nextState = nextState; + } + } else { + c = escape(*m_nextChar++); + if (!isEscaping()) { + if(*m_nextChar == '\0') { + m_nextState = nextState; + } + } + } + return c; +} + +char BaseFormatter::readStartTagChar(const char* tag, int nextState) { + m_nextChar = tag; + char c = pgm_read_byte(m_nextChar++); + m_nextState = nextState; + return c; +} diff --git a/libraries/Temboo/src/utility/BaseFormatter.h b/libraries/Temboo/src/utility/BaseFormatter.h new file mode 100644 index 000000000..d8886ad13 --- /dev/null +++ b/libraries/Temboo/src/utility/BaseFormatter.h @@ -0,0 +1,46 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#ifndef BASEFORMATTER_H_ +#define BASEFORMATTER_H_ +#include "TembooGlobal.h" + +class BaseFormatter { + public: + BaseFormatter() {m_escapedChar = '\0';} + + protected: + const char* m_nextChar; + int m_nextState; + char m_escapedChar; + + char escape(char c); + bool isEscaping() {return m_escapedChar != '\0';} + char finishEscape(); + + char readTagChar(int nextState); + char readValueChar(int nextState); + char readStartTagChar(const char* tag, int nextState); + +}; + +#endif diff --git a/libraries/Temboo/src/utility/ChoreoInput.cpp b/libraries/Temboo/src/utility/ChoreoInput.cpp new file mode 100644 index 000000000..00138b7a3 --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoInput.cpp @@ -0,0 +1,34 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#include +#include "ChoreoInput.h" + +ChoreoInput::ChoreoInput(ChoreoInput* prev, const char* name, const char* value) { + if (prev != NULL) { + prev->m_next = this; + } + m_next = NULL; + m_name = name; + m_value = value; +} + diff --git a/libraries/Temboo/src/utility/ChoreoInput.h b/libraries/Temboo/src/utility/ChoreoInput.h new file mode 100644 index 000000000..3e2b8b83a --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoInput.h @@ -0,0 +1,41 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#ifndef CHOREOINPUT_H_ +#define CHOREOINPUT_H_ +#include "TembooGlobal.h" +class ChoreoInput { + public: + ChoreoInput(ChoreoInput* prev, const char* name, const char* value); + const char* getName() const {return m_name;} + const char* getValue() const {return m_value;} + void setValue(const char* value) {m_value = value;} + ChoreoInput* getNext() const {return m_next;} + + private: + ChoreoInput* m_next; + const char* m_name; + const char* m_value; +}; + +#endif + diff --git a/libraries/Temboo/src/utility/ChoreoInputFormatter.cpp b/libraries/Temboo/src/utility/ChoreoInputFormatter.cpp new file mode 100644 index 000000000..e70bd8aab --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoInputFormatter.cpp @@ -0,0 +1,125 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#include +#include +#include "ChoreoInputFormatter.h" +#include "ChoreoInputSet.h" + +static const char TAG_INPUTS_START[] PROGMEM = "\"inputs\":{"; + +ChoreoInputFormatter::ChoreoInputFormatter(const ChoreoInputSet* inputSet) { + m_inputSet = inputSet; + reset(); +} + +void ChoreoInputFormatter::reset() { + m_currentInput = NULL; + m_nextChar = NULL; + if (m_inputSet == NULL || m_inputSet->isEmpty()) { + m_nextState = END; + } else { + m_nextState = START; + } +} + +bool ChoreoInputFormatter::hasNext() { + return m_nextState != END; +} + +char ChoreoInputFormatter::next() { + char c; + switch(m_nextState) { + case START: + c = readStartTagChar(TAG_INPUTS_START, INPUTS_TAG); + break; + + case INPUTS_TAG: + c = readTagChar(NAME_START); + if (m_nextState == NAME_START) { + m_currentInput= m_inputSet->getFirstInput(); + } + break; + + case NAME_START: + c = '"'; + m_nextChar = m_currentInput->getName(); + if ((NULL == m_nextChar) || ('\0' == *m_nextChar)) { + m_nextState = NAME_END; + } else { + m_nextState = NAME; + } + break; + + case NAME: + c = readValueChar(NAME_END); + break; + + case NAME_END: + c = '"'; + m_nextState = NAME_VALUE_SEPARATOR; + break; + + case NAME_VALUE_SEPARATOR: + c = ':'; + m_nextState = VALUE_START; + break; + + case VALUE_START: + c = '"'; + m_nextChar = m_currentInput->getValue(); + if ((NULL == m_nextChar) || ('\0' == *m_nextChar)) { + m_nextState = VALUE_END; + } else { + m_nextState = VALUE; + } + break; + + case VALUE: + c = readValueChar(VALUE_END); + break; + + case VALUE_END: + c = '"'; + m_currentInput = m_currentInput->getNext(); + if (m_currentInput != NULL) { + m_nextState = NEXT_INPUT; + } else { + m_nextState = INPUTS_END; + } + break; + case NEXT_INPUT: + c = ','; + m_nextChar = m_currentInput->getName(); + m_nextState = NAME_START; + break; + + case INPUTS_END: + c = '}'; + m_nextState = END; + break; + case END: + default: + c = '\0'; + } + return c; +} diff --git a/libraries/Temboo/src/utility/ChoreoInputFormatter.h b/libraries/Temboo/src/utility/ChoreoInputFormatter.h new file mode 100644 index 000000000..78b2f9776 --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoInputFormatter.h @@ -0,0 +1,58 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#ifndef CHOREOINPUTFORMATTER_H_ +#define CHOREOINPUTFORMATTER_H_ +#include "TembooGlobal.h" +#include "BaseFormatter.h" +#include "ChoreoInputSet.h" + +class ChoreoInputFormatter : public BaseFormatter { + + public: + ChoreoInputFormatter(const ChoreoInputSet* inputSet); + bool hasNext(); + char next(); + void reset(); + + protected: + const ChoreoInputSet* m_inputSet; + const ChoreoInput* m_currentInput; + + + enum State { + START, + INPUTS_TAG, + NAME_START, + NAME, + NAME_END, + NAME_VALUE_SEPARATOR, + VALUE_START, + VALUE, + VALUE_END, + NEXT_INPUT, + INPUTS_END, + END + }; +}; + +#endif diff --git a/libraries/Temboo/src/utility/ChoreoInputSet.cpp b/libraries/Temboo/src/utility/ChoreoInputSet.cpp new file mode 100644 index 000000000..5257a1695 --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoInputSet.cpp @@ -0,0 +1,80 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#include +#include "ChoreoInputSet.h" + +ChoreoInputSet::ChoreoInputSet() { + m_first = NULL; +} + +ChoreoInputSet::~ChoreoInputSet() { + ChoreoInput* i = m_first; + ChoreoInput* next = NULL; + while (i != NULL) { + next = i->getNext(); + delete i; + i = next; + } +} + +void ChoreoInputSet::put(const char* name, const char* value) { + + // Haven't set ANY inputs yet? + // Just create a new one. + if (m_first == NULL) { + m_first = new ChoreoInput(NULL, name, value); + } else { + // Some inputs already set. + // See if we already have this input. + ChoreoInput* last = NULL; + ChoreoInput* i = m_first; + while(i != NULL) { + if (strcmp(i->getName(), name) == 0) { + // We already have an input with this name. + // Just update the value. + i->setValue(value); + break; + } + last = i; + i = i->getNext(); + } + + // We don't have an input with this name + // So we need to create a new one. + if (i == NULL) { + new ChoreoInput(last, name, value); + } + } +} + +const char* ChoreoInputSet::get(const char* name) const { + ChoreoInput* i = m_first; + while(i != NULL) { + if (strcmp(i->getName(), name) == 0) { + return i->getValue(); + } + i = i->getNext(); + } + return NULL; +} + diff --git a/libraries/Temboo/src/utility/ChoreoInputSet.h b/libraries/Temboo/src/utility/ChoreoInputSet.h new file mode 100644 index 000000000..4349049c5 --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoInputSet.h @@ -0,0 +1,43 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#ifndef CHOREOINPUTSET_H_ +#define CHOREOINPUTSET_H_ +#include +#include "TembooGlobal.h" +#include "ChoreoInput.h" + +class ChoreoInputSet { + + public: + ChoreoInputSet(); + ~ChoreoInputSet(); + void put(const char* name, const char* value); + const char* get(const char* name) const; + bool isEmpty() const {return m_first == NULL;} + const ChoreoInput* getFirstInput() const {return m_first;} + + protected: + ChoreoInput* m_first; +}; + +#endif diff --git a/libraries/Temboo/src/utility/ChoreoOutput.cpp b/libraries/Temboo/src/utility/ChoreoOutput.cpp new file mode 100644 index 000000000..63ede6bf5 --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoOutput.cpp @@ -0,0 +1,37 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#include +#include "ChoreoOutput.h" + + +ChoreoOutput::ChoreoOutput(ChoreoOutput* prev, const char* name, const char* path, const char* var) { + if (prev != NULL) { + prev->m_next = this; + } + m_next = NULL; + m_name = name; + m_path = path; + m_var = var; +} + + diff --git a/libraries/Temboo/src/utility/ChoreoOutput.h b/libraries/Temboo/src/utility/ChoreoOutput.h new file mode 100644 index 000000000..a026d955d --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoOutput.h @@ -0,0 +1,44 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#ifndef CHOREOOUTPUT_H_ +#define CHOREOOUTPUT_H_ +#include "TembooGlobal.h" + +class ChoreoOutput { + public: + ChoreoOutput(ChoreoOutput* prev, const char* name, const char* path, const char* var); + const char* getName() const {return m_name;} + const char* getPath() const {return m_path;} + const char* getVariable() const {return m_var;} + void setPath(const char* path) {m_path = path;} + void setVariable(const char* variable) {m_var = variable;} + ChoreoOutput* getNext() const {return m_next;} + + private: + ChoreoOutput* m_next; + const char* m_name; + const char* m_path; + const char* m_var; +}; + +#endif diff --git a/libraries/Temboo/src/utility/ChoreoOutputFormatter.cpp b/libraries/Temboo/src/utility/ChoreoOutputFormatter.cpp new file mode 100644 index 000000000..a4b581bb1 --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoOutputFormatter.cpp @@ -0,0 +1,181 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#include +#include +#include "ChoreoOutputFormatter.h" +#include "ChoreoOutputSet.h" + +static const char TAG_OUTPUTS_START[] PROGMEM = "\"outputs\":["; +static const char TAG_NAME[] PROGMEM = "\"name\":"; +static const char TAG_PATH[] PROGMEM = "\"path\":"; +static const char TAG_VAR[] PROGMEM = "\"variable\":"; + + +ChoreoOutputFormatter::ChoreoOutputFormatter(const ChoreoOutputSet* outputSet) { + m_outputSet = outputSet; + reset(); +} + +void ChoreoOutputFormatter::reset() { + m_currentOutput = NULL; + m_nextChar = NULL; + if (m_outputSet == NULL || m_outputSet->isEmpty()) { + m_nextState = END; + } else { + m_nextState = START; + } +} + +bool ChoreoOutputFormatter::hasNext() { + return m_nextState != END; +} + +char ChoreoOutputFormatter::next() { + char c = '\0'; + switch(m_nextState) { + case START: + c = readStartTagChar(TAG_OUTPUTS_START, OUTPUTS_TAG); + break; + + case OUTPUTS_TAG: + c = readTagChar(OUTPUT_START); + if (m_nextState == OUTPUT_START) { + m_currentOutput = m_outputSet->getFirstOutput(); + } + break; + + case OUTPUT_START: + c = '{'; + m_nextChar = TAG_NAME; + m_nextState = NAME_TAG; + break; + + case NAME_TAG: + c = readTagChar(NAME_START); + break; + + case NAME_START: + c = '"'; + m_nextChar = m_currentOutput->getName(); + if ((NULL == m_nextChar) || ('\0' == *m_nextChar)) { + m_nextState = NAME_END; + } else { + m_nextState = NAME; + } + break; + + case NAME: + c = readValueChar(NAME_END); + break; + + case NAME_END: + c = '"'; + m_nextState = NAME_PATH_SEPARATOR; + break; + + case NAME_PATH_SEPARATOR: + c = ','; + m_nextState = PATH_TAG; + m_nextChar = TAG_PATH; + break; + + case PATH_TAG: + c = readTagChar(PATH_START); + break; + + case PATH_START: + c = '"'; + m_nextChar = m_currentOutput->getPath(); + if ((NULL == m_nextChar) || ('\0' == *m_nextChar)) { + m_nextState = PATH_END; + } else { + m_nextState = PATH; + } + break; + + case PATH: + c = readValueChar(PATH_END); + break; + + case PATH_END: + c = '"'; + m_nextState = PATH_VAR_SEPARATOR; + break; + + case PATH_VAR_SEPARATOR: + c = ','; + m_nextState = VAR_TAG; + m_nextChar = TAG_VAR; + break; + + case VAR_TAG: + c = readTagChar(VAR_START); + break; + + case VAR_START: + c = '"'; + m_nextChar = m_currentOutput->getVariable(); + if ((NULL == m_nextChar) || ('\0' == *m_nextChar)) { + m_nextState = VAR_END; + } else { + m_nextState = VAR; + } + break; + + case VAR: + c = readValueChar(VAR_END); + break; + + case VAR_END: + c = '"'; + m_nextState = OUTPUT_END; + break; + + case OUTPUT_END: + c = '}'; + m_currentOutput = m_currentOutput->getNext(); + if (m_currentOutput != NULL) { + m_nextState = NEXT_OUTPUT; + } else { + m_nextState = OUTPUTS_END; + } + break; + + case NEXT_OUTPUT: + c = ','; + m_nextChar = m_currentOutput->getName(); + m_nextState = OUTPUT_START; + break; + + case OUTPUTS_END: + c = ']'; + m_nextState = END; + break; + case END: + default: + c = '\0'; + } + + return c; +} + diff --git a/libraries/Temboo/src/utility/ChoreoOutputFormatter.h b/libraries/Temboo/src/utility/ChoreoOutputFormatter.h new file mode 100644 index 000000000..c1086fc57 --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoOutputFormatter.h @@ -0,0 +1,66 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#ifndef CHOREOOUTPUTFORMATTER_H_ +#define CHOREOOUTPUTFORMATTER_H_ +#include "TembooGlobal.h" +#include "BaseFormatter.h" +#include "ChoreoOutputSet.h" + +class ChoreoOutputFormatter : public BaseFormatter { + + public: + ChoreoOutputFormatter(const ChoreoOutputSet* outputSet); + bool hasNext(); + char next(); + void reset(); + + protected: + const ChoreoOutputSet* m_outputSet; + const ChoreoOutput* m_currentOutput; + + enum State { + START, + OUTPUTS_TAG, + OUTPUT_START, + NAME_TAG, + NAME_START, + NAME, + NAME_END, + NAME_PATH_SEPARATOR, + PATH_TAG, + PATH_START, + PATH, + PATH_END, + PATH_VAR_SEPARATOR, + VAR_TAG, + VAR_START, + VAR, + VAR_END, + OUTPUT_END, + NEXT_OUTPUT, + OUTPUTS_END, + END + }; +}; + +#endif diff --git a/libraries/Temboo/src/utility/ChoreoOutputSet.cpp b/libraries/Temboo/src/utility/ChoreoOutputSet.cpp new file mode 100644 index 000000000..f61b83fd9 --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoOutputSet.cpp @@ -0,0 +1,73 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#include +#include +#include "ChoreoOutputSet.h" + + +ChoreoOutputSet::ChoreoOutputSet() { + m_first = NULL; +} + +ChoreoOutputSet::~ChoreoOutputSet() { + ChoreoOutput* i = m_first; + ChoreoOutput* next = NULL; + while(i != NULL) { + next = i->getNext(); + delete i; + i = next; + } +} + +void ChoreoOutputSet::put(const char* name, const char* path, const char* variable) { + if (m_first == NULL) { + m_first = new ChoreoOutput(NULL, name, path, variable); + } else { + ChoreoOutput* last = NULL; + ChoreoOutput* i = m_first; + while(i != NULL) { + if (strcmp(i->getName(), name) == 0) { + i->setPath(path); + i->setVariable(variable); + break; + } + last = i; + i = i->getNext(); + } + + if (i == NULL) { + new ChoreoOutput(last, name, path, variable); + } + } +} + +const ChoreoOutput* ChoreoOutputSet::get(const char* name) const { + ChoreoOutput* i = m_first; + while(i != NULL) { + if (strcmp(i->getName(), name) == 0) { + return i; + } + i = i->getNext(); + } + return NULL; +} diff --git a/libraries/Temboo/src/utility/ChoreoOutputSet.h b/libraries/Temboo/src/utility/ChoreoOutputSet.h new file mode 100644 index 000000000..b15808980 --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoOutputSet.h @@ -0,0 +1,43 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#ifndef CHOREOOUTPUTSET_H_ +#define CHOREOOUTPUTSET_H_ +#include +#include "TembooGlobal.h" +#include "ChoreoOutput.h" + +class ChoreoOutputSet { + + public: + ChoreoOutputSet(); + ~ChoreoOutputSet(); + void put(const char* name, const char* path, const char* variable); + const ChoreoOutput* get(const char* name) const; + bool isEmpty() const {return m_first == NULL;} + const ChoreoOutput* getFirstOutput() const {return m_first;} + + protected: + ChoreoOutput* m_first; +}; + +#endif diff --git a/libraries/Temboo/src/utility/ChoreoPreset.cpp b/libraries/Temboo/src/utility/ChoreoPreset.cpp new file mode 100644 index 000000000..8b637001b --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoPreset.cpp @@ -0,0 +1,23 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#include "ChoreoPreset.h" diff --git a/libraries/Temboo/src/utility/ChoreoPreset.h b/libraries/Temboo/src/utility/ChoreoPreset.h new file mode 100644 index 000000000..b48b14262 --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoPreset.h @@ -0,0 +1,40 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#ifndef CHOREOPRESET_H_ +#define CHOREOPRESET_H_ +#include +#include "TembooGlobal.h" + +class ChoreoPreset { + public: + ChoreoPreset() {m_name = NULL;} + ChoreoPreset(const char* name) {put(name);} + const char* getName() const {return m_name;} + void put(const char* name) {m_name = name;} + bool isEmpty() const {return m_name == NULL || *m_name == '\0';} + + private: + const char* m_name; +}; + +#endif diff --git a/libraries/Temboo/src/utility/ChoreoPresetFormatter.cpp b/libraries/Temboo/src/utility/ChoreoPresetFormatter.cpp new file mode 100644 index 000000000..a5b8e2891 --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoPresetFormatter.cpp @@ -0,0 +1,84 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#include +#include +#include "ChoreoPresetFormatter.h" +#include "ChoreoPreset.h" + +static const char TAG_PRESET[] PROGMEM = "\"preset\":"; + +ChoreoPresetFormatter::ChoreoPresetFormatter(const ChoreoPreset* preset) { + m_preset = preset; + reset(); +} + +void ChoreoPresetFormatter::reset() { + m_nextChar = NULL; + if (m_preset == NULL || m_preset->isEmpty()) { + m_nextState = END; + } else { + m_nextState = START; + } +} + +bool ChoreoPresetFormatter::hasNext() { + return m_nextState != END; +} + +char ChoreoPresetFormatter::next() { + char c = '\0'; + switch(m_nextState) { + case START: + c = readStartTagChar(TAG_PRESET, PRESET_TAG); + break; + + case PRESET_TAG: + c = readTagChar(NAME_START); + break; + + case NAME_START: + c = '"'; + m_nextChar = m_preset->getName(); + if ((NULL == m_nextChar) || ('\0' == *m_nextChar)) { + m_nextState = NAME_END; + } else { + m_nextState = NAME; + } + break; + + case NAME: + c = readValueChar(NAME_END); + break; + + case NAME_END: + c = '"'; + m_nextState = END; + break; + + case END: + default: + c = '\0'; + } + return c; +} + diff --git a/libraries/Temboo/src/utility/ChoreoPresetFormatter.h b/libraries/Temboo/src/utility/ChoreoPresetFormatter.h new file mode 100644 index 000000000..a0ffaf984 --- /dev/null +++ b/libraries/Temboo/src/utility/ChoreoPresetFormatter.h @@ -0,0 +1,50 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#ifndef CHOREOPROFILEFORMATTER_H_ +#define CHOREOPROFILEFORMATTER_H_ +#include "TembooGlobal.h" +#include "BaseFormatter.h" +#include "ChoreoPreset.h" + +class ChoreoPresetFormatter : public BaseFormatter { + + public: + ChoreoPresetFormatter(const ChoreoPreset* preset); + bool hasNext(); + char next(); + void reset(); + + protected: + const ChoreoPreset* m_preset; + + enum State { + START, + PRESET_TAG, + NAME_START, + NAME, + NAME_END, + END + }; +}; + +#endif diff --git a/libraries/Temboo/src/utility/DataFormatter.cpp b/libraries/Temboo/src/utility/DataFormatter.cpp new file mode 100644 index 000000000..7291da94e --- /dev/null +++ b/libraries/Temboo/src/utility/DataFormatter.cpp @@ -0,0 +1,114 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#include "DataFormatter.h" + + +DataFormatter::DataFormatter( + const ChoreoInputSet* inputSet, + const ChoreoOutputSet* outputSet, + const ChoreoPreset* preset) : + m_inputFormatter(inputSet), + m_outputFormatter(outputSet), + m_presetFormatter(preset) { + + m_inputSet = inputSet; + m_outputSet = outputSet; + m_preset = preset; + + reset(); +} + +void DataFormatter::reset() { + m_nextState = DATA_START; + m_inputFormatter.reset(); + m_outputFormatter.reset(); + m_presetFormatter.reset(); +} + +bool DataFormatter::hasNext() { + return m_nextState != DATA_END; +} + +char DataFormatter::next() { + char c; + switch(m_nextState) { + case DATA_START: + c = '{'; + if (m_inputFormatter.hasNext()) { + m_nextState = FORMATTING_INPUTS; + } else if (m_outputFormatter.hasNext()) { + m_nextState = FORMATTING_OUTPUTS; + } else if (m_presetFormatter.hasNext()) { + m_nextState = FORMATTING_PRESET; + } else { + m_nextState = FORMATTING_EMPTY; + } + break; + case FORMATTING_INPUTS: + if (m_inputFormatter.hasNext()) { + c = m_inputFormatter.next(); + } else if (m_outputFormatter.hasNext()) { + c = ','; + m_nextState = FORMATTING_OUTPUTS; + } else if (m_presetFormatter.hasNext()) { + c = ','; + m_nextState = FORMATTING_PRESET; + } else { + c = '}'; + m_nextState = DATA_END; + } + break; + case FORMATTING_OUTPUTS: + if (m_outputFormatter.hasNext()) { + c = m_outputFormatter.next(); + } else if (m_presetFormatter.hasNext()) { + c = ','; + m_nextState = FORMATTING_PRESET; + } else { + c = '}'; + m_nextState = DATA_END; + } + break; + + case FORMATTING_PRESET: + if (m_presetFormatter.hasNext()) { + c = m_presetFormatter.next(); + } else { + c = '}'; + m_nextState = DATA_END; + } + break; + + case FORMATTING_EMPTY: + c = '}'; + m_nextState = DATA_END; + break; + + case DATA_END: + default: + c = '\0'; + break; + } + return c; +} + diff --git a/libraries/Temboo/src/utility/DataFormatter.h b/libraries/Temboo/src/utility/DataFormatter.h new file mode 100644 index 000000000..0ee110f87 --- /dev/null +++ b/libraries/Temboo/src/utility/DataFormatter.h @@ -0,0 +1,63 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#ifndef DATAFORMATTER_H_ +#define DATAFORMATTER_H_ +#include "TembooGlobal.h" +#include "ChoreoInputSet.h" +#include "ChoreoOutputSet.h" +#include "ChoreoPreset.h" +#include "ChoreoInputFormatter.h" +#include "ChoreoOutputFormatter.h" +#include "ChoreoPresetFormatter.h" + + +class DataFormatter { + + public: + DataFormatter(const ChoreoInputSet* inputSet, const ChoreoOutputSet* outputSet, const ChoreoPreset* preset); + bool hasNext(); + char next(); + void reset(); + + private: + const ChoreoInputSet* m_inputSet; + const ChoreoOutputSet* m_outputSet; + const ChoreoPreset* m_preset; + + ChoreoInputFormatter m_inputFormatter; + ChoreoOutputFormatter m_outputFormatter; + ChoreoPresetFormatter m_presetFormatter; + + enum State { + DATA_START, + FORMATTING_INPUTS, + FORMATTING_OUTPUTS, + FORMATTING_PRESET, + FORMATTING_EMPTY, + DATA_END + }; + + State m_nextState; + +}; +#endif diff --git a/libraries/Temboo/src/utility/TembooGlobal.c b/libraries/Temboo/src/utility/TembooGlobal.c new file mode 100644 index 000000000..256ea2ea9 --- /dev/null +++ b/libraries/Temboo/src/utility/TembooGlobal.c @@ -0,0 +1,48 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#include "TembooGlobal.h" + +char* uint16toa(uint16_t value, char* dest) { + return uint32toa(value, dest); +} + +char* uint32toa(uint32_t value, char* dest) { + char* end = dest; + do { + *end++ = (value % 10) + '0'; + } while (value /= 10); + *end = '\0'; + end--; + + char c; + char* begin = dest; + while(end > begin) { + c = *end; + *end = *begin; + *begin = c; + end--; + begin++; + } + + return dest; +} diff --git a/libraries/Temboo/src/utility/TembooGlobal.h b/libraries/Temboo/src/utility/TembooGlobal.h new file mode 100644 index 000000000..91d16585c --- /dev/null +++ b/libraries/Temboo/src/utility/TembooGlobal.h @@ -0,0 +1,53 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#ifndef TEMBOOGLOBAL_H_ +#define TEMBOOGLOBAL_H_ + +#include + +//#define TEMBOO_VERBOSE + +#ifdef TEMBOO_VERBOSE + #define TEMBOO_TRACE(x) Serial.print(x) + #define TEMBOO_TRACE_BYTES(x,c) Serial.write((const uint8_t*)x,c) + #define TEMBOO_TRACELN(x) Serial.println(x) +#else + #define TEMBOO_TRACE(x) + #define TEMBOO_TRACE_BYTES(x,c) + #define TEMBOO_TRACELN(x) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +char* uint16toa(uint16_t value, char* dest); +char* uint32toa(uint32_t value, char* dest); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/libraries/Temboo/src/utility/TembooSession.cpp b/libraries/Temboo/src/utility/TembooSession.cpp new file mode 100644 index 000000000..bdd7e229a --- /dev/null +++ b/libraries/Temboo/src/utility/TembooSession.cpp @@ -0,0 +1,266 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#include +#include +#include +#include "TembooSession.h" +#include "tmbhmac.h" +#include "DataFormatter.h" + +static const char EOL[] PROGMEM = "\r\n"; +static const char POST[] PROGMEM = "POST "; +static const char POSTAMBLE[] PROGMEM = " HTTP/1.0"; // Prevent host from using chunked encoding in response. +static const char HEADER_HOST[] PROGMEM = "Host: "; +static const char HEADER_ACCEPT[] PROGMEM = "Accept: application/xml"; +static const char HEADER_ORG[] PROGMEM = "x-temboo-domain: /"; +static const char HEADER_DOM[] PROGMEM = "/master"; +static const char HEADER_CONTENT_LENGTH[] PROGMEM = "Content-Length: "; +static const char HEADER_TIME[] PROGMEM = "x-temboo-time: "; +static const char BASE_CHOREO_URI[] PROGMEM = "/arcturus-web/api-1.0/ar"; +static const char HEADER_AUTH[] PROGMEM = "x-temboo-authentication: "; +static const char HEADER_CONTENT_TYPE[] PROGMEM = "Content-Type: text/plain"; +static const char TEMBOO_DOMAIN[] PROGMEM = ".temboolive.com"; +static const char SDK_ID[] PROGMEM = "?source_id=arduinoSDK1"; + +unsigned long TembooSession::s_timeOffset = 0; + +TembooSession::TembooSession(Client& client, + IPAddress serverAddr, + uint16_t port) : m_client(client) { + m_addr = serverAddr; + m_port = port; + m_sendQueueDepth = 0; +} + + +void TembooSession::setTime(unsigned long currentTime) { + s_timeOffset = currentTime - (millis()/1000); +} + + +unsigned long TembooSession::getTime() { + return s_timeOffset + (millis()/1000); +} + + + +int TembooSession::executeChoreo( + const char* accountName, + const char* appKeyName, + const char* appKeyValue, + const char* path, + const ChoreoInputSet& inputSet, + const ChoreoOutputSet& outputSet, + const ChoreoPreset& preset) { + + DataFormatter fmt(&inputSet, &outputSet, &preset); + char auth[HMAC_HEX_SIZE_BYTES + 1]; + char buffer[11]; + + // We use the current time-of-day as salt on the app key. + // We keep track of time-of-day by getting the current time + // from the server and applying an offset (the length of time + // we've been running.) + uint32toa((uint32_t)TembooSession::getTime(), buffer); + + uint16_t contentLength = getAuth(fmt, appKeyValue, buffer, auth); + + m_client.stop(); + m_client.flush(); + + int connected = 0; + TEMBOO_TRACE("Connecting: "); + + // reserve space for the "host" string sufficient to hold either the + // (dotted-quad) IP address + port, or the default .temboolive.com + // host string. + int hostLen = (m_addr == INADDR_NONE ? (strlen_P(TEMBOO_DOMAIN) + strlen(accountName) + 1):21); + char host[hostLen]; + + // If no explicit IP address was specified (the normal case), construct + // the "host" string from the account name and the temboo domain name. + if (m_addr == INADDR_NONE) { + strcpy(host, accountName); + strcat_P(host, TEMBOO_DOMAIN); + TEMBOO_TRACELN(host); + connected = m_client.connect(host, m_port); + } else { + + // If an IP address was explicitly specified (presumably for testing purposes), + // convert it to a dotted-quad text string. + host[0] = '\0'; + for(int i = 0; i < 4; i++) { + uint16toa(m_addr[i], &host[strlen(host)]); + strcat(host, "."); + } + + // replace the last '.' with ':' + host[strlen(host)-1] = ':'; + + // append the port number + uint16toa(m_port, &host[strlen(host)]); + + TEMBOO_TRACELN(host); + connected = m_client.connect(m_addr, m_port); + } + + if (connected) { + + TEMBOO_TRACELN("OK. req:"); + qsendProgmem(POST); + qsendProgmem(BASE_CHOREO_URI); + qsend(path); + qsendProgmem(SDK_ID); + qsendlnProgmem(POSTAMBLE); + + // Send our custom authentication header + // (app-key-name:hmac) + qsendProgmem(HEADER_AUTH); + qsend(appKeyName); + qsend(":"); + qsendln(auth); + + // send the standard host header + qsendProgmem(HEADER_HOST); + qsendln(host); + + // send the standard accept header + qsendlnProgmem(HEADER_ACCEPT); + + // send our custom account name neader + qsendProgmem(HEADER_ORG); + qsend(accountName); + qsendlnProgmem(HEADER_DOM); + + // send the standard content type header + qsendlnProgmem(HEADER_CONTENT_TYPE); + + // send our custom client time header + qsendProgmem(HEADER_TIME); + qsendln(buffer); + + // send the standard content length header + qsendProgmem(HEADER_CONTENT_LENGTH); + qsendln(uint16toa(contentLength, buffer)); + + qsendProgmem(EOL); + + // Format and send the body of the request + fmt.reset(); + while(fmt.hasNext()) { + qsend(fmt.next()); + } + + qsendProgmem(EOL); + qflush(); + return 0; + } else { + TEMBOO_TRACELN("FAIL"); + return 1; + } +} + + +uint16_t TembooSession::getAuth(DataFormatter& fmt, const char* appKeyValue, const char* salt, char* result) const { + + // We need the length of the data for other things, and + // this method is a convenient place to calculate it. + uint16_t len = 0; + + HMAC hmac; + + //combine the salt and the key and give it to the HMAC calculator + size_t keyLength = strlen(appKeyValue) + strlen(salt); + char key[keyLength + 1]; + strcpy(key, salt); + strcat(key, appKeyValue); + hmac.init((uint8_t*)key, keyLength); + + // process the data a block at a time. + uint8_t buffer[HMAC_BLOCK_SIZE_BYTES]; + int blockCount = 0; + fmt.reset(); + while(fmt.hasNext()) { + uint8_t c = fmt.next(); + len++; + buffer[blockCount++] = c; + if (blockCount == HMAC_BLOCK_SIZE_BYTES) { + hmac.process(buffer, blockCount); + blockCount = 0; + } + } + hmac.process(buffer, blockCount); + + // Finalize the HMAC calculation and store the (ASCII HEX) value in *result. + hmac.finishHex(result); + + // Return the number of characters processed. + return len; +} + + +void TembooSession::qsend(const char* s) { + char c = *s++; + while(c != '\0') { + qsend(c); + c = *s++; + } +} + + +void TembooSession::qsendProgmem(const char* s) { + char c = pgm_read_byte(s++); + while(c != '\0') { + qsend(c); + c = pgm_read_byte(s++); + } +} + + +void TembooSession::qsend(char c) { + m_sendQueue[m_sendQueueDepth++] = c; + if (m_sendQueueDepth >= TEMBOO_SEND_QUEUE_SIZE) { + qflush(); + } +} + + +void TembooSession::qflush() { + m_client.write((const uint8_t*)m_sendQueue, m_sendQueueDepth); + TEMBOO_TRACE_BYTES(m_sendQueue, m_sendQueueDepth); + m_sendQueueDepth = 0; +} + + +void TembooSession::qsendln(const char* s) { + qsend(s); + qsendProgmem(EOL); +} + + +void TembooSession::qsendlnProgmem(const char* s) { + qsendProgmem(s); + qsendProgmem(EOL); +} + + diff --git a/libraries/Temboo/src/utility/TembooSession.h b/libraries/Temboo/src/utility/TembooSession.h new file mode 100644 index 000000000..403ed8eb6 --- /dev/null +++ b/libraries/Temboo/src/utility/TembooSession.h @@ -0,0 +1,134 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#ifndef TEMBOOSESSIONCLASS_H_ +#define TEMBOOSESSIONCLASS_H_ + +#include +#include +#include +#include +#include "TembooGlobal.h" + +#ifndef TEMBOO_SEND_QUEUE_SIZE + +// Some network interfaces (i.e. ethernet or WiFi shields) can only accept +// a limited amount of data. If you try to send more than the limit, the excess +// is just lost. However, sending one character at a time is very inefficient. +// To deal with this situation, we queue up TEMBOO_SEND_QUEUE_SIZE bytes to send +// to the network device at one time. This is a compromise between RAM usage +// and performance. +#define TEMBOO_SEND_QUEUE_SIZE (32) +#endif + +class ChoreoInputSet; +class ChoreoOutputSet; +class ChoreoPreset; +class DataFormatter; + +class TembooSession { + public: + + //TembooSession constructor + //client: REQUIRED TCP/IP client object. Usually either an EthernetClient or a WiFiClient + //IPAddress: OPTIONAL IP address of the server to connect to. Usually only used for testing. + //port: OPTIONAL port number to use with the IPAddress. Usually only used for testing. + TembooSession(Client& client, IPAddress serverAddr=INADDR_NONE, uint16_t port=80); + + //executeChoreo sends a choreo execution request to the Temboo system. + // Does not wait for a response (that's a job for whoever owns the Client.) + //accountName: the name of the user's account at Temboo. + //appKeyName: the name of an application key in the user's account to use + // for this execution (analogous to a user name). + //appKeyValue: the value of the application key named in appKeyName. + // Used to authenticate the user (analogous to a password) + //path: The full path to the choreo to be executed (relative to the root of the + // user's account.) + //inputSet: the set of inputs needed by the choreo. + // May be an empty ChoreoInputSet. + //outputSet: the set of output filters to be applied to the choreo results. + // May be an empty ChoreoOutputSet + //preset: the ChoreoPreset to be used with the choreo execution. + // May be an empty ChoreoPreset. + int executeChoreo(const char* accountName, + const char* appKeyName, + const char* appKeyValue, + const char* path, + const ChoreoInputSet& inputSet, + const ChoreoOutputSet& outputSet, + const ChoreoPreset& preset); + + // setTime sets the current time in Unix timestamp format. Needed for execution request authentication. + // NOTE: This method is usually called by TembooChoreo.run() with the current time returned by + // an error response from the Temboo system, thus automatically setting the time. However, it + // MAY be called from user code if the particular board has a way of determining the current + // time in the proper format. + // currentTime: the number of seconds since 1970-01-01 00:00:00 UTC. + static void setTime(unsigned long currentTime); + + //getTime returns the current time in Unix timestamp format (seconds since 1970-01-01 00:00:00 UTC). + // Only valid after setTime has been called. + static unsigned long getTime(); + + private: + static unsigned long s_timeOffset; + + IPAddress m_addr; + uint16_t m_port; + + Client& m_client; + char m_sendQueue[TEMBOO_SEND_QUEUE_SIZE]; + size_t m_sendQueueDepth; + + // calculate the authentication code value of the formatted request body + // using the salted application key value as the key. + // Returns the number of characters processed (i.e. the length of the request body) + uint16_t getAuth(DataFormatter& fmt, const char* appKeyValue, const char* salt, char* hexAuth) const; + + + // queue an entire nul-terminated char array + // from RAM followed by a newline. + void qsendln(const char* str); + + // queue an entire nul-terminated char array + // from flash memory (PROGMEM) one byte at a time, + // followed by a newline. + void qsendlnProgmem(const char* str); + + // queue an entire nul-terminated char array + // from RAM one byte at a time. + void qsend(const char*); + + // queue an entire nul-terminated char array + // from flash memory (PROGMEM) one byte at a time. + void qsendProgmem(const char*); + + // queue a single character to be sent when the queue is full. + void qsend(char); + + // send the current contents of the send queue to the client. + void qflush(); + +}; + +#endif + diff --git a/libraries/Temboo/src/utility/tmbhmac.cpp b/libraries/Temboo/src/utility/tmbhmac.cpp new file mode 100644 index 000000000..736e60d44 --- /dev/null +++ b/libraries/Temboo/src/utility/tmbhmac.cpp @@ -0,0 +1,107 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#include +#include +#include "tmbhmac.h" + +HMAC::HMAC() { +} + +HMAC::HMAC(const uint8_t* key, uint32_t keyLength) { + init(key, keyLength); +} + +void HMAC::init(const uint8_t* key, uint32_t keyLength) { + + m_key = key; + m_keyLength = keyLength; + + uint8_t iKeyPad[HMAC_BLOCK_SIZE_BYTES]; + + constructKeyPad(iKeyPad, key, keyLength, (uint8_t)0x36); + + m_md5.init(); + m_md5.process(iKeyPad, HMAC_BLOCK_SIZE_BYTES); +} + +void HMAC::process(const uint8_t* msg, uint32_t msgLength) { + // hmac = hash(o_key_pad + hash(i_key_pad + message)) + // continue hashing the message + m_md5.process(msg, msgLength); +} + +void HMAC::finish(uint8_t* dest) { + //hmac = hash(o_key_pad + hash(i_key_pad + message)) + // + // Construct the o_key_pad + uint8_t finalBlock[HMAC_BLOCK_SIZE_BYTES + HMAC_HASH_SIZE_BYTES]; + constructKeyPad(finalBlock, m_key, m_keyLength, (uint8_t)0x5C); + m_md5.finish(finalBlock + HMAC_BLOCK_SIZE_BYTES); + + m_md5.init(); + m_md5.process(finalBlock, HMAC_BLOCK_SIZE_BYTES + HMAC_HASH_SIZE_BYTES); + m_md5.finish(dest); +} + +void HMAC::finishHex(char* dest) { + uint8_t binDest[HMAC_HASH_SIZE_BYTES]; + finish(binDest); + toHex(binDest, dest); +} + +void HMAC::toHex(uint8_t* hmac, char* dest) { + static const char hex[17] PROGMEM = "0123456789abcdef"; + uint16_t i; + for (i = 0; i < HMAC_HASH_SIZE_BYTES; i++) { + dest[i*2] = pgm_read_byte(&hex[hmac[i] >> 4]); + dest[(i*2) + 1] = pgm_read_byte(&hex[hmac[i] & 0x0F]); + } + dest[HMAC_HASH_SIZE_BYTES * 2] = '\0'; +} + +/* + * dest MUST be big enough to hold HMAC_BLOCK_SIZE_BYTES + */ +void HMAC::constructKeyPad(uint8_t* dest, const uint8_t* key, uint32_t keyLength, uint8_t padByte) { + + if (keyLength > HMAC_BLOCK_SIZE_BYTES) { + // If the key is bigger than 1 block, + // replace the key with the hash of the key. + MD5 md5; + md5.process(key, keyLength); + md5.finish(dest); + keyLength = HMAC_HASH_SIZE_BYTES; + } else { + // If the key length is <= to the HMAC block length, + // just use the key as-is. + memcpy(dest, key, keyLength); + } + // pad the remaining space with 0s + if (keyLength < HMAC_BLOCK_SIZE_BYTES) { + memset(dest + keyLength, 0, HMAC_BLOCK_SIZE_BYTES-keyLength); + } + + for (int i = 0; i < HMAC_BLOCK_SIZE_BYTES; i++) { + dest[i] ^= padByte; + } +} diff --git a/libraries/Temboo/src/utility/tmbhmac.h b/libraries/Temboo/src/utility/tmbhmac.h new file mode 100644 index 000000000..6652dbf82 --- /dev/null +++ b/libraries/Temboo/src/utility/tmbhmac.h @@ -0,0 +1,57 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#ifndef TMBHMAC_H_ +#define TMBHMAC_H_ +#include "tmbmd5.h" +#include "TembooGlobal.h" + +#define HMAC_HASH_SIZE_BYTES (MD5_HASH_SIZE_BYTES) +#define HMAC_BLOCK_SIZE_BYTES (MD5_BLOCK_SIZE_BYTES) + +#define HMAC_HEX_SIZE_BYTES (HMAC_HASH_SIZE_BYTES * 2) + +class HMAC +{ + public: + HMAC(); + HMAC(const uint8_t* key, uint32_t keyLength); + void init(const uint8_t* key, uint32_t keyLength); + void process(const uint8_t* msg, uint32_t msgLength); + void finish(uint8_t* dest); + void finishHex(char* dest); + enum { + HMAC_OK = 0, + HMAC_ERROR, + HMAC_FAIL_TESTVECTOR + }; + + private: + MD5 m_md5; + const uint8_t* m_key; + uint32_t m_keyLength; + + void constructKeyPad(uint8_t* dest, const uint8_t* key, uint32_t keyLength, uint8_t padByte); + void toHex(uint8_t* hmac, char* dest); +}; +#endif + diff --git a/libraries/Temboo/src/utility/tmbmd5.cpp b/libraries/Temboo/src/utility/tmbmd5.cpp new file mode 100644 index 000000000..e270c1c27 --- /dev/null +++ b/libraries/Temboo/src/utility/tmbmd5.cpp @@ -0,0 +1,213 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + + +#include +#include +#include "tmbmd5.h" + + +static const uint8_t Worder[64] PROGMEM = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12, + 5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2, + 0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9 +}; + +static const uint8_t Rorder[64] PROGMEM = { + 7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22, + 5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20, + 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23, + 6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21 +}; + +static const uint32_t Korder[64] PROGMEM = { +0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL, 0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL, +0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL, 0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL, +0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL, 0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL, +0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL, 0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL, +0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL, 0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL, +0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL, 0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL, +0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL, 0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL, +0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL, 0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL +}; + + +MD5::MD5() { + init(); +} + +void MD5::init() { + m_state[0] = 0x67452301UL; + m_state[1] = 0xefcdab89UL; + m_state[2] = 0x98badcfeUL; + m_state[3] = 0x10325476UL; + m_bufLength = 0; + m_msgLengthBits = 0; +} + +int MD5::compress(const uint8_t* buf) { + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; + uint32_t i; + uint32_t W[16]; + uint32_t t; + + // Copy data into W[0..15] in an endian-agnostic way + for (i = 0; i < 16; i++) { + W[i] = ((uint32_t)(buf[3])) << 24 + | ((uint32_t)(buf[2])) << 16 + | ((uint32_t)(buf[1])) << 8 + | ((uint32_t)(buf[0])); + buf += 4; + } + + // copy current state + a = m_state[0]; + b = m_state[1]; + c = m_state[2]; + d = m_state[3]; + + for (i = 0; i < 16; ++i) { + FF(&a,b,c,d,W[pgm_read_byte(&Worder[i])],pgm_read_byte(&Rorder[i]),pgm_read_dword(&Korder[i])); + t = d; d = c; c = b; b = a; a = t; + } + + for (; i < 32; ++i) { + GG(&a,b,c,d,W[pgm_read_byte(&Worder[i])],pgm_read_byte(&Rorder[i]),pgm_read_dword(&Korder[i])); + t = d; d = c; c = b; b = a; a = t; + } + + for (; i < 48; ++i) { + HH(&a,b,c,d,W[pgm_read_byte(&Worder[i])],pgm_read_byte(&Rorder[i]),pgm_read_dword(&Korder[i])); + t = d; d = c; c = b; b = a; a = t; + } + + for (; i < 64; ++i) { + II(&a,b,c,d,W[pgm_read_byte(&Worder[i])],pgm_read_byte(&Rorder[i]),pgm_read_dword(&Korder[i])); + t = d; d = c; c = b; b = a; a = t; + } + + m_state[0] = m_state[0] + a; + m_state[1] = m_state[1] + b; + m_state[2] = m_state[2] + c; + m_state[3] = m_state[3] + d; + + return MD5::MD5_OK; +} + +int MD5::process (const uint8_t* msg, uint32_t msgLengthBytes) { + uint32_t n; + int err; + + if (m_bufLength >= sizeof(m_buf)) { + return MD5::MD5_INVALID_ARG; + } + + while (msgLengthBytes > 0) { + + // Process the input msg in 64 byte chunks + if (m_bufLength == 0 && msgLengthBytes >= 64) { + err = compress (msg); + if (err != MD5::MD5_OK) { + return err; + } + m_msgLengthBits += 64 * 8; + msg += 64; + msgLengthBytes -= 64; + } else { + n = 64 - m_bufLength; + if (msgLengthBytes < n) { + n = msgLengthBytes; + } + memcpy(m_buf + m_bufLength, msg, (size_t)n); + m_bufLength += n; + msg += n; + msgLengthBytes -= n; + if (m_bufLength == 64) { + err = compress (m_buf); + if (err != MD5::MD5_OK) { + return err; + } + m_msgLengthBits += 64 * 8; + m_bufLength = 0; + } + } + } + return MD5::MD5_OK; +} + + +int MD5::finish(uint8_t* out) { + int i; + + if (m_bufLength >= sizeof(m_buf)) { + return MD5::MD5_INVALID_ARG; + } + + m_msgLengthBits += m_bufLength * 8; + + // append a '1' bit (right-padded with zeros) + m_buf[m_bufLength++] = (uint8_t)0x80; + + // if the bufLength is > 56 bytes, pad with zeros then compress. + // Then fall back to padding with zeros and length encoding like normal. + if (m_bufLength > 56) { + while (m_bufLength < 64) { + m_buf[m_bufLength++] = (uint8_t)0; + } + compress(m_buf); + m_bufLength = 0; + } + + // pad with zeroes up to 56 bytes. + // (Why 56? because we store the 8-byte length at the end.) + // (What if bufLength == 56? Perfect! No padding prior to 8-byte length needed.) + while (m_bufLength < 56) { + m_buf[m_bufLength++] = (uint8_t)0; + } + + // add the length in an endian-agnostic way + m_buf[56] = (uint8_t)((m_msgLengthBits ) & 255); + m_buf[57] = (uint8_t)((m_msgLengthBits >> 8) & 255); + m_buf[58] = (uint8_t)((m_msgLengthBits >> 16) & 255); + m_buf[59] = (uint8_t)((m_msgLengthBits >> 24) & 255); + m_buf[60] = (uint8_t)((m_msgLengthBits >> 32) & 255); + m_buf[61] = (uint8_t)((m_msgLengthBits >> 40) & 255); + m_buf[62] = (uint8_t)((m_msgLengthBits >> 48) & 255); + m_buf[63] = (uint8_t)((m_msgLengthBits >> 56) & 255); + + compress(m_buf); + + // copy the state to the output in an endian-agnostic way + for (i = 0; i < 4; i++) { + out[0] = m_state[i] & 255; + out[1] = (m_state[i] >> 8) & 255; + out[2] = (m_state[i] >> 16) & 255; + out[3] = (m_state[i] >> 24) & 255; + out += 4; + } + return MD5::MD5_OK; +} + diff --git a/libraries/Temboo/src/utility/tmbmd5.h b/libraries/Temboo/src/utility/tmbmd5.h new file mode 100644 index 000000000..3a0bcf0e6 --- /dev/null +++ b/libraries/Temboo/src/utility/tmbmd5.h @@ -0,0 +1,72 @@ +/* +############################################################################### +# +# Temboo Arduino library +# +# Copyright 2014, Temboo Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +# either express or implied. See the License for the specific +# language governing permissions and limitations under the License. +# +############################################################################### +*/ + +#ifndef TMBMD5_H_ +#define TMBMD5_H_ + +#include +#include "TembooGlobal.h" + +#define MD5_HASH_SIZE_BITS (128) +#define MD5_HASH_SIZE_BYTES (MD5_HASH_SIZE_BITS/8) + +#define MD5_BLOCK_SIZE_BITS (512) +#define MD5_BLOCK_SIZE_BYTES (MD5_BLOCK_SIZE_BITS/8) + + +#define ROL(x, y) ( (((uint32_t)(x)<<(uint32_t)((y)&31)) | (((uint32_t)(x)&0xFFFFFFFFUL)>>(uint32_t)(32-((y)&31)))) & 0xFFFFFFFFUL) +class MD5 { + +public: + MD5(); + void init(); + int process(const uint8_t* in, uint32_t inlen); + int finish(uint8_t* hash); + enum { + MD5_OK = 0, + MD5_ERROR, + MD5_INVALID_ARG, + MD5_FAIL_TESTVECTOR + }; + +private: + uint64_t m_msgLengthBits; + uint32_t m_state[4]; + uint32_t m_bufLength; + uint8_t m_buf[64]; + + int compress(const uint8_t* buf); + + inline uint32_t F_(uint32_t x, uint32_t y, uint32_t z) { return (z ^ (x & (y ^ z))); } + inline uint32_t G_(uint32_t x, uint32_t y, uint32_t z) { return (y ^ (z & (y ^ x))); } + inline uint32_t H_(uint32_t x, uint32_t y, uint32_t z) { return (x^y^z); } + inline uint32_t I_(uint32_t x, uint32_t y, uint32_t z) { return (y^(x|(~z))); } + + + inline void FF(uint32_t* a, uint32_t b, uint32_t c, uint32_t d, uint32_t M, uint32_t s, uint32_t t) { *a = (*a + F_(b,c,d) + M + t); *a = ROL(*a, s) + b; } + inline void GG(uint32_t* a, uint32_t b, uint32_t c, uint32_t d, uint32_t M, uint32_t s, uint32_t t) { *a = (*a + G_(b,c,d) + M + t); *a = ROL(*a, s) + b; } + inline void HH(uint32_t* a, uint32_t b, uint32_t c, uint32_t d, uint32_t M, uint32_t s, uint32_t t) { *a = (*a + H_(b,c,d) + M + t); *a = ROL(*a, s) + b; } + inline void II(uint32_t* a, uint32_t b, uint32_t c, uint32_t d, uint32_t M, uint32_t s, uint32_t t) { *a = (*a + I_(b,c,d) + M + t); *a = ROL(*a, s) + b; } + +}; + +#endif