mqtt specific components for the impact mbed endpoint library

Dependents:   mbed_mqtt_endpoint_ublox_ethernet mbed_mqtt_endpoint_ublox_cellular mbed_mqtt_endpoint_nxp

MBEDEndpoint.cpp

Committer:
ansond
Date:
2014-09-26
Revision:
56:789a1a8c5ebe
Parent:
53:74816856d11b

File content as of revision 56:789a1a8c5ebe:

/* 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"
 
 // Light Personality: Emulated Light Resource Factory
 #include "EmulatedLightResourceFactory.h"
 
 // Light Personality: Emulated Actions we can act on with the Light personalikty
 #include "EmulatedLightDimmerAction.h"
 #include "EmulatedLightSwitchAction.h"
 
 // Salesforce Status Reporting (if enabled)
 #if SF_STATUS_REPORTING
    #include "StatusReporter.h"
 #endif
 
 // string support
 #include <stdlib.h>
 #include <string.h>
   
 // shutdown endpoint reference
 extern void closedown(int code);
  
 // default constructor
 MBEDEndpoint::MBEDEndpoint(Logger *logger,void *transport,void *status_reporter,void *extra) : BaseClass(logger,NULL) {
     bool success = true;
     this->m_instance_id = 0;
     this->m_preferences = NULL;
     this->m_status_reporter = status_reporter;
     memset(this->m_lcd_status,0,TEMP_BUFFER_LEN+1);
     memset(this->m_gw_address,0,PREFERENCE_VALUE_LEN+1);
     for(int i=0;i<NUM_TRANSPORTS;++i) this->m_transports[i] = NULL;
     this->logger()->setEndpoint((void *)this);
     this->setEndpoint(new IOCEndpoint(logger,(void *)this));
     if (success) this->initPreferences();
     if (success) this->initEndpointName();
     if (success) this->logger()->turnLEDBlue();
 #ifdef MAC_ADDRESS
     extern char fmt_mac[RESOURCE_VALUE_LEN+1];
     if (success)this->logger()->log("%s (MAC: %s)",ENDPOINT_VERSION_ANNOUNCE,fmt_mac);
#else
     if (success)this->logger()->log(ENDPOINT_VERSION_ANNOUNCE);
#endif
     if (success) this->initGWAddress();
     //if (success) this->logger()->log("IOC GW IP: %s",this->m_gw_address);
     if (PL_ENABLE && success) this->logger()->log("Philips Light ID: %d Philips Gateway IP: %s",PL_LIGHT_ID,PL_GW_ADDRESS);
#ifdef CELLULAR_NETWORK
     this->m_cellular_modem = NULL;
     this->m_gps = NULL;
     this->logger()->log("initializing Cellular Modem...");
     if (success) success = this->initializeCellularModem(transport);
     //this->logger()->log("initializing GPS Receiver...");
     //if (success) success = this->initializeGPSReceiver(this,extra);
#else
     if (success) success = this->initializeEthernet((EthernetInterface *)transport);
#endif
     if (success) this->logger()->turnLEDYellow();
     this->logger()->log("initializing resource map...");
     if (success)this->m_map = new MBEDToIOCResourceMap(logger); 
     this->logger()->log("initializing transports...");
     if (success) success = this->initializeTransports();
     this->logger()->log("initializing personalities...");
     if (success) success = this->initializePersonalities();  
     this->logger()->log("initialization complete for endpoint...");
     if (success) this->logger()->turnLEDOrange();
     this->logger()->lcdStatusOnly(true);
     if (!success) closedown(2);
     if (success && AUTO_REGISTER_WITH_IOC) {
         // load up our endpoints
         this->loadPersonalities();
         this->updatePersonalities();
     }
 }
 
 // default destructor
 MBEDEndpoint::~MBEDEndpoint() {
     bool success = true;
     if (success) this->logger()->turnLEDYellow();
     if (success) success = this->closePersonalities();
     if (success) success = this->closeTransports();
#ifdef CELLULAR_NETWORK
     if (success) success = this->closeCellularModem();
     if (success) success = this->closeGPSReceiver();
     if (this->m_cellular_modem != NULL) delete this->m_cellular_modem;
     if (this->m_gps != NULL) delete this->m_gps;
     if (this->m_preferences != NULL) delete this->m_preferences;
#else
     if (success) success = this->closeEthernet();
#endif
     if (success) this->logger()->turnLEDBlue();
     if (this->m_map != NULL) delete this->m_map;
     if (this->getEndpoint() != NULL) delete (IOCEndpoint *)this->getEndpoint();
 }
  
 // get the IOC <--> MBED resource map
 MBEDToIOCResourceMap *MBEDEndpoint::getMap() { return this->m_map; }
 
 // initialize our preferences
 void MBEDEndpoint::initPreferences() { 
    if (this->m_preferences == NULL) 
        this->m_preferences = new Preferences(this->logger()); 
    if (this->m_preferences != NULL) 
        this->m_preferences->fixCoordsForIOC(); 
 }

 // get our preferences
 Preferences *MBEDEndpoint::preferences() { return this->m_preferences; }
 
 // initialize the GW address from the configuration
 void MBEDEndpoint::initGWAddress() {
     memset(this->m_gw_address,0,PREFERENCE_VALUE_LEN+1);
     strcpy(this->m_gw_address,GW_IPADDRESS);
     if (this->m_preferences != NULL) {
        this->m_preferences->getPreference("gw_address",this->m_gw_address,PREFERENCE_VALUE_LEN,GW_IPADDRESS);
        this->m_preferences->getPreference("gw_port",this->m_gw_port,PREFERENCE_VALUE_LEN,GW_PORT);
        this->logger()->log("GW: %s:%s",this->m_gw_address,this->m_gw_port);
     }   
 }
 
 // get our GW address
 char *MBEDEndpoint::getGWAddress() { return this->m_gw_address; }
 
 // get our GW Port
 char *MBEDEndpoint::getGWPort() { return this->m_gw_port; }
 
 // get our LCD status
 char *MBEDEndpoint::getLCDStatus() {
     memset(this->m_lcd_status,0,TEMP_BUFFER_LEN+1);
     
     // look at Light#0 to determine the IOC linkage ID...
     char *ioc = this->m_personalities[0]->getResourceFactory()->getResourceValue(EXTERNAL_LINKAGE_RESOURCE);
     
     // color our LED depending on whether we have IOC linkage or not...
     if (ioc == NULL || strcmp(ioc,EXTERNAL_LINKAGE_UNSET) == 0) this->logger()->turnLEDOrange();
     else this->logger()->turnLEDGreen();
           
     sprintf(this->m_lcd_status,"Node: %s\nGW IP: %s\nIOC Link: %s",this->getEndpointName(),this->getGWAddress(),ioc);
     return this->m_lcd_status;
 }
 
 // initialize our personality
 bool MBEDEndpoint::initializePersonalities() {
 #ifdef LIGHT_PERSONALITY
    return this->initializeLights();
 #endif
 #ifdef COPCAR_PERSONALITY
    return this->initializeLights();
 #endif
 }
 
 // initialize the Lights
 bool MBEDEndpoint::initializeLights() {
     int index = PERSONALITY_NAME_INDEX;
     if (this->m_preferences != NULL) index = this->m_preferences->getIntPreference("endpoint_id",PERSONALITY_NAME_INDEX); 
     this->logger()->log("Initializing Lights...");
     for(int i=0;i<NUM_PERSONALITY_INSTANCES;++i) {
         this->m_personalities[i] = new MBEDLight(this->logger(),this->m_transports,i+index,this);
         ((Light *)this->m_personalities[i])->setDimmerAction(new EmulatedLightDimmerAction(this->logger(),(Light *)this->m_personalities[i]));
         ((Light *)this->m_personalities[i])->setSwitchAction(new EmulatedLightSwitchAction(this->logger(),(Light *)this->m_personalities[i]));
     }
     return true;
 }
 
 // does the input name match any of our personality instances?
 int MBEDEndpoint::indexOfPersonality(char *name) {
     bool found = false;
     int index = -1;
     
     for(int i=0;i<NUM_PERSONALITY_INSTANCES && !found;++i) {
         if (strcmp(this->m_personalities[i]->getName(),name) == 0) {
             found = true;
             index = i;
         }
     }
     
     return index;
 }
 
 // get a specific resources
 ResourceFactory *MBEDEndpoint::getResources(int index) {
     if (index >= 0 && index < NUM_PERSONALITY_INSTANCES) return this->m_personalities[index]->getResourceFactory();
     return NULL;
 }
 
 // initialize the ResourceFactory to fit our personality
 ResourceFactory *MBEDEndpoint::initResourceFactory() {
#ifdef LIGHT_PERSONALITY
    return this->initLightResourceFactory(); 
#endif
#ifdef COPCAR_PERSONALITY
    return this->initLightResourceFactory(); 
#endif
 }
 
 // initialize a Light Resource Factory
 ResourceFactory *MBEDEndpoint::initLightResourceFactory() { return new EmulatedLightResourceFactory(this->logger(),(void *)this); }
 
 // Initialize the Endpoint Name - will be the first Light resource name (and there must be one...)
 void MBEDEndpoint::initEndpointName() {
     this->m_instance_id = PERSONALITY_NAME_INDEX;
     memset(this->m_endpoint_name,0,PERSONALITY_NAME_LEN+1);
     if (this->m_preferences != NULL) 
        this->m_instance_id = this->m_preferences->getIntPreference("endpoint_id",PERSONALITY_NAME_INDEX);
     sprintf(this->m_endpoint_name,PERSONALITY_NAME,this->m_instance_id);
 }
 
 // get our endpoint name
 char *MBEDEndpoint::getEndpointName() { return this->m_endpoint_name; }
 
 // get our instance id
 int MBEDEndpoint::getInstanceID() { return this->m_instance_id; }
 
 // 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();
          if (success) this->logger()->log("Transport %s initialized and connected",key);
      }
      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->logger(),this,this->getMap()));
      }
      
      if (success == true) {
          // HTTP Initialization
          success = this->initializeTransport(HTTP_TRANSPORT,"HTTP",new IOCHTTPTransport(this->logger(),this));
      }
      return success;
 }
 
 #ifdef CELLULAR_NETWORK
 bool MBEDEndpoint::initializeCellularModem(void *modem) {
     bool success = false;
     
     // initialize
     if (this->m_cellular_modem == NULL) this->m_cellular_modem = new MBEDUbloxCellRadio(this->logger(),(void *)this,modem);
     if (this->m_cellular_modem != NULL) success = this->m_cellular_modem->connect();
     
     // return our status
     return success;
 }
 
 bool MBEDEndpoint::initializeGPSReceiver(void *gps) {
     bool success = false;
     
     // initialize
     if (this->m_gps == NULL) this->m_gps = new MBEDUbloxGPS(this->logger(),(void *)this,gps);
     if (this->m_gps != NULL) success = this->m_gps->connect();
     
     // return our status
     return success;
 }
 #endif
 
 #ifndef CELLULAR_NETWORK
 // 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->init("192.168.1.220","255.255.255.0","192.168.1.1");
         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;
 }
 #endif
 
 // load up all personality instances into the IOC
 bool MBEDEndpoint::loadPersonalities() {
     bool success = true;
     this->logger()->log("Loading All Personalities into the IOC...");
     for(int i=0;i<NUM_PERSONALITY_INSTANCES && success;++i) success = this->loadPersonality(this->m_personalities[i]);
     return success;
 }
 
 // load up our personality to the IOC
 bool MBEDEndpoint::loadPersonality(Personality *instance) {      
     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("Building Payload for Personality(%s): %s...",instance->getType(),instance->getName());
          
     // build the personality payload
     char *data = ((IOCEndpoint *)this->getEndpoint())->buildLightPayload(payload,IOC_PAYLOAD_LEN,(Light *)instance);
      
     // issue the request
     if (data != NULL && strlen(data) > 0) {
        // DEBUG
        this->logger()->log("Sending Personality(%s): %s to the IOC...",instance->getType(),instance->getName());
     
        // load
        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 External ID if found
     if (success) ((IOCEndpoint *)this->getEndpoint())->saveExternalID(instance,result);
     
     // DEBUG
     if (success) this->logger()->log("Personality(%s): %s IOC ID=%d sent successfully",instance->getType(),instance->getName(),instance->getExternalID());
     
     // DEBUG
     if (!success) {
         if (instance != NULL) this->logger()->log("Personality(%s): %s send FAILED",instance->getType(),instance->getName());
         else this->logger()->log("Personality send FAILED: NULL Personality instance");
     }
     
     // return our status
     return success;
 }
 
 // update all personality instances into the IOC
 bool MBEDEndpoint::updatePersonalities() {
     bool success = true;
     for(int i=0;i<NUM_PERSONALITY_INSTANCES && success;++i) success = this->updatePersonality(i);
     return success;
 }
 
 // update all personality instances to the IOC
 bool MBEDEndpoint::updatePersonality(int index) {
     if (index >= 0 && index < NUM_PERSONALITY_INSTANCES) return this->updatePersonality(this->m_personalities[index]);
     return false; 
 }
 
 // update our ith personality instance with the IOC
 bool MBEDEndpoint::updatePersonality(Personality *instance) { 
     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 = ((IOCEndpoint *)this->getEndpoint())->buildLightPayload(payload,IOC_PAYLOAD_LEN,(Light *)instance);

     // issue the request  
     if (data != NULL && strlen(data) > 0) {
        // DEBUG
        this->logger()->log("Updating Personality(%s): %s at the IOC...",instance->getType(),instance->getName()); 
        
        // update
        success = this->m_transports[LOAD_TRANSPORT]->updateEndpoint(instance->getExternalID(),(char *)payload,strlen(payload),(char *)result,IOC_RESULT_LEN);
     }
     
     // DEBUG
     if (success) this->logger()->log("Update of Personality instance to IOC successful");
     else this->logger()->log("Update of Personality instance to IOC FAILED");
          
     // return our status
     return success; 
 } 
 
 // close down our personalities
 bool MBEDEndpoint::closePersonalities() {
    bool success = true;
    this->logger()->log("Closing down Personalities...");
    for(int i=0;i<NUM_PERSONALITY_INSTANCES;++i)
        if (this->m_personalities[i] != NULL) delete this->m_personalities[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;
 }
 
 #ifdef CELLULAR_NETWORK
 bool MBEDEndpoint::closeCellularModem() {
     bool success = true; 
     if (this->m_cellular_modem != NULL) success = this->m_cellular_modem->disconnect();
     return success;
 }
 
 bool MBEDEndpoint::closeGPSReceiver() {
     bool success = true; 
     if (this->m_gps != NULL) success = this->m_gps->disconnect();
     return success;
 }
 #endif
 
 #ifndef CELLULAR_NETWORK
 // close down our Ethernet 
 bool MBEDEndpoint::closeEthernet() {
     this->logger()->log("Closing down Ethernet...");
     if (this->m_ethernet != NULL) this->m_ethernet->disconnect();
     return true;
 }
 #endif
   
 // main running loop
 void MBEDEndpoint::run() {
     this->logger()->log("Endpoint Main Loop");
     while(true) {
         // sleep a bit
         //this->logger()->log("Sleeping for a bit...");
         Thread::wait(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();
         
         // do any extra event loop activities
         this->extraEventLoopWork();
     }
 }

 // do any extra work from within the event loop
 void MBEDEndpoint::extraEventLoopWork() {
    // check and send status reporting if enabled
 #if SF_STATUS_REPORTING
    if (this->m_status_reporter != NULL) {
        StatusReporter *status_reporter = (StatusReporter *)this->m_status_reporter;
        status_reporter->checkAndReportOnStatus();
    }
 #endif
 }