Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: C12832_lcd EthernetInterface StatusReporter LM75B MQTT-ansond endpoint_core endpoint_mqtt mbed-rtos mbed
MBEDEndpoint.cpp
- Committer:
- ansond
- Date:
- 2014-02-28
- Revision:
- 33:8302b02413bd
- Parent:
- 32:a7b3c285446c
- Child:
- 36:210f3956038c
File content as of revision 33:8302b02413bd:
/* Copyright C2013 Doug Anson, MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files the "Software", to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "MQTTTransport.h"
#include "MBEDEndpoint.h"
// MBED Light support
#include "MBEDLight.h"
// Emulated Resource Factory
#include "EmulatedResourceFactory.h"
// Emulated Actions we can act on
#include "EmulatedLightDimmerAction.h"
#include "EmulatedLightSwitchAction.h"
// shutdown endpoint reference
extern void closedown(int code);
// default constructor
MBEDEndpoint::MBEDEndpoint(ErrorHandler *error_handler,EthernetInterface *ethernet) {
bool success = true;
for(int i=0;i<NUM_TRANSPORTS;++i) this->m_transports[i] = NULL;
this->m_error_handler = error_handler;
if (success) this->initEndpointName();
if (success) this->logger()->turnLEDBlue();
if (success)this->logger()->log(ENDPOINT_VERSION_ANNOUNCE);
if (success) success = this->initializeEthernet(ethernet);
if (success) this->logger()->turnLEDYellow();
if (success)this->m_map = new MBEDToIOCResourceMap(error_handler);
if (success) success = this->initializeTransports();
if (success) success = this->initializeLights();
if (success) this->logger()->turnLEDGreen();
if (!success) closedown(2);
}
// default destructor
MBEDEndpoint::~MBEDEndpoint() {
bool success = true;
if (success) this->logger()->turnLEDYellow();
if (success) success = this->closeLights();
if (success) success = this->closeTransports();
if (success) success = this->closeEthernet();
if (success) this->logger()->turnLEDBlue();
if (this->m_map != NULL) delete this->m_map;
}
// get the IOC <--> MBED resource map
MBEDToIOCResourceMap *MBEDEndpoint::getMap() { return this->m_map; }
// initialize the Lights
bool MBEDEndpoint::initializeLights() {
this->logger()->log("Initializing Lights...");
for(int i=0;i<NUM_LIGHTS;++i) {
this->m_lights[i] = new MBEDLight(this->logger(),this->m_transports,i+1,this);
this->m_lights[i]->setDimmerAction(new EmulatedLightDimmerAction(this->logger(),this->m_lights[i]));
this->m_lights[i]->setSwitchAction(new EmulatedLightSwitchAction(this->logger(),this->m_lights[i]));
}
return true;
}
// does the input name match any of our light resources?
int MBEDEndpoint::indexOfLight(char *name) {
bool found = false;
int index = -1;
for(int i=0;i<NUM_LIGHTS && !found;++i) {
if (strcmp(this->m_lights[i]->getName(),name) == 0) {
found = true;
index = i;
}
}
return index;
}
// get a specific resources
ResourceFactory *MBEDEndpoint::getResources(int index) {
if (index >= 0 && index < NUM_LIGHTS) return this->m_lights[index]->resources();
return NULL;
}
// initialize our ResourceFactory
ResourceFactory *MBEDEndpoint::initResourceFactory() { return new EmulatedResourceFactory(this->logger()); }
// Initialize the Endpoint Name - will be the first Light resource name (and there must be one...)
void MBEDEndpoint::initEndpointName() {
memset(this->m_endpoint_name,0,LIGHT_NAME_LEN+1);
sprintf(this->m_endpoint_name,LIGHT_NAME,1);
}
// get our endpoint name
char *MBEDEndpoint::getEndpointName() { return this->m_endpoint_name; }
// initialize a specific transport
bool MBEDEndpoint::initializeTransport(int index,char *key,Transport *transport) {
bool success = false;
if (this->m_transports[index] == NULL) {
this->logger()->log("Initializing %s Transport...", key);
this->m_transports[index] = transport;
if (this->m_transports[index] != NULL) success = this->m_transports[index]->connect();
}
else {
this->logger()->log("%s already connected (OK)...", key);
success = true;
}
return success;
}
// initialize our transports
bool MBEDEndpoint::initializeTransports() {
bool success = true;
if (success == true) {
// MQTT Initialization
success = this->initializeTransport(MQTT_TRANSPORT,"MQTT",new MQTTTransport(this->m_error_handler,this,this->getMap()));
}
if (success == true) {
// HTTP Initialization
success = this->initializeTransport(HTTP_TRANSPORT,"HTTP",new HTTPTransport(this->m_error_handler,this));
}
return success;
}
// initialize our Ethernet
bool MBEDEndpoint::initializeEthernet(EthernetInterface *ethernet) {
bool success = false;
this->m_ethernet = ethernet;
if (this->m_ethernet != NULL) {
this->logger()->log("Initializing Ethernet...");
// connect up ethernet
this->m_ethernet->init();
this->m_ethernet->connect();
// display our IP address
char *ipaddr = this->m_ethernet->getIPAddress();
if (ipaddr != NULL && strlen(ipaddr) > 0) {
this->logger()->log("IPAddress: %s",this->m_ethernet->getIPAddress());
success = true;
}
else {
this->logger()->log("Ethernet Not Connected...");
success = false;
}
}
else {
this->logger()->log("No Ethernet instance found");
success = false;
}
return success;
}
// load up all endpoints into the IOC
bool MBEDEndpoint::loadEndpoints() {
bool success = true;
this->logger()->log("Loading All Endpoints to IOC...");
for(int i=0;i<NUM_LIGHTS && success;++i) success = this->loadEndpoint(this->m_lights[i]);
return success;
}
// load up our endpoint to the IOC
bool MBEDEndpoint::loadEndpoint(Light *light) {
bool success = false;
char result[IOC_RESULT_LEN+1];
char payload[IOC_PAYLOAD_LEN+1];
// initialize
memset(result,0,IOC_RESULT_LEN+1);
memset(payload,0,IOC_PAYLOAD_LEN+1);
// DEBUG
//this->logger()->log("Loading Light: %s...",light->getName());
// build the payload
char *data = this->buildIOCPayload(payload,IOC_PAYLOAD_LEN,light);
// DEBUG
this->logger()->log("Sending Light: %s to the IOC...",light->getName());
// issue the request
success = this->m_transports[LOAD_TRANSPORT]->loadEndpoint((char *)payload,strlen(payload),(char *)result,IOC_RESULT_LEN);
// DEBUG
//if (success) this->logger()->log("Saving IOC ID for Light: %s...",light->getName());
// update the IOC ID if found
if (success) this->saveIOCID(light,result);
// DEBUG
if (success) this->logger()->log("Light: %s IOC ID=%d sent successfully",light->getName(),light->getIOCID());
else this->logger()->log("Light: %s send FAILED",light->getName());
// DEBUG
if (!success) this->logger()->log("Loading Light: %s FAILED",light->getName());
// return our status
return success;
}
// update all endpoints to the IOC
bool MBEDEndpoint::updateEndpoints() {
bool success = true;
for(int i=0;i<NUM_LIGHTS && success;++i) success = this->updateEndpoints(i);
return success;
}
// update all endpoints to the IOC
bool MBEDEndpoint::updateEndpoints(int index) {
if (index >= 0 && index < NUM_LIGHTS) return this->updateEndpoint(this->m_lights[index]);
return false;
}
// update our endpoint with the IOC
bool MBEDEndpoint::updateEndpoint(Light *light) {
bool success = false;
char result[IOC_RESULT_LEN+1];
char payload[IOC_PAYLOAD_LEN+1];
// initialize
memset(result,0,IOC_RESULT_LEN+1);
memset(payload,0,IOC_PAYLOAD_LEN+1);
// build the payload
char *data = this->buildIOCPayload(payload,IOC_PAYLOAD_LEN,light);
// issue the request
success = this->m_transports[LOAD_TRANSPORT]->updateEndpoint(light->getIOCID(),(char *)payload,strlen(payload),(char *)result,IOC_RESULT_LEN);
// DEBUG
if (success) this->logger()->log("Update of Endpoint to IOC successful");
else this->logger()->log("Update of Endpoint to IOC FAILED");
// return our status
return success;
}
// build out the Payload
char *MBEDEndpoint::buildIOCPayload(char *data,int data_length,Light *light) {
// construct the payload for Load/Updates
ResourceFactory *factory = light->getResourceFactory();
// accumulator string
std::string str_json("{");
// loop through the resources and build a JSON representation for the payload
for(int i=0;i<factory->numResources();++i) {
// get the ith resource
Resource *resource = factory->getResource(i);
// add to the JSON payload
char *name = this->getMap()->endpointNameToIOCName(resource->getName());
char *value = resource->getValue();
// Handle LOCATION a special way
if (strcmp(name,"LOCATION") != 0) {
str_json += "\"" + std::string(name) + "\":\"" + std::string(value) + "\",";
}
else {
// IOC expects "Point(X,Y)" for LOCATION, but in reverse from MBED
str_json += "\"" + std::string(name) + "\":\"Point(" + std::string(value) + ")\",";
}
// Handle /dev/addldata
char *dev_addldata = this->getMap()->endpointNameToIOCName("/dev/addldata");
if (dev_addldata != NULL && strcmp(name,dev_addldata) == 0 && light != NULL && light->getIOCID() > 0) {
char buf[10]; memset(buf,0,10); sprintf(buf,"%d",light->getIOCID());
str_json += "\"" + std::string(name) + "\":\"id:" + std::string(buf) + "\",";
}
}
// Special Case: STARTDATETIME
str_json += "\"STARTDATETIME\":\"2014-02-27T22:03:06.973Z\",";
// Special Case: ENDDATETIME
str_json += "\"ENDDATETIME\":\"2015-02-27T03:35:55.940Z\",";
// Special Case: NAME
str_json += "\"NAME\":\"" + std::string(light->getName()) + "\",";
// Special Case: TIMEZONEOFFSET
str_json += "\"TIMEZONEOFFSET\":\"+2:00\"";
// close
str_json += "}";
// copy over to the buffer
strncpy(data,str_json.c_str(),this->min(str_json.length(),data_length));
// DEBUG
//this->logger()->log("Loading Payload: %s",data);
// return the payload
return data;
}
// save the IOC ID
void MBEDEndpoint::saveIOCID(Light *light,char *json) {
if (json != NULL) {
std::string str_json(json);
// look for "id":
std::string check("\"id\":");
int pos1 = str_json.find(check);
int pos2 = str_json.find(",",pos1);
if (pos1 >= 0 && pos2 >= 0 && pos2 > pos1) {
pos1 += check.length();
int length = pos2 - pos1;
std::string str_ioc_id = str_json.substr(pos1,length);
// DEBUG
//this->logger()->log("IOC ID found: %s",str_ioc_id.c_str());
// parse into int
int ioc_id = 0;
sscanf(str_ioc_id.c_str(),"%d",&ioc_id);
// save the IOC ID
if (ioc_id > 0) light->setIOCID(ioc_id);
}
else {
// cannot find the ID tag in the result JSON
this->logger()->log("Cannot find the IOC ID in the JSON result");
this->logger()->log("JSON: %s",json);
}
}
}
// close down the Lights
bool MBEDEndpoint::closeLights() {
bool success = true;
this->logger()->log("Closing down Lights...");
for(int i=0;i<NUM_LIGHTS;++i)
if (this->m_lights[i] != NULL) delete this->m_lights[i];
return success;
}
// close a given transport
bool MBEDEndpoint::closeTransport(int index,char *key) {
this->logger()->log("Closing down %s Transport...", key);
if (this->m_transports[index] != NULL) delete this->m_transports[index];
return true;
}
// close down our transports
bool MBEDEndpoint::closeTransports() {
bool success = true;
if (success) {
// close MQTT
success = this->closeTransport(MQTT_TRANSPORT,"MQTT");
}
if (success) {
// close HTTP
success = this->closeTransport(HTTP_TRANSPORT,"HTTP");
}
return success;
}
// close down our Ethernet
bool MBEDEndpoint::closeEthernet() {
this->logger()->log("Closing down Ethernet...");
if (this->m_ethernet != NULL) this->m_ethernet->disconnect();
return true;
}
// min function
int MBEDEndpoint::min(int value1,int value2) {
if (value1 < value2) return value1;
return value2;
}
// get our error handler
ErrorHandler *MBEDEndpoint::logger() { return this->m_error_handler; }
// main running loop
void MBEDEndpoint::run() {
this->logger()->log("Endpoint Main Loop");
while(true) {
// sleep a bit
//this->logger()->log("Sleeping for a bit...");
wait_ms(MAIN_LOOP_SLEEP);
// check for events
//this->logger()->log("Processing Events...");
for(int i=0;i<NUM_TRANSPORTS;++i) this->m_transports[i]->checkAndProcess();
// check for exit
//this->logger()->log("Checking for exit...");
this->logger()->checkForExit();
}
}