mbed based IoT Gateway More details http://blog.thiseldo.co.uk/wp-filez/IoTGateway.pdf
Dependencies: NetServices FatFileSystem csv_parser mbed MQTTClient RF12B DNSResolver SDFileSystem
main.cpp
- Committer:
- SomeRandomBloke
- Date:
- 2012-04-02
- Revision:
- 0:a29a0225f203
- Child:
- 2:27714c8c9c0a
File content as of revision 0:a29a0225f203:
/** IoT Gateway main code * * @author Andrew Lindsay * * @section LICENSE * * Copyright (c) 2012 Andrew Lindsay (andrew [at] thiseldo [dot] co [dot] uk) * * 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. * * @section DESCRIPTION * * Code is to be classed as beta. There is a lot of debug code still includes * to dump heap sizes and other values. It is still a work in progress and * should be treated as such. * * Sample configuration file IOTSETUP.TXT * * @code * pachube.key=***your pachube api key*** * ip.mode=fixed * ip.address=192.168.1.99 * ip.netmask=255.255.255.0 * ip.gateway=192.168.1.1 * ip.dns=192.168.1.1 * rfm12b.band=868 * rfm12b.id=30 * rfm12b.group=212 * time.timezone=GMT * time.dst=yes * mqtt.host= * mqtt.port= * @endcode * * Some values are not yet used * */ #include "mbed.h" #include "SDFileSystem.h" #include "EthernetNetIf.h" #include "NTPClient.h" #include "RF12B.h" #include "IoTRouting.h" using std::string; #define VERSION_INFO "IoT Gateway Basic - Version 0.4-BETA " DigitalOut heartbeatLED(LED1, "heartbeatLED"); DigitalOut led2(LED2, "led2"); DigitalOut led3(LED3, "led3"); //DigitalOut led4(LED4, "led4"); DigitalOut linkLED(p30, "linkLED"); DigitalOut statusLED(p25, "statusLED"); // Setup which filesystem to use, Local or uSD card __attribute((section("AHBSRAM0"))) LocalFileSystem fs("iotfs"); //__attribute((section("AHBSRAM0"))) SDFileSystem sd(p5, p6, p7, p8, "iotfs"); __attribute((section("AHBSRAM0"))) EthernetNetIf *eth; __attribute((section("AHBSRAM0"))) NTPClient ntp; __attribute((section("AHBSRAM0"))) Ethernet ethernet; // Configuration values loaded from file iotsetup.dat __attribute((section("AHBSRAM0"))) IpAddr ipAddress(0, 0, 0, 0); __attribute((section("AHBSRAM0"))) IpAddr netMask(255, 255, 255, 0); __attribute((section("AHBSRAM0"))) IpAddr gwAddress(0, 0, 0, 0); __attribute((section("AHBSRAM0"))) IpAddr dnsAddress(0, 0, 0, 0); __attribute((section("AHBSRAM0"))) bool useDHCP = false; // Static buffers #define MAX_LINE_LENGTH 128 __attribute__((section("AHBSRAM0"))) static char lineBuf[MAX_LINE_LENGTH]; __attribute__((section("AHBSRAM0"))) static OutputPachube outPachube; __attribute__((section("AHBSRAM0"))) static IoTRouting rtr; // Pachube config __attribute__((section("AHBSRAM0"))) static char pachubeApiKey[65]; // MQTT config __attribute((section("AHBSRAM0"))) IpAddr mqttHostAddress( 0, 0, 0, 0); //char mqttHostName[65]; // RFM12B config __attribute((section("AHBSRAM0"))) static string rfm12bBands[4] = {"xxx", "433", "868", "915" }; __attribute((section("AHBSRAM0"))) uint8_t rfm12bId; __attribute((section("AHBSRAM0"))) uint8_t rfm12bBand; __attribute((section("AHBSRAM0"))) uint8_t rfm12bGroup; #define iotConfigFile "/iotfs/IOTSETUP.TXT" #define startUrlFile "/iotfs/START.URL" __attribute((section("AHBSRAM0"))) RF12B rfm12b(p11, p12, p13, p14, p18); __attribute((section("AHBSRAM0"))) Serial pc(USBTX, USBRX); // tx, rx // Utility functions /** convert string to IP address * * @param ipAddrInt IP address as single 32bit integer * @param value The IP address as a string */ void setIpAddress( int *ipAddrInt, char *value ) { sscanf(value, "%d.%d.%d.%d", &ipAddrInt[0],&ipAddrInt[1],&ipAddrInt[2],&ipAddrInt[3]); } /** Get the value from a name=value pair * * @param buf The name/value pair character buffer * @returns pointer to value */ char *getConfigValue( char *buf ) { char *ptr = strchr(buf, '='); if ( ptr == NULL ) return NULL; ptr++; return ptr; } /** Copy zero or CR/LF terminated string to new zero terminated string * Used when reading config values from files to remove CR/LF endings * * @param to Char pointer to destination * @param from Char pointer to source */ void strcpynull(char *to, char *from ) { while ( *from != '\n' && *from != '\r' && *from != '\0' ) { *to++ = *from++; } *to = '\0'; } /** Read IoT gateway configuration file * File is of format name=value * */ bool readConfig() { FILE *fp = fopen(iotConfigFile, "r"); if (fp == NULL) { printf("Could not open file %s for read\n", iotConfigFile); return false; } // read file while (!feof( fp )) { fgets(lineBuf,MAX_LINE_LENGTH,fp); //printf("%s",lineBuf); // Need to read each entry and update config char *nameStr; char *valueStr; nameStr = lineBuf; valueStr = strchr( lineBuf, '=' ); if ( valueStr != NULL ) { *valueStr++ = '\0'; int tmpAddress[4] = {0,0,0,0}; if ( strcmp( nameStr, "ip.address" ) == 0 ) { setIpAddress( &tmpAddress[0], valueStr ); ipAddress = IpAddr( tmpAddress[0],tmpAddress[1],tmpAddress[2],tmpAddress[3]); } else if ( strcmp( nameStr, "ip.netmask" ) == 0 ) { setIpAddress( &tmpAddress[0], valueStr ); netMask = IpAddr( tmpAddress[0],tmpAddress[1],tmpAddress[2],tmpAddress[3]); } else if ( strcmp( nameStr, "ip.gateway" ) == 0 ) { setIpAddress( &tmpAddress[0], valueStr ); gwAddress = IpAddr( tmpAddress[0],tmpAddress[1],tmpAddress[2],tmpAddress[3]); } else if ( strcmp( nameStr, "ip.dns" ) == 0 ) { setIpAddress( &tmpAddress[0], valueStr ); dnsAddress = IpAddr( tmpAddress[0],tmpAddress[1],tmpAddress[2],tmpAddress[3]); } else if ( strcmp( nameStr, "pachube.key" ) == 0 ) { strcpynull(pachubeApiKey, valueStr ); } else if ( strcmp( nameStr, "ip.mode" ) == 0 ) { useDHCP = (strncmp( valueStr, "dhcp", 4) == 0 ? true : false); } else if ( strcmp( nameStr, "rfm12b.band" ) == 0 ) { if ( strncmp( valueStr, "433", 3 ) == 0 ) rfm12bBand = RF12_433MHZ; else if ( strncmp( valueStr, "868", 3 ) == 0 ) rfm12bBand = RF12_868MHZ; else if ( strncmp( valueStr, "915", 3 ) == 0 ) rfm12bBand = RF12_915MHZ; } else if ( strcmp( nameStr, "rfm12b.id" ) == 0 ) { rfm12bId = atoi( valueStr ); } else if ( strcmp( nameStr, "rfm12b.group" ) == 0 ) { rfm12bGroup = atoi( valueStr ); } } } fclose(fp); return true; } /** Write the current config to file */ bool writeConfig() { // Doesnt work? // Rename original file // if( rename ( iotConfigFile.c_str(), iotConfigFileBak.c_str() ) != 0 ) { // printf("Could not rename file %s\n", iotConfigFile); // return false; // } FILE *fp = fopen(iotConfigFile, "w"); if (fp == NULL) { printf("Could not open file %s for write\n", iotConfigFile); return false; } time_t ctTime; ctTime = time(NULL); fprintf(fp, "# iotsetup created (UTC) %s\n", ctime(&ctTime)); fprintf(fp, "pachube.key=%s\n", pachubeApiKey ); fprintf(fp, "ip.mode=%s\n", (useDHCP ? "dhcp" : "fixed") ); // Add msg to say net config being ignored if ( useDHCP ) fprintf(fp, "# Following ip.* parameters not used in DHCP mode\n"); fprintf(fp, "ip.address=%hhu.%hhu.%hhu.%hhu\n", ipAddress[0], ipAddress[1],ipAddress[2],ipAddress[3]); fprintf(fp, "ip.netmask=%hhu.%hhu.%hhu.%hhu\n",netMask[0], netMask[1], netMask[2], netMask[3]); fprintf(fp, "ip.gateway=%hhu.%hhu.%hhu.%hhu\n",gwAddress[0],gwAddress[1],gwAddress[2],gwAddress[3]); fprintf(fp, "ip.dns=%hhu.%hhu.%hhu.%hhu\n",dnsAddress[0],dnsAddress[1],dnsAddress[2],dnsAddress[3]); fprintf(fp, "rfm12b.band=%s\n",rfm12bBands[rfm12bBand].c_str()); fprintf(fp, "rfm12b.id=%d\n",rfm12bId); fprintf(fp, "rfm12b.group=%d\n",rfm12bGroup); fprintf(fp, "time.timezone=GMT\n"); fprintf(fp, "time.dst=yes\n"); fclose(fp); return true; } // These external symbols are maintained by the linker to indicate the // location of various regions in the device's memory. They will be used by // DisplayRAMBanks() to dump the size of each RAM bank to stdout. extern unsigned int Image$$RW_IRAM1$$Base; extern unsigned int Image$$RW_IRAM1$$ZI$$Limit; extern unsigned int Image$$RW_IRAM2$$Base; extern unsigned int Image$$RW_IRAM2$$ZI$$Limit; extern unsigned int Image$$RW_IRAM3$$Base; extern unsigned int Image$$RW_IRAM3$$ZI$$Limit; // Displays the size of static allocations for each RAM bank as indicated by // ARM linker to stdout. static void DisplayRAMBanks(void) { printf("Static RAM bank allocations\r\n"); printf(" Main RAM = %u\r\n", (unsigned int)&Image$$RW_IRAM1$$ZI$$Limit - (unsigned int)&Image$$RW_IRAM1$$Base); printf(" RAM0 = %u\r\n", (unsigned int)&Image$$RW_IRAM2$$ZI$$Limit - (unsigned int)&Image$$RW_IRAM2$$Base); printf(" RAM1 = %u\r\n", (unsigned int)&Image$$RW_IRAM3$$ZI$$Limit - (unsigned int)&Image$$RW_IRAM3$$Base); } /** Main function, where all the magic starts */ int main() { linkLED = 1; statusLED = 0; pc.baud(115200); printf(VERSION_INFO); printf("\n"); DisplayRAMBanks(); printf("Setting up...\n"); printf("\nHEAP STATS\n"); __heapstats((__heapprt)fprintf,stderr); if ( !readConfig() ) { error("Setup failed"); } if (useDHCP) { printf("Using DHCP\n"); eth = new EthernetNetIf( "IoTGateway" ); } else { // printf("Using Fixed addressing\n"); eth = new EthernetNetIf( ipAddress, netMask, gwAddress, dnsAddress ); } EthernetErr ethErr = eth->setup(); if (ethErr) { printf("Error %d in setup.\n", ethErr); return -1; } linkLED = !ethernet.link(); if (useDHCP) { // We are using dhcp so get IP Address ipAddress = eth->getIp(); } // Get Current time Host server(IpAddr(), 123, "0.uk.pool.ntp.org"); ntp.setTime(server); time_t ctTime = time(NULL); printf("\nTime is now (UTC): %s\n", ctime(&ctTime)); outPachube = OutputPachube(); outPachube.setApiKey( pachubeApiKey ); // IpAddr serverIpAddr(192,168,1,77); // OutputMqtt outMqtt = OutputMqtt(); // outMqtt.setHost( &serverIpAddr ); // printf("MAIN: outPachube = %ld\n",(int)&outPachube); rtr.addOutput( (OutputDef*)&outPachube , 1); // rtr.addOutput( (OutputDef*)&outMqtt , 2); rtr.initRouting(); printf("Setup OK\n"); printf( "Setting RFM12B ID %d, Band %d Group %d\n",rfm12bId, rfm12bBand, rfm12bGroup); rfm12b.init(rfm12bId, rfm12bBand, rfm12bGroup ); //id = 2, band 866, group 5 printf("Listening...\n"); Timer tm; tm.start(); printf("\nHEAP STATS\n"); __heapstats((__heapprt)fprintf,stderr); short dataLen = 0; uint8_t *rf12Buf; // Start receiving data rfm12b.rf12_recvStart(); while (true) { Net::poll(); // This is RFM12B specific if ( rfm12b.available() > 0 ) { statusLED = 1; rf12Buf = rfm12b.get_data(); dataLen = rfm12b.length(); if ( rtr.routePayload( rf12Buf, dataLen + 3 ) ) { // Successfully dealt with a packet // Do something different if routed } // For now, acknowledge everything // Send an ack if required if ((rf12Buf[1] & ~RF12_HDR_MASK) == RF12_HDR_ACK // && //(config.nodeId & 0x20) == 0 ) { printf("RFM12B -> ack\n"); byte addr = rf12Buf[1] & RF12_HDR_MASK; rfm12b.rf12_sendStart(RF12_HDR_CTL | RF12_HDR_DST | addr, 0, 1); } statusLED = 0; } if (tm.read()>.5) { heartbeatLED=!heartbeatLED; //Show that we are alive tm.start(); } linkLED = !ethernet.link(); } } // The End!