Rob Meades / Mbed 2 deprecated C027N_WaterMeterDemo

Dependencies:   C027_Support_N CIoT_MessagingCommon IapSupport WaterMeterSupport mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* Main application file for the device side of the
00002  * MWC demo 2015.
00003  *
00004  * Copyright (C) u-blox Melbourn Ltd
00005  * u-blox Melbourn Ltd, Melbourn, UK
00006  *
00007  * All rights reserved.
00008  *
00009  * This source file is the sole property of u-blox Melbourn Ltd.
00010  * Reproduction or utilization of this source in whole or part is
00011  * forbidden without the written consent of u-blox Melbourn Ltd.
00012  */
00013 
00014 #include "mbed.h"
00015 #include "IapApi.h"
00016 #include "MDM.h"
00017 #include "IotMeterApi.hpp"
00018 #include "WaterMeterApi.hpp"
00019 
00020 #define FILE_REV "Revision 1.0"
00021 #define FILE_CL  "Pushed by RobMeades"
00022 #define FILE_DATETIME "2015/05/15"
00023 
00024 // ----------------------------------------------------------------
00025 // GENERAL COMPILE-TIME CONSTANTS
00026 // ----------------------------------------------------------------
00027 
00028 // The time for which the flash turns the LED on or off for
00029 #define FLASH_DURATION_MS 250
00030 
00031 // The maximum number of datagrams that are available for use
00032 // at any one time (i.e. the total of send and receive)
00033 #define MAX_NUM_DATAGRAMS 10
00034 
00035 // The number of milliseconds to wait for a received message
00036 // after a send
00037 #define RECEIVE_DURATION_MS 1000
00038 
00039 // The number of seconds to wait for device registration
00040 #define WAIT_REG_S 300
00041 
00042 // The number of SOS flashes at an assert before restarting
00043 // if not in development mode; in development mode there
00044 // is no restart, just flashing forever
00045 #define NUM_ASSERT_SOS_BEFORE_RESTART 3
00046 
00047 // Baud rate of the PC interface
00048 //#define PC_BAUD_RATE 9600
00049 #define PC_BAUD_RATE 9600
00050 
00051 // The maximum length of a MACTEST string (as raw bytes)
00052 #define MACTEST_STRING_MAX_SIZE 48
00053 
00054 // The time to wait for a user to interrupt to change
00055 // the mactest string
00056 #define USER_WAIT_DECISECONDS 50
00057 
00058 // The size of the stack required by IAP
00059 #define SIZE_STACK_FOR_IAP 32
00060 
00061 // An ID for the NVRAM contents so that we
00062 // can tell if it's there.
00063 #define NVRAM_ID 0x12345678
00064 
00065 // NVRAM bytes to write (can be a set of fixed sizes, min 256)
00066 #define NVRAM_SIZE 256
00067 
00068 // Macro to convert to upper case
00069 #define TO_UPPER(x) (((x) >= 'a' && (x) <= 'z') ? x & ~0x20 : x)
00070 
00071 // Macro to tell is something is odd
00072 #define IS_ODD(x) (((x) & 0x01) == 0x01 ? true : false)
00073 
00074 // Macro to tell is something is even
00075 #define IS_EVEN(x) (((x) & 0x01) == 0x01 ? false : true)
00076 
00077 // Highlight for talking to the user at the PC side
00078 #define COLOUR_HIGHLIGHT "\033[33m"
00079 
00080 // Default colour
00081 #define COLOUR_DEFAULT "\033[39m"
00082 
00083 // ----------------------------------------------------------------
00084 // TYPES
00085 // ----------------------------------------------------------------
00086 
00087 /// A type to hold a datagram
00088 // Used for encoding AT commands on the send side and
00089 // receiving messages on the receive side.
00090 typedef struct DatagramTag_t
00091 {
00092     uint32_t size;
00093     char pBody[MAX_DATAGRAM_SIZE_RAW];
00094 } Datagram_t;
00095 
00096 /// A linked list entry holding a datagram
00097 typedef struct DatagramEntryTag_t
00098 {
00099     bool inUse;
00100     Datagram_t datagram;
00101     DatagramEntryTag_t * pPrevEntry;
00102     DatagramEntryTag_t * pNextEntry;
00103 
00104 } DatagramEntry_t;
00105 
00106 /// Debug flashes
00107 typedef enum DebugSosTypeTag_t
00108 {
00109     DEBUG_SOS_WATER_METER_PROBLEM = WAKE_UP_CODE_WATER_METER_PROBLEM,
00110     DEBUG_SOS_AT_COMMAND_PROBLEM = WAKE_UP_CODE_AT_COMMAND_PROBLEM,
00111     DEBUG_SOS_NETWORK_SEND_PROBLEM = WAKE_UP_CODE_NETWORK_SEND_PROBLEM,
00112     DEBUG_SOS_MEMORY_ALLOC_PROBLEM = WAKE_UP_CODE_MEMORY_ALLOC_PROBLEM,
00113     DEBUG_SOS_PROTOCOL_PROBLEM = WAKE_UP_CODE_PROTOCOL_PROBLEM,
00114     DEBUG_SOS_GENERIC_FAILURE = WAKE_UP_CODE_GENERIC_FAILURE,
00115     DEBUG_SOS_REBOOT = WAKE_UP_CODE_REBOOT,
00116 } DebugSosType_t;
00117 
00118 /// Context data, which will be in NVRAM
00119 // and must be no bigger than NVRAM_SIZE
00120 typedef struct NvContextTag_t
00121 {
00122     uint32_t id;                             //<! An ID for the NVRAM
00123     bool devModeOnNotOff;                    //<! Development mode
00124     WakeUpCode_t wakeUpCode;                 //<! Wake-up code
00125     uint32_t readingIntervalSeconds;         //<! The read interval
00126     bool ledOnNotOff;                        //<! The LED state
00127     bool flashOnNotOff;                      //<! The Flash state
00128     char mactestString[MACTEST_STRING_MAX_SIZE]; //<! The MACTEST string, only used with phase 1 modules
00129                                              //<! this is a string of bytes (so NOT the hex coded form)
00130                                              //<! and no terminator is stored
00131     uint32_t mactestStringSize;              //<! The size of the MACTEST string
00132 } NvContext_t;
00133 
00134 
00135 typedef union NvramTag_t
00136 {
00137     char rawBytes[NVRAM_SIZE];
00138     NvContext_t nvContext;
00139 } Nvram_t;
00140 
00141 // Note that order is important below: modules of newer phases
00142 // should be of higher values
00143 typedef enum ModulePhase_t
00144 {
00145     MODULE_PHASE_UNKNOWN,
00146     MODULE_PHASE_1,     //<! As used at Mobile World Congress Barcelona 2015
00147     MODULE_PHASE_2,    //<! As used at Mobile World Congress Shanghai 2015
00148     MODULE_PHASE_3
00149 } ModulePhase;
00150 
00151 // ----------------------------------------------------------------
00152 // PRIVATE VARIABLES
00153 // ----------------------------------------------------------------
00154 
00155 // Non-volatile storage area, aligned on a 4-byte boundary
00156 Nvram_t  __attribute__((aligned(4))) nvram;
00157 
00158 // Instantiate the NVRAM handling code
00159 static IAP iap;
00160 
00161 // Pointer to instance of the Neul modem, populated once we
00162 // get into main() as its constructor requires some initialisation
00163 // that is only complete on entry into main()
00164 MDMSerial *pgNeul = NULL;
00165 
00166 // Instantiate the interface to the water meter
00167 static WaterMeterHandler gWaterMeter;
00168 
00169 // Instantiate the messaging API to the C027N
00170 // as an IoT metering device
00171 static MessageCodec gMessageCodec;
00172 
00173 // The module phase
00174 static ModulePhase gModulePhase = MODULE_PHASE_UNKNOWN;
00175 
00176 // A good default MACTEST string
00177 static char defaultMactestString[] = {0x02, 0x00, 0x00, 0x00, 0x60, 0xb3, 0xc8, 0x37, 0x20, 0x0e, 0x1a, 0x35, 0x16, 0x00, 0x00, 0x00, 0x45, 0x23, 0x01, 0x00, 0x01, 0x02, 0x01, 0x00};
00178 
00179 // The LED
00180 static DigitalOut led(LED);
00181 static const int gpioTable[] = {D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13};
00182 
00183 // The connected GPIO(s)
00184 static DigitalOut pump((PinName) gpioTable[GPIO_WATER_PUMP]);
00185 
00186 // Head of free datagram linked list
00187 static DatagramEntry_t gFreeDatagramListHeadUnused;
00188 // Head of send datagram linked list
00189 static DatagramEntry_t gSendDatagramListHead;
00190 // Head of receive datagram linked list
00191 static DatagramEntry_t gRecvDatagramListHead;
00192 
00193 const char hexTable[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', \
00194                          '9', 'a', 'b', 'c', 'd', 'e', 'f'};
00195 
00196 // ----------------------------------------------------------------
00197 // GENERIC PRIVATE FUNCTION PROTOTYPES
00198 // ----------------------------------------------------------------
00199 
00200 static void doDebugFlash (uint32_t numberOfFlashes);
00201 static void debugSos(DebugSosType_t debugSosType);
00202 #ifdef DEBUG
00203   static void debugPrintLists (void);
00204 #endif
00205 static void getModulePhase (void);
00206 static bool isValidHex (char digit);
00207 static uint8_t hexToNibble (char digit);
00208 static uint8_t hexTobyte (char digit1, char digit2);
00209 static char peekChar (void);
00210 static char getChar (void);
00211 static uint32_t getUserHexString (uint32_t size, char * buf);
00212 static void printByteString (uint32_t size, const char * buf);
00213 static void printMactestString (uint32_t size, const char * string);
00214 static void configureModule (void);
00215 static void assert (bool condition, DebugSosType_t debugSosType, const char * pFormat, ...);
00216 static void assertAlways (DebugSosType_t debugSosType, const char * pFormat, ...);
00217 static bool writeNvContext (Nvram_t * pNvram);
00218 static NvContext_t * resetNvContext (void);
00219 static NvContext_t * readNvContext (void);
00220 static void doSendFlash (void);
00221 static void doRecvFlash (void);
00222 static bool setGpio (GpioState_t * pGpioState);
00223 static bool getGpio (GpioState_t * pGpioState);
00224 static void setWakeUpCode (WakeUpCode_t wakeUpCode);
00225 static void setDevMode (bool onNotOff);
00226 static void setReadingIntervalSeconds (uint32_t readingIntervalSeconds);
00227 static void setLed (bool onNotOff);
00228 static void setFlash (bool onNotOff);
00229 static bool init (void);
00230 static void deInit (void);
00231 static Datagram_t * allocDatagram (DatagramEntry_t * pDatagramListHead);
00232 static Datagram_t * allocSendDatagram (void);
00233 static Datagram_t * allocRecvDatagram (void);
00234 static void freeDatagram (Datagram_t *pDatagram, DatagramEntry_t * pDatagramListHead);
00235 static void freeRecvDatagram (Datagram_t *pDatagram);
00236 static void freeAllDatagrams (DatagramEntry_t *pDatagramListHead);
00237 static void freeUnusedDatagrams (DatagramEntry_t *pDatagramListHead);
00238 static void freeUnusedSendDatagrams (void);
00239 static void freeUnusedRecvDatagrams (void);
00240 static bool waitReg (uint32_t durationSeconds);
00241 static bool sendAndReceive (void);
00242 static bool queueInitialDatagram (void);
00243 static bool queuePeriodicDatagram (void);
00244 static bool handleSerialNumberGetReqDlMsg (void);
00245 static bool handleRebootReqDlMsg (bool devModeOnNotOff);
00246 static bool enqueueReadingIntervalSetGetCnfUlMsg (bool setNotGet);
00247 static bool handleReadingIntervalSetReqDlMsg (uint32_t readingIntervalSeconds);
00248 static bool handleReadingIntervalGetReqDlMsg (void);
00249 static bool enqueueGpioSetGetCnfUlMsg (bool setNotGet, GpioState_t * gpioState);
00250 static bool handleGpioSetReqDlMsg (GpioState_t * pGpioState);
00251 static bool handleGpioGetReqDlMsg (uint8_t gpio);
00252 static bool enqueueLedSetGetCnfUlMsg (bool setNotGet);
00253 static bool handleLedSetReqDlMsg (bool onNotOff);
00254 static bool handleLedGetReqDlMsg (void);
00255 static bool enqueueFlashSetGetCnfUlMsg (bool setNotGet);
00256 static bool handleFlashSetReqDlMsg (bool onNotOff);
00257 static bool handleFlashGetReqDlMsg (void);
00258 static bool processReceivedDatagrams (void);
00259 static MDMSerial *getMDMSerial(void);
00260 
00261 // ----------------------------------------------------------------
00262 // GENERIC PRIVATE FUNCTIONS
00263 // ----------------------------------------------------------------
00264 
00265 // Debug
00266 static void doDebugFlash (uint32_t numberOfFlashes)
00267 {
00268     uint32_t x;
00269     uint32_t y;
00270     bool devModeOnNotOff = readNvContext()->devModeOnNotOff;
00271 
00272     led = 0;
00273     wait_ms (1000);
00274     for (y = 0; (y < NUM_ASSERT_SOS_BEFORE_RESTART) | devModeOnNotOff; y++)
00275     {
00276         for (x = 0; x < numberOfFlashes; x++)
00277         {
00278             led = !led;
00279             wait_ms (FLASH_DURATION_MS);
00280             led = !led;
00281             wait_ms (FLASH_DURATION_MS);
00282         }
00283         wait_ms (2000);
00284     }
00285 
00286     // Restart the system and try again
00287     printf ("Resetting system...\n");
00288     wait_ms (2000);
00289     NVIC_SystemReset();
00290 
00291 }
00292 
00293 static void debugSos(DebugSosType_t debugSosType)
00294 {
00295     switch (debugSosType)
00296     {
00297         case (DEBUG_SOS_WATER_METER_PROBLEM):
00298         {
00299             doDebugFlash (3);
00300         }
00301         break;
00302         case (DEBUG_SOS_AT_COMMAND_PROBLEM):
00303         {
00304             doDebugFlash (4);
00305         }
00306         break;
00307         case (DEBUG_SOS_NETWORK_SEND_PROBLEM):
00308         {
00309             doDebugFlash (5);
00310         }
00311         break;
00312         case (DEBUG_SOS_MEMORY_ALLOC_PROBLEM):
00313         {
00314             doDebugFlash (6);
00315         }
00316         break;
00317         case (DEBUG_SOS_PROTOCOL_PROBLEM):
00318         {
00319             doDebugFlash (7);
00320         }
00321         break;
00322         case (DEBUG_SOS_GENERIC_FAILURE):
00323         {
00324             doDebugFlash (8);
00325         }
00326         break;
00327         case (DEBUG_SOS_REBOOT):
00328         {
00329             doDebugFlash (9);
00330         }
00331         break;
00332         default:
00333         {
00334             doDebugFlash (10);
00335         }
00336         break;
00337     }
00338 }
00339 
00340 /// Print out the datagram lists for debugging
00341 #ifdef DEBUG
00342 static void debugPrintLists (void)
00343 {
00344     uint32_t x;
00345     DatagramEntry_t * pEntry;
00346 
00347     printf ("LIST CONTENTS:\n");
00348 
00349     printf ("Free list head is at 0x%ld.\n", &gFreeDatagramListHeadUnused);
00350     pEntry = &gFreeDatagramListHeadUnused;
00351     for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
00352     {
00353         printf (" %d: prev 0x%lx, next 0x%lx, inUse 0x%x, datagram.size %d, datagram \"%s\".\n",
00354                 x, pEntry->pPrevEntry, pEntry->pNextEntry, pEntry->inUse, pEntry->datagram.size, pEntry->datagram.pBody);
00355         pEntry = pEntry->pNextEntry;
00356     }
00357 
00358     printf ("Send list head is at 0x%ld.\n", &gSendDatagramListHead);
00359     pEntry = &gSendDatagramListHead;
00360     for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
00361     {
00362         printf (" %d: prev 0x%lx, next 0x%lx, inUse 0x%x, datagram.size %d, datagram \"%s\".\n",
00363                 x, pEntry->pPrevEntry, pEntry->pNextEntry, pEntry->inUse, pEntry->datagram.size, pEntry->datagram.pBody);
00364         pEntry = pEntry->pNextEntry;
00365     }
00366 
00367     printf ("Recv list head is at 0x%ld.\n", &gRecvDatagramListHead);
00368     pEntry = &gRecvDatagramListHead;
00369     for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
00370     {
00371         printf (" %d: prev 0x%lx, next 0x%lx, inUse 0x%x, datagram.size %d, datagram \"%s\".\n",
00372                 x, pEntry->pPrevEntry, pEntry->pNextEntry, pEntry->inUse, pEntry->datagram.size, pEntry->datagram.pBody);
00373         pEntry = pEntry->pNextEntry;
00374     }
00375 }
00376 #endif
00377 
00378 // Set the phase of the module in a global variable
00379 static void getModulePhase (void)
00380 {
00381     char * pVersion = NULL;
00382 
00383     pVersion = pgNeul->getVersion();
00384 
00385     if (pVersion != NULL)
00386     {
00387         printf ("Version: \"%s\", so ", pVersion);
00388         if (strcmp(pVersion, "Neul CIoT Phase 2") == 0)
00389         {
00390             gModulePhase = MODULE_PHASE_2;
00391             printf ("module is MODULE_PHASE_2.\n");
00392         }
00393         else if (strcmp(pVersion, "Neul CIoT") == 0)
00394         {
00395             gModulePhase = MODULE_PHASE_1;
00396             printf ("module is MODULE_PHASE_1.\n");
00397         }
00398         else
00399         {
00400             printf ("module is MODULE_PHASE_UNKNOWN.\n");
00401         }
00402     }
00403 }
00404 
00405 #if 0
00406 // Convert to upper case
00407 // Not using this as found it didn't seem to work for the Chinese using their
00408 // terminal program.  Potential character set issues maybe?
00409 // Instead, please do a direct comparison against upper and lower case versions
00410 static char toUpper (char digit)
00411 {
00412     if (digit >= 'a' && digit <= 'z')
00413     {
00414         digit &= ~0x20;
00415     }
00416 
00417     return digit;
00418 }
00419 #endif
00420 
00421 // Return true if digit is a valid hex
00422 // character, otherwise false
00423 static bool isValidHex (char digit)
00424 {
00425     uint32_t x;
00426     bool isValid = false;
00427 
00428     for (x = 0; (x < sizeof (hexTable)) && !isValid; x++)
00429     {
00430         if (TO_UPPER(digit) == TO_UPPER(hexTable[x]))
00431         {
00432             isValid = true;
00433         }
00434     }
00435 
00436     return isValid;
00437 }
00438 
00439 // Take a hex nibble and convert to a byte.
00440 static uint8_t hexToNibble (char digit)
00441 {
00442     uint8_t nibbleValue = 0;
00443 
00444     digit = TO_UPPER (digit);
00445     if (isValidHex (digit))
00446     {
00447         if (digit >= '0' && digit <= '9')
00448         {
00449             nibbleValue = digit - '0';
00450         }
00451         else
00452         {
00453             if (digit >= 'A' && digit <= 'F')
00454             {
00455                 nibbleValue = digit - 'A' + 10;
00456             }
00457         }
00458     }
00459 
00460     return nibbleValue;
00461 }
00462 
00463 // Take a hex value made up of digit1 and digit2
00464 // and return the corresponding byte value.
00465 // So if digit1 were 'a' and digit2 '3' the hex value
00466 // would be 0xA3.  Invalid hex digits are ignored.
00467 static uint8_t hexTobyte (char digit1, char digit2)
00468 {
00469     return (hexToNibble (digit1) << 4) + hexToNibble (digit2);
00470 }
00471 
00472 // See if a character has been entered
00473 // at the PC serial port and return it,
00474 // or otherwise return 0.
00475 static char peekChar (void)
00476 {
00477     char input = 0;
00478     Serial pc (USBTX, USBRX);
00479 
00480     pc.baud (PC_BAUD_RATE);
00481 
00482     if (pc.readable())
00483     {
00484         input = pc.getc();
00485     }
00486 
00487     return input;
00488 }
00489 
00490 // Wait for a character to be entered
00491 // at the PC serial port and return it.
00492 static char getChar (void)
00493 {
00494     Serial pc (USBTX, USBRX);
00495 
00496     pc.baud (PC_BAUD_RATE);
00497 
00498     return pc.getc();
00499 }
00500 
00501 // Get a string of numbers from the user as a hex
00502 // string and store it as a string of bytes in buf
00503 // String entry is terminated with <enter>, which is
00504 // NOT stored with the string and also no
00505 // terminator is stored.
00506 // If characters that aren't a valid part of a hex
00507 // string are entered they will be ignored.
00508 static uint32_t getUserHexString (uint32_t size, char * buf)
00509 {
00510     char input;
00511     char hexChar1 = 0;
00512     bool done = false;
00513     uint32_t charCount = 0;
00514     uint32_t byteCount = 0;
00515     Serial pc (USBTX, USBRX);
00516 
00517     pc.baud (PC_BAUD_RATE);
00518 
00519     while (!done && (byteCount < size))
00520     {
00521         input = pc.getc();
00522         if (input == '\r')
00523         {
00524             done = true;
00525         }
00526         else
00527         {
00528             if (isValidHex(input))
00529             {
00530                 pc.putc(input);
00531                 if (IS_EVEN (charCount))
00532                 {
00533                     hexChar1 = input;
00534                 }
00535                 else
00536                 {
00537                     buf[byteCount] = hexTobyte(hexChar1, input);
00538                     byteCount++;
00539                 }
00540                 charCount++;
00541             }
00542         }
00543     }
00544 
00545     pc.putc('\n');
00546 
00547     return byteCount;
00548 }
00549 
00550 /// Print a byte string as hex
00551 static void printByteString (uint32_t size, const char * buf)
00552 {
00553     char hexBuf[MACTEST_STRING_MAX_SIZE * 2];
00554     uint32_t x = 0;
00555     uint32_t y = 0;
00556 
00557     for (x = 0; (x < size) && (y < sizeof (hexBuf)); x++)
00558     {
00559         hexBuf[y] = hexTable[(buf[x] >> 4) & 0x0f]; // upper nibble
00560         y++;
00561         if (y < sizeof (hexBuf))
00562         {
00563             hexBuf[y] = hexTable[buf[x] & 0x0f]; // lower nibble
00564             y++;
00565         }
00566     }
00567 
00568     printf ("%.*s", (int) y, hexBuf);
00569 }
00570 
00571 // Print out the AT+MACTEST string
00572 static void printMactestString (uint32_t size, const char * string)
00573 {
00574     if (size > 0)
00575     {
00576         printf ("The MACTEST string will be:\n");
00577         printf ("AT+MACTEST=%d,", (int) size);
00578         printByteString(size, string);
00579         printf ("\n");
00580     }
00581     else
00582     {
00583         printf ("No MACTEST string has been set.\n");
00584     }
00585 }
00586 
00587 // Enter transparent AT command mode until
00588 // CTRL-C is detected.
00589 static void transparentMode (void)
00590 {
00591     char input;
00592     bool done = false;
00593     Serial pc (USBTX, USBRX);
00594 
00595     pc.baud (PC_BAUD_RATE);
00596 
00597     while (!done)
00598     {
00599         // transfer data from pc to modem
00600         if (pc.readable() && pgNeul->writeable())
00601         {
00602             input = pc.getc();
00603             if (input == '\x03') // CTRL-C
00604             {
00605                 done = true;
00606             }
00607             else
00608             {
00609                 pc.putc (input); // echo
00610                 pgNeul->putc (input);
00611             }
00612         }
00613 
00614         // transfer data from modem to pc
00615         if (pgNeul->readable() && pc.writeable())
00616         {
00617             pc.putc (pgNeul->getc());
00618         }
00619     }
00620 }
00621 
00622 // User configuration of the module
00623 // Should only be called after the module has been initialised
00624 static void configureModule (void)
00625 {
00626     bool done = false;
00627     uint32_t x;
00628 
00629     printf ("%s\n", COLOUR_HIGHLIGHT);
00630     /* get the phase of the module */
00631     getModulePhase();
00632 
00633     printf ("\n");
00634     if (gModulePhase == MODULE_PHASE_UNKNOWN)
00635     {
00636         printf ("Phase of module SW unknown, skipping config...\n");
00637     }
00638     else
00639     {
00640         if (gModulePhase == MODULE_PHASE_1)
00641         {
00642             // Print out the AT+MACTEST command on the debug port and give the PC side
00643             // some time to change it
00644             printMactestString (readNvContext()->mactestStringSize, readNvContext()->mactestString);
00645             printf ("Press 'y' within 5 seconds to change this, 'n' to continue. \n");
00646         }
00647         else
00648         {
00649             printf ("Press 'y' within 5 seconds to enter AT command mode. \n");
00650         }
00651 
00652         for (x = 0; (x < USER_WAIT_DECISECONDS) && !done; x++)
00653         {
00654             char input;
00655             led = !led;
00656             wait_ms (100);
00657 
00658             input = peekChar();
00659 
00660             if (input != 0)
00661             {
00662                 printf ("You pressed '%c' (0x%x).\n", input, input);
00663             }
00664 
00665             if ((input == 'Y') || (input == 'y'))
00666             {
00667                 uint32_t y;
00668 
00669                 led = 1;
00670 
00671                 if (gModulePhase == MODULE_PHASE_1)
00672                 {
00673                     while (!done)
00674                     {
00675                         char string[MACTEST_STRING_MAX_SIZE];
00676 
00677                         printf ("\n");
00678                         printf ("Enter the new MACTEST string (just the part beyond the\n");
00679                         printf ("comma) and press <enter>, or just press <enter> to clear\n");
00680                         printf ("the current MACTEST string.  Backspace/delete will not work\n");
00681                         printf ("but you can check your entry, and try again, before it is\n");
00682                         printf ("committed: ");
00683                         y = getUserHexString (sizeof (string), string);
00684 
00685                         printf ("\n");
00686                         printMactestString (y, string);
00687 
00688                         printf ("\n");
00689                         printf ("Is this correct? Press 'y' to save it, 'n' to try again,\n");
00690                         printf ("any other key to continue without changes. ");
00691                         input = getChar();
00692                         printf ("\nYou pressed '%d'.\n", input);
00693                         if ((input == 'Y') || (input == 'y'))
00694                         {
00695                             printf ("Saving...\n");
00696                             nvram.nvContext.mactestStringSize = y;
00697                             memcpy (nvram.nvContext.mactestString, string, y);
00698                             writeNvContext (&nvram);
00699                             done = true;
00700                         }
00701                         else
00702                         {
00703                             if (input != 'N')
00704                             {
00705                                 printf ("OK, continuing...\n");
00706                                 done = true;
00707                             }
00708                         }
00709                     }
00710                 }
00711                 else
00712                 {
00713                     printf ("\n");
00714                     printf ("You are now in transparent AT command mode with the modem.\n");
00715                     printf ("Enter whatever commands are required to configure the modem\n");
00716                     printf ("and press CTRL-C to continue.\n");
00717                     transparentMode();
00718                     done = true;
00719                     printf ("\nContinuing...\n");
00720                 }
00721             }
00722             else
00723             {
00724                 if ((input == 'N') || (input == 'n'))
00725                 {
00726                     done = true;
00727                     printf ("OK, continuing...\n");
00728                 }
00729             }
00730        }
00731 
00732         if (x == USER_WAIT_DECISECONDS)
00733         {
00734             printf ("Timed out, no key-press detected...\n");
00735         }
00736 
00737         if ((gModulePhase == MODULE_PHASE_1) && (readNvContext()->mactestStringSize > 0))
00738         {
00739             // Send the mactest string to the module
00740             // No need to do anything for a phase 2 module SW as those values are stored
00741             // in NVRAM inside the module
00742             printf ("Sending the MACTEST string to the module...\n");
00743             if (pgNeul->sendMactest (readNvContext()->mactestStringSize, readNvContext()->mactestString))
00744             {
00745                 printf ("Done.\n");
00746             }
00747             else
00748             {
00749                 printf ("Module responded with ERROR.\n");
00750             }
00751         }
00752     }
00753 
00754     led = 0;
00755 
00756     printf (COLOUR_DEFAULT);
00757 }
00758 
00759 // Asserts
00760 static void assert (bool condition, DebugSosType_t debugSosType, const char * pFormat, ...)
00761 {
00762     if (!condition)
00763     {
00764         printf ("\n!!! ASSERT !!! ASSERT !!! ASSERT !!! ASSERT !!! ASSERT !!!\n");
00765         va_list args;
00766         va_start (args, pFormat);
00767         printf (pFormat, args);
00768         va_end (args);
00769         printf ("\n!!! ASSERT !!! ASSERT !!! ASSERT !!! ASSERT !!! ASSERT !!!\n\n\n");
00770         wait_ms (2000);
00771         setWakeUpCode ((WakeUpCode_t) debugSosType);
00772         debugSos (debugSosType);
00773     }
00774 }
00775 
00776 static void assertAlways (DebugSosType_t debugSosType, const char * pFormat, ...)
00777 {
00778     assert (false, debugSosType, pFormat);
00779 }
00780 
00781 /// Write to NVRAM, returning true if successful,
00782 // otherwise false.  The pointer pNvContext must be
00783 // on a 4 byte boundary and the structure size must
00784 // be a multiple of 4.
00785 static bool writeNvContext (Nvram_t * pNvram)
00786 {
00787     bool success = false;
00788     uint32_t iapResult;
00789 
00790 #ifdef DEBUG
00791     printf ("Writing structure at 0x%08x to NVRAM.\n", pNvram);
00792 #endif
00793     assert (((((uint32_t) pNvram) & 0x03) == 0), DEBUG_SOS_GENERIC_FAILURE, "pNvContext must be on a 4 byte boundary.");
00794     assert (((sizeof (pNvram->rawBytes) & 0x03) == 0), DEBUG_SOS_GENERIC_FAILURE, "sizeof (pNvram->rawBytes) must be a multiple of 4.");
00795 
00796     // Blank check: mbed erases all flash contents after downloading a new executable
00797     iapResult = iap.blank_check (FLASH_SECTOR (USER_FLASH_AREA_START), FLASH_SECTOR (USER_FLASH_AREA_START));
00798 #ifdef DEBUG
00799     printf ("NVRAM: blank check result = 0x%x\n", iapResult);
00800 #endif
00801 
00802     // Erase sector, if required
00803     if (iapResult == SECTOR_NOT_BLANK)
00804     {
00805         iap.prepare (FLASH_SECTOR (USER_FLASH_AREA_START), FLASH_SECTOR (USER_FLASH_AREA_START));
00806         iapResult = iap.erase (FLASH_SECTOR (USER_FLASH_AREA_START), FLASH_SECTOR (USER_FLASH_AREA_START));
00807 #ifdef DEBUG
00808         printf ("NVRAM: erase result = 0x%x\n", iapResult);
00809 #endif
00810     }
00811 
00812     // Copy RAM to Flash
00813     iap.prepare (FLASH_SECTOR (USER_FLASH_AREA_START), FLASH_SECTOR (USER_FLASH_AREA_START));
00814     iapResult = iap.write (&(pNvram->rawBytes[0]), sector_start_adress[FLASH_SECTOR (USER_FLASH_AREA_START)], sizeof (pNvram->rawBytes));
00815 #ifdef DEBUG
00816     printf ("NVRAM: copied: SRAM (0x%08x) -> Flash (0x%08x), %d bytes, result = 0x%x\n", pNvram, sector_start_adress[FLASH_SECTOR (USER_FLASH_AREA_START)], sizeof (*pNvram), iapResult);
00817 #endif
00818 
00819     // Compare
00820     iapResult = iap.compare (&(pNvram->rawBytes[0]), sector_start_adress[FLASH_SECTOR (USER_FLASH_AREA_START)], sizeof (pNvram->rawBytes));
00821     printf ("NVRAM: compare result = \"%s\"\n", iapResult ? "FAILED" : "OK" );
00822     if (iapResult == CMD_SUCCESS)
00823     {
00824         success = true;
00825     }
00826 
00827     return success;
00828 }
00829 
00830 /// Write defaults to NVRAM and return
00831 // a pointer to the reset contents.
00832 static NvContext_t * resetNvContext (void)
00833 {
00834     printf ("*** Resetting NVRAM to defaults.\n");
00835 
00836     nvram.nvContext.id = NVRAM_ID;
00837     nvram.nvContext.devModeOnNotOff = false;
00838     nvram.nvContext.wakeUpCode = WAKE_UP_CODE_OK;
00839     nvram.nvContext.readingIntervalSeconds = DEFAULT_READING_INTERVAL_SECONDS;
00840     nvram.nvContext.flashOnNotOff = true;
00841     nvram.nvContext.ledOnNotOff = false;
00842     memcpy (nvram.nvContext.mactestString, defaultMactestString, sizeof (defaultMactestString));
00843     nvram.nvContext.mactestStringSize = sizeof (defaultMactestString);
00844 
00845     // Ignore the return value - must always return an answer
00846     writeNvContext (&nvram);
00847 
00848     return &(nvram.nvContext);
00849 }
00850 
00851 /// Read from NVRAM, always guaranteed to produce
00852 // a result (may be default values).
00853 static NvContext_t * readNvContext (void)
00854 {
00855     NvContext_t * pNvContext = NULL;
00856     uint32_t iapResult;
00857 
00858     // Blank check
00859     iapResult = iap.blank_check (FLASH_SECTOR (USER_FLASH_AREA_START), FLASH_SECTOR (USER_FLASH_AREA_START));
00860 
00861     if (iapResult == SECTOR_NOT_BLANK)
00862     {
00863         if (nvram.nvContext.id != NVRAM_ID)
00864         {
00865 #ifdef DEBUG
00866             printf ("Loading NVRAM...\n");
00867 #endif
00868             memcpy (&(nvram.rawBytes[0]), (const char *) USER_FLASH_AREA_START, sizeof (nvram.rawBytes));
00869         }
00870 
00871         if (nvram.nvContext.id == NVRAM_ID)
00872         {
00873             // Contents are valid
00874             pNvContext = &(nvram.nvContext);
00875         }
00876         else
00877         {
00878 #ifdef DEBUG
00879             printf ("NVRAM contents invalid.\n");
00880             // Contents are not valid so set them up
00881 #endif
00882             pNvContext = resetNvContext ();
00883         }
00884     }
00885     else
00886     {
00887 #ifdef DEBUG
00888         printf ("NVRAM blank.\n");
00889 #endif
00890         // Contents are not there so set them up
00891         pNvContext = resetNvContext ();
00892     }
00893 
00894     return pNvContext;
00895 }
00896 
00897 /// Do the flash thing, should be called on a Send
00898 static void doSendFlash (void)
00899 {
00900     if (readNvContext()->flashOnNotOff)
00901     {
00902         led = !led;
00903         wait_ms (FLASH_DURATION_MS);
00904         led = !led;
00905     }
00906 }
00907 
00908 /// Do the other flash thing, should be called on a Receive
00909 static void doRecvFlash (void)
00910 {
00911     if (readNvContext()->flashOnNotOff)
00912     {
00913         led = !led;
00914         wait_ms (FLASH_DURATION_MS /4);
00915         led = !led;
00916         wait_ms (FLASH_DURATION_MS /4);
00917         led = !led;
00918         wait_ms (FLASH_DURATION_MS /4);
00919         led = !led;
00920     }
00921 }
00922 
00923 /// Set the state of a GPIO
00924 static bool setGpio (GpioState_t * pGpioState)
00925 {
00926     bool success = false;
00927 
00928     if (pGpioState->gpio < (sizeof (gpioTable) / sizeof (gpioTable[0])))
00929     {
00930         if (pGpioState->inputNotOutput)
00931         {
00932             DigitalIn((PinName) gpioTable[pGpioState->gpio]);
00933         }
00934         else
00935         {
00936             DigitalOut * pOutput = new DigitalOut((PinName) gpioTable[pGpioState->gpio]);
00937             *pOutput = pGpioState->onNotOff;
00938         }
00939         success = true;
00940     }
00941 
00942     return success;
00943 }
00944 
00945 /// Get the state of a GPIO
00946 static bool getGpio (GpioState_t * pGpioState)
00947 {
00948     bool success = false;
00949 
00950     if (pGpioState->gpio < (sizeof (gpioTable) / sizeof (gpioTable[0])))
00951     {
00952         if (pGpioState->inputNotOutput)
00953         {
00954             DigitalIn *pInput = new DigitalIn((PinName) gpioTable[pGpioState->gpio]);
00955             pGpioState->onNotOff = *pInput;
00956         }
00957         else
00958         {
00959             DigitalOut *pOutput = new DigitalOut((PinName) gpioTable[pGpioState->gpio]);
00960             pGpioState->onNotOff = *pOutput;
00961         }
00962         success = true;
00963     }
00964 
00965     return success;
00966 }
00967 
00968 /// Set the wake-up code
00969 static void setWakeUpCode (WakeUpCode_t wakeUpCode)
00970 {
00971     if (nvram.nvContext.wakeUpCode != wakeUpCode)
00972     {
00973         nvram.nvContext.id = NVRAM_ID;
00974         nvram.nvContext.wakeUpCode = wakeUpCode;
00975         writeNvContext (&nvram);
00976     }
00977 }
00978 
00979 /// Set development mode
00980 static void setDevMode (bool onNotOff)
00981 {
00982     if (nvram.nvContext.devModeOnNotOff != onNotOff)
00983     {
00984         nvram.nvContext.id = NVRAM_ID;
00985         nvram.nvContext.devModeOnNotOff = onNotOff;
00986         writeNvContext (&nvram);
00987     }
00988 }
00989 
00990 /// Set the reading interval in seconds
00991 static void setReadingIntervalSeconds (uint32_t readingIntervalSeconds)
00992 {
00993     if (nvram.nvContext.readingIntervalSeconds != readingIntervalSeconds)
00994     {
00995         nvram.nvContext.id = NVRAM_ID;
00996         nvram.nvContext.readingIntervalSeconds = readingIntervalSeconds;
00997         writeNvContext (&nvram);
00998     }
00999 }
01000 
01001 /// Set the LED state
01002 static void setLed (bool onNotOff)
01003 {
01004     if (nvram.nvContext.ledOnNotOff != onNotOff)
01005     {
01006         nvram.nvContext.id = NVRAM_ID;
01007         nvram.nvContext.ledOnNotOff = onNotOff;
01008         writeNvContext (&nvram);
01009     }
01010     led = nvram.nvContext.ledOnNotOff;
01011 }
01012 
01013 /// Set the Flash state
01014 static void setFlash (bool onNotOff)
01015 {
01016     if (nvram.nvContext.flashOnNotOff != onNotOff)
01017     {
01018         nvram.nvContext.id = NVRAM_ID;
01019         nvram.nvContext.flashOnNotOff = onNotOff;
01020         writeNvContext (&nvram);
01021     }
01022 }
01023 
01024 /// Initialise ourselves
01025 static bool init (void)
01026 {
01027     bool success = true;
01028     uint32_t x;
01029     GpioState_t waterPumpGpio = {GPIO_WATER_PUMP, false, false};
01030     DatagramEntry_t * pPrevEntry = &gFreeDatagramListHeadUnused;
01031     DatagramEntry_t ** ppEntry = &(gFreeDatagramListHeadUnused.pNextEntry);
01032 
01033     memset (&gFreeDatagramListHeadUnused, 0, sizeof (gFreeDatagramListHeadUnused));
01034     memset (&gSendDatagramListHead, 0, sizeof (gSendDatagramListHead));
01035     memset (&gRecvDatagramListHead, 0, sizeof (gRecvDatagramListHead));
01036 
01037     // Create a malloc()ed free list attached to the (unused) static
01038     // head of the free list
01039     for (x = 1; (x < MAX_NUM_DATAGRAMS) && success; x++)  // from 1 as it's from head.pNextEntry onwards
01040     {
01041         *ppEntry = (DatagramEntry_t *) malloc (sizeof (DatagramEntry_t));
01042         if (*ppEntry != NULL)
01043         {
01044             memset (*ppEntry, 0, sizeof (**ppEntry));
01045             // Link it in
01046             (*ppEntry)->pPrevEntry = pPrevEntry;
01047             (*ppEntry)->pNextEntry = NULL;
01048             (*ppEntry)->inUse = false;
01049             if (pPrevEntry != NULL)
01050             {
01051                 pPrevEntry->pNextEntry = *ppEntry;
01052             }
01053             pPrevEntry = *ppEntry;
01054 
01055             // Next
01056             ppEntry = &((*ppEntry)->pNextEntry);
01057         }
01058         else
01059         {
01060             assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "failed malloc().");
01061             success = false;
01062         }
01063     }
01064 
01065 #ifdef DEBUG
01066     debugPrintLists ();
01067 #endif
01068 
01069     if (success)
01070     {
01071         /* set the water pump control pin to an output and to off */
01072         success = setGpio (&waterPumpGpio);
01073         assert (success, DEBUG_SOS_GENERIC_FAILURE, "failed to set water pump pin.");
01074 
01075         if (success)
01076         {
01077             // Check NVRAM
01078             printf ("\n=== IAP: NVRAM check ===\n");
01079             printf ("  device-ID = 0x%08x\n", iap.read_ID());
01080             printf ("  serial# = 0x%08x\n", iap.read_serial());
01081             printf ("  CPU running at %ld MHz\n", SystemCoreClock / 1000000);
01082             printf ("  user reserved flash area: start_address = 0x%08lx\n", (long unsigned int) iap.reserved_flash_area_start());
01083             printf ("                            size = %d bytes\n", iap.reserved_flash_area_size());
01084             printf ("  read_BootVer = 0x%08x\n", iap.read_BootVer());
01085             printf ("  local ID value = 0x%08lx\n", readNvContext()->id);
01086 
01087             // And finally, setup the LED.
01088             led = readNvContext()->ledOnNotOff;
01089         }
01090     }
01091 
01092     return success;
01093 }
01094 
01095 /// Tidy up
01096 static void deInit (void)
01097 {
01098     uint32_t x = 0;
01099     DatagramEntry_t * pEntry = NULL;
01100 
01101     // Return send datagram memory to the free list
01102     freeAllDatagrams (&gSendDatagramListHead);
01103     // Return receive datagram memory to the free list
01104     freeAllDatagrams (&gRecvDatagramListHead);
01105 
01106     // Free the free list from the end
01107     pEntry = &gFreeDatagramListHeadUnused;
01108     for (x = 0; (pEntry->pNextEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
01109     {
01110         pEntry = pEntry->pNextEntry;
01111     }
01112     for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
01113     {
01114         DatagramEntry_t * pNextOne = pEntry->pPrevEntry;
01115         free (pEntry);
01116         pEntry = pNextOne;
01117     }
01118 }
01119 
01120 /// Allocate room for a datagram from the given list, returning a pointer
01121 // to it or NULL if unsuccessful
01122 static Datagram_t * allocDatagram (DatagramEntry_t * pDatagramListHead)
01123 {
01124     Datagram_t * pAlloc = NULL;
01125     uint32_t x = 0;
01126     DatagramEntry_t * pEntry;
01127 
01128     // If there is already an unused entry in the list, just return it
01129     pEntry = pDatagramListHead;
01130     for (x = 0; (pEntry != NULL) && (pEntry->inUse) && (x < MAX_NUM_DATAGRAMS); x++)
01131     {
01132         pEntry = pEntry->pNextEntry;
01133     }
01134 
01135     if ((pEntry != NULL) && (!pEntry->inUse))
01136     {
01137 #ifdef DEBUG
01138         printf ("allocDatagram: found existing unused entry in list.\n");
01139 #endif
01140         // Good, use this one
01141         memset (&(pEntry->datagram), 0, sizeof (pEntry->datagram));
01142         pEntry->inUse = true;
01143         pAlloc = &(pEntry->datagram);
01144     }
01145     else
01146     {
01147 #ifdef DEBUG
01148         printf ("allocDatagram: finding malloc()ed entry in the free list...\n");
01149 #endif
01150         // Find the malloc()ed entry at the end of the free list
01151         pEntry = &gFreeDatagramListHeadUnused;
01152         for (x = 0; (pEntry->pNextEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
01153         {
01154             pEntry = pEntry->pNextEntry;
01155         }
01156 
01157         // If there is one, move it to the given list
01158         if ((pEntry != NULL) && (pEntry->pNextEntry == NULL) && pEntry != &gFreeDatagramListHeadUnused)
01159         {
01160             DatagramEntry_t * pWantedEntry = pEntry;
01161 
01162             // Unlink it from the end of the free list
01163             if (pWantedEntry->pPrevEntry != NULL)
01164             {
01165                 pWantedEntry->pPrevEntry->pNextEntry = pWantedEntry->pNextEntry;
01166                 pWantedEntry->pPrevEntry = NULL;
01167             }
01168 
01169             // Attach it to the end of the given list
01170             pEntry = pDatagramListHead;
01171             for (x = 0; (pEntry->pNextEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
01172             {
01173                 pEntry = pEntry->pNextEntry;
01174             }
01175 
01176             if (pEntry->pNextEntry == NULL)
01177             {
01178                 pEntry->pNextEntry = pWantedEntry;
01179                 pWantedEntry->pPrevEntry = pEntry;
01180                 pWantedEntry->inUse = true;
01181                 pAlloc = &(pWantedEntry->datagram);
01182             }
01183             else
01184             {
01185                 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "allocDatagram: failed to find end of list (x = %d).", x);
01186             }
01187         }
01188         else
01189         {
01190             assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "allocDatagram: failed to find malloc()ed entry in free list (x = %d).", x);
01191         }
01192 
01193     }
01194 
01195     return pAlloc;
01196 }
01197 
01198 /// Allocate room for a send datagram, returning a pointer
01199 // to it or to NULL if unsuccessful
01200 static Datagram_t * allocSendDatagram (void)
01201 {
01202     return allocDatagram (&gSendDatagramListHead);
01203 }
01204 
01205 /// Allocate room for a receive datagram, returning a pointer
01206 // to it or to NULL if unsuccessful
01207 static Datagram_t * allocRecvDatagram (void)
01208 {
01209     return allocDatagram (&gRecvDatagramListHead);
01210 }
01211 
01212 /// Free a datagram from the given list
01213 static void freeDatagram (Datagram_t *pDatagram, DatagramEntry_t * pDatagramListHead)
01214 {
01215     uint32_t x = 0;
01216     DatagramEntry_t * pEntry;
01217 
01218     if (pDatagram != NULL)
01219     {
01220 #ifdef DEBUG
01221         printf ("Freeing a datagram (at 0x%lx)...\n", pDatagram);
01222 #endif
01223         // Find the entry in the list
01224         pEntry = pDatagramListHead;
01225         for (x = 0; (pEntry != NULL) && (&(pEntry->datagram) != pDatagram) && (x < MAX_NUM_DATAGRAMS); x++)
01226         {
01227             pEntry = pEntry->pNextEntry;
01228         }
01229 
01230         if ((pEntry != NULL) && (&(pEntry->datagram) == pDatagram))
01231         {
01232             DatagramEntry_t * pWantedEntry = pEntry;
01233 
01234 #ifdef DEBUG
01235             printf ("Found the datagram.\n");
01236 #endif
01237             // Found it, mark it as not in use and, if it is a malloc()ed
01238             // entry, unlink it from the current list and move it to the
01239             // free list
01240             pWantedEntry->inUse = false;
01241             memset (&(pWantedEntry->datagram), 0, sizeof (pWantedEntry->datagram));
01242             if (pWantedEntry != pDatagramListHead)
01243             {
01244 #ifdef DEBUG
01245                 printf ("freeDatagram: moving malloc()ed entry to free list.\n");
01246 #endif
01247                 if (pWantedEntry->pPrevEntry != NULL)
01248                 {
01249                     pWantedEntry->pPrevEntry->pNextEntry = pWantedEntry->pNextEntry;
01250                     pWantedEntry->pPrevEntry = NULL;
01251                 }
01252                 if (pWantedEntry->pNextEntry != NULL)
01253                 {
01254                     pWantedEntry->pNextEntry->pPrevEntry = pWantedEntry->pPrevEntry;
01255                     pWantedEntry->pNextEntry = NULL;
01256                 }
01257 
01258                 // Find the end of the free list
01259                 pEntry = &gFreeDatagramListHeadUnused;
01260                 for (x = 0; (pEntry->pNextEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
01261                 {
01262                     pEntry = pEntry->pNextEntry;
01263                 }
01264 
01265                 // Link it there
01266                 if (pEntry->pNextEntry == NULL)
01267                 {
01268                     pEntry->pNextEntry = pWantedEntry;
01269                     pWantedEntry->pPrevEntry = pEntry;
01270                 }
01271                 else
01272                 {
01273                     assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "freeDatagram: failed to find end of free list (x = %d).", x);
01274                 }
01275             }
01276 #ifdef DEBUG
01277             else
01278             {
01279                 printf ("freeDatagram: just marking head entry as unused.\n");
01280             }
01281 #endif
01282         }
01283         else
01284         {
01285             assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM,
01286                           "freeDatagram: couldn't find entry in list (pDatagram = 0x%lx, gDatagramListHead = 0x%lx, x = %d).",
01287                           pDatagram, pDatagramListHead, x);
01288         }
01289     }
01290     else
01291     {
01292         assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "freeDatagram: NULL pointer passed in.");
01293     }
01294 }
01295 
01296 /// Free a specific datagram from the receive list
01297 static void freeRecvDatagram (Datagram_t *pDatagram)
01298 {
01299     freeDatagram (pDatagram, &gRecvDatagramListHead);
01300 }
01301 
01302 // Empty a datagram list (either send or receive)
01303 static void freeAllDatagrams (DatagramEntry_t *pDatagramListHead)
01304 {
01305     uint32_t x;
01306     DatagramEntry_t * pEntry = NULL;
01307 
01308     pEntry = pDatagramListHead;
01309     for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
01310     {
01311         pEntry->inUse = false;
01312         pEntry = pEntry->pNextEntry;
01313     }
01314 
01315     freeUnusedDatagrams(pDatagramListHead);
01316 }
01317 
01318 /// Free unused datagrams from the send or receive lists
01319 static void freeUnusedDatagrams (DatagramEntry_t *pDatagramListHead)
01320 {
01321     uint32_t x = 0;
01322     DatagramEntry_t * pEntry = NULL;
01323 
01324     if ((pDatagramListHead != NULL) && (pDatagramListHead != &gFreeDatagramListHeadUnused))
01325     {
01326         // Go to the end of the list
01327         pEntry = pDatagramListHead;
01328         for (x = 0; (pEntry->pNextEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
01329         {
01330             pEntry = pEntry->pNextEntry;
01331         }
01332 
01333         if ((pEntry != NULL) && (pEntry->pNextEntry == NULL))
01334         {
01335             // Now work backwards up the list freeing unused things until we get
01336             // to the head
01337             for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
01338             {
01339                 DatagramEntry_t * pNextOne = pEntry->pPrevEntry;
01340                 // Check that this entry is unused and not the first static entry then,
01341                 // if it is, free it
01342                 if ((!(pEntry->inUse)) && (pEntry != pDatagramListHead))
01343                 {
01344                     freeDatagram (&(pEntry->datagram), pDatagramListHead);
01345 #ifdef DEBUG
01346                     printf ("freeUnusedDatagrams: freeing an entry.\n");
01347 #endif
01348                 }
01349                 pEntry = pNextOne;
01350             }
01351         }
01352         else
01353         {
01354             assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "freeUnusedDatagrams : failed to find end of list (x = %d).", x);
01355         }
01356     }
01357     else
01358     {
01359         assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "freeUnusedDatagrams: NULL or free list head pointer passed in (== 0x%lx).", pDatagramListHead);
01360     }
01361 }
01362 
01363 /// Free unused datagrams from the send list
01364 static void freeUnusedSendDatagrams (void)
01365 {
01366     freeUnusedDatagrams (&gSendDatagramListHead);
01367 }
01368 
01369 /// Free unused datagrams from the receive list
01370 static void freeUnusedRecvDatagrams (void)
01371 {
01372     freeUnusedDatagrams (&gRecvDatagramListHead);
01373 }
01374 
01375 /// Wait for the device to register on the network
01376 static bool waitReg (uint32_t durationSeconds)
01377 {
01378     uint32_t count = 0;
01379     bool success = false;
01380 
01381     while (!success && (count < durationSeconds))
01382     {
01383         success = pgNeul->checkNetStatus (NULL);
01384         wait_ms (1000);
01385         count++;
01386     }
01387 
01388     return success;
01389 }
01390 
01391 /// Do Sending (working through the inUse datagrams in the Send queue) and
01392 // then a Receive of a single datagram (putting it in the Receive queue).
01393 // \return true if the send was successful, otherwise false.
01394 static bool sendAndReceive (void)
01395 {
01396     bool success = true; // Set to true as otherwise will fail if there's nothing to send
01397     uint32_t x;
01398     DatagramEntry_t * pEntry;
01399     Datagram_t *pRecvDatagram;
01400     bool somethingInRxQueue = false;
01401 
01402 #ifdef DEBUG
01403     printf ("\nSending datagram(s)...\n");
01404 #endif
01405     // Do the sending first
01406     pEntry = &gSendDatagramListHead;
01407     for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS) && success; x++)
01408     {
01409         if (pEntry->inUse)
01410         {
01411             success = false;
01412             printf ("\nSending datagram %ld...\n", x);
01413             // Send the datagram.
01414             if (pgNeul != NULL)
01415             {
01416                 success = pgNeul->datagramSend (pEntry->datagram.size, pEntry->datagram.pBody);
01417             }
01418 
01419             if (success)
01420             {
01421                 doSendFlash();
01422                 printf ("Sent.\n");
01423             }
01424             else
01425             {
01426                 assertAlways (DEBUG_SOS_NETWORK_SEND_PROBLEM, "Couldn't send datagram.");
01427             }
01428 
01429             // Lose it always, don't want to clog up
01430             pEntry->inUse = false;
01431         }
01432         pEntry = pEntry->pNextEntry; // Move to the next entry
01433     }
01434 
01435     freeUnusedSendDatagrams();
01436 
01437     // Now the receiving
01438     do
01439     {
01440         somethingInRxQueue = false;
01441         pRecvDatagram = allocRecvDatagram ();
01442         if (pRecvDatagram != NULL)
01443         {
01444 #ifdef DEBUG
01445             printf ("Checking for downlink...\n");
01446 #endif
01447             pRecvDatagram->size = sizeof (pRecvDatagram->pBody);
01448             // Don't check the return value here (as we don't want to fail
01449             // if nothing has been received) check the size returned instead
01450             if (pgNeul != NULL)
01451             {
01452                 somethingInRxQueue  = pgNeul->datagramRecv ((int *) &(pRecvDatagram->size), pRecvDatagram->pBody, RECEIVE_DURATION_MS);
01453             }
01454             // If something was received say so, otherwise free the buffer
01455             if (somethingInRxQueue && (pRecvDatagram->size > 0))
01456             {
01457                 doRecvFlash ();
01458                 printf ("A datagram was received.\n");
01459             }
01460             else
01461             {
01462                 freeRecvDatagram (pRecvDatagram);
01463             }
01464         }
01465         else
01466         {
01467             assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate a datagram for receive.");
01468         }
01469     }
01470     while (somethingInRxQueue);
01471 
01472     return success;
01473 }
01474 
01475 /// Prepare an InitInd, plus a SerialNumberInd.
01476 // \param indNotCnf  if true encode an initInt, else encode an initCnf
01477 // \return true if the preparation was successful, otherwise false.
01478 static bool queueInitialDatagram (void)
01479 {
01480     bool success = false;
01481     InitIndUlMsg_t initIndUlMsg;
01482     SerialNumberIndUlMsg_t serialNumberIndUlMsg;
01483     Datagram_t * pDatagram;
01484     uint32_t bytesEncoded = 0;
01485 
01486     printf ("\nPreparing initial datagram...\n");
01487 
01488     pDatagram = allocSendDatagram();
01489     if (pDatagram != NULL)
01490     {
01491         printf ("Reading serial number from water meter...\n");
01492         // Read the serial number from the water meter
01493         gWaterMeter.readSerialNumber (&(serialNumberIndUlMsg.serialNumber));
01494         // Ignore the return value and just set success == true so that the code
01495         // can run without a water meter attached.
01496         success = true;
01497         if (success)
01498         {
01499             printf ("Serial number is %ld.\n", serialNumberIndUlMsg.serialNumber);
01500 
01501             // Encode the InitInd and SerialNumberInd messages into a datagram
01502             printf ("Encoding datagram...\n");
01503 
01504             // Set up the InitInd contents
01505             initIndUlMsg.wakeUpCode = readNvContext()->wakeUpCode;
01506             printf ("Wake-up code is 0x%x.\n", initIndUlMsg.wakeUpCode);
01507 
01508             setWakeUpCode (WAKE_UP_CODE_OK);
01509             bytesEncoded += gMessageCodec.encodeInitIndUlMsg (&(pDatagram->pBody[bytesEncoded]), &initIndUlMsg);
01510             bytesEncoded += gMessageCodec.encodeSerialNumberIndUlMsg (&(pDatagram->pBody[bytesEncoded]), &serialNumberIndUlMsg);
01511             pDatagram->size = bytesEncoded;
01512         }
01513         else
01514         {
01515             assertAlways (DEBUG_SOS_WATER_METER_PROBLEM, "Failed to read serial number from water meter.");
01516         }
01517     }
01518     else
01519     {
01520         assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate send datagram.");
01521     }
01522 
01523     return success;
01524 }
01525 
01526 /// Prepare the periodic datagram.
01527 // \return true if the preparation was successful, otherwise false.
01528 static bool queuePeriodicDatagram (void)
01529 {
01530     bool success = false;
01531     VolumeIndUlMsg_t volumeIndMsg;
01532     RssiIndUlMsg_t rssiIndMsg;
01533     uint32_t bytesEncoded =  0;
01534     Datagram_t * pDatagram;
01535 
01536     printf ("\nPreparing periodic datagram...\n");
01537 
01538     pDatagram = allocSendDatagram();
01539     if (pDatagram != NULL)
01540     {
01541         // Read the volume in litres
01542         printf ("Reading volume from water meter...\n");
01543         gWaterMeter.readLitres (&(volumeIndMsg.volumeLitres));
01544         printf ("Volume is %ld litres.\n", volumeIndMsg.volumeLitres);
01545 
01546         // Ignore the return value and just set success == true so that the code
01547         // can run without a water meter attached.
01548         success = true;
01549 
01550         if (success)
01551         {
01552             // Read the RSSI
01553             printf ("Reading RSSI from module...\n");
01554             if (pgNeul != NULL)
01555             {
01556                 success = pgNeul->getRssi ((int *) &(rssiIndMsg.rssi));
01557                 printf ("RSSI is %ld.\n", rssiIndMsg.rssi);
01558             }
01559             if (success)
01560             {
01561                 printf ("Encoding datagram...\n");
01562                 // Encode the VolumeInd and RssiInd messages into a datagram
01563                 bytesEncoded += gMessageCodec.encodeVolumeIndUlMsg (&(pDatagram->pBody[bytesEncoded]), &volumeIndMsg);
01564                 bytesEncoded += gMessageCodec.encodeRssiIndUlMsg (&(pDatagram->pBody[bytesEncoded]), &rssiIndMsg);
01565                 pDatagram->size = bytesEncoded;
01566             }
01567             else
01568             {
01569                 assertAlways (DEBUG_SOS_AT_COMMAND_PROBLEM, "Failed to read RSSI from module.");
01570             }
01571         }
01572         else
01573         {
01574             assertAlways (DEBUG_SOS_WATER_METER_PROBLEM, "Failed to read volume from water meter.");
01575         }
01576     }
01577     else
01578     {
01579         assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate send datagram.");
01580     }
01581 
01582     return success;
01583 }
01584 
01585 /// Handle a SerialNumberGetReq message
01586 static bool handleSerialNumberGetReqDlMsg (void)
01587 {
01588     bool success = false;
01589     SerialNumberGetCnfUlMsg_t serialNumberGetCnfUlMsg;
01590     uint32_t bytesEncoded =  0;
01591     Datagram_t * pDatagram;
01592 
01593     printf ("\nHandling SerialNumberGetReqDlMsg.\n");
01594     printf ("Reading serial number from water meter...\n");
01595     // Read the serial number from the water meter
01596     gWaterMeter.readSerialNumber (&(serialNumberGetCnfUlMsg.serialNumber));
01597 
01598     // Ignore the return value and just set success == true so that the code
01599     // can run without a water meter attached.
01600     success = true;
01601 
01602     if (success)
01603     {
01604         printf ("Serial number is %ld.\n", serialNumberGetCnfUlMsg.serialNumber);
01605         printf ("Preparing SerialNumberGetCnfUlMsg response in a datagram...\n");
01606         pDatagram = allocSendDatagram();
01607         if (pDatagram != NULL)
01608         {
01609             // Encode the serialNumberGetCnfUlMsg into a datagram
01610             printf ("Encoding datagram...\n");
01611 
01612             bytesEncoded += gMessageCodec.encodeSerialNumberGetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &serialNumberGetCnfUlMsg);
01613 
01614             pDatagram->size = bytesEncoded;
01615             success = true;
01616         }
01617         else
01618         {
01619             assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate send datagram.");
01620         }
01621     }
01622     else
01623     {
01624         assertAlways (DEBUG_SOS_WATER_METER_PROBLEM, "Failed to read volume from water meter.");
01625     }
01626 
01627     return success;
01628 }
01629 
01630 /// Handle a RebootReq message
01631 static bool handleRebootReqDlMsg (bool devModeOnNotOff)
01632 {
01633     bool success = true;
01634     printf ("\nHandling RebootReqDlMsg, devMode is 0x%d.\n", devModeOnNotOff);
01635 
01636     setDevMode (devModeOnNotOff);
01637 
01638     wait_ms (1000);
01639 
01640     printf ("Resetting system...\n");
01641     wait_ms (2000);
01642     NVIC_SystemReset();
01643 
01644     return success;
01645 }
01646 
01647 /// Enqueue a ReadingIntervalSetCnf or a ReadingIntervalGetCnf message
01648 static bool enqueueReadingIntervalSetGetCnfUlMsg (bool setNotGet)
01649 {
01650     bool success = false;
01651     uint32_t bytesEncoded =  0;
01652     Datagram_t * pDatagram;
01653 
01654      printf ("Preparing ReadingIntervalxxxCnfUlMsg response...\n");
01655      pDatagram = allocSendDatagram();
01656      if (pDatagram != NULL)
01657      {
01658          // Encode the ledxxxCnfUlMsg into a datagram
01659          printf ("Encoding datagram...\n");
01660          if (setNotGet)
01661          {
01662              ReadingIntervalSetCnfUlMsg_t readingIntervalSetCnfUlMsg;
01663 
01664              readingIntervalSetCnfUlMsg.readingIntervalSeconds = readNvContext()->readingIntervalSeconds;
01665              bytesEncoded += gMessageCodec.encodeReadingIntervalSetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &readingIntervalSetCnfUlMsg);
01666          }
01667          else
01668          {
01669              ReadingIntervalGetCnfUlMsg_t readingIntervalGetCnfUlMsg;
01670 
01671              readingIntervalGetCnfUlMsg.readingIntervalSeconds = readNvContext()->readingIntervalSeconds;
01672              bytesEncoded += gMessageCodec.encodeReadingIntervalGetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &readingIntervalGetCnfUlMsg);
01673          }
01674 
01675          pDatagram->size = bytesEncoded;
01676          success = true;
01677      }
01678      else
01679      {
01680          assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate send datagram.");
01681      }
01682 
01683      return success;
01684 }
01685 
01686 /// Handle a ReadingIntervalSetReq message
01687 static bool handleReadingIntervalSetReqDlMsg (uint32_t readingIntervalSeconds)
01688 {
01689     printf ("\nHandling ReadingIntervalSetReqDlMsg, set to %ld.\n", readingIntervalSeconds);
01690     setReadingIntervalSeconds (readingIntervalSeconds);
01691 
01692     return enqueueReadingIntervalSetGetCnfUlMsg (true);
01693 }
01694 
01695 /// Handle a ReadingIntervalGetReq message
01696 static bool handleReadingIntervalGetReqDlMsg (void)
01697 {
01698      printf ("\nHandling ReadingIntervalGetReqDlMsg.\n");
01699 
01700      return enqueueReadingIntervalSetGetCnfUlMsg (false);
01701 }
01702 
01703 /// Enqueue a GpioSetCnf or a GpioGetCnf message
01704 static bool enqueueGpioSetGetCnfUlMsg (bool setNotGet, GpioState_t * gpioState)
01705 {
01706     bool success = false;
01707     uint32_t bytesEncoded =  0;
01708     Datagram_t * pDatagram;
01709 
01710      printf ("Preparing GpioxxxCnfUlMsg response in a datagram...\n");
01711      pDatagram = allocSendDatagram();
01712      if (pDatagram != NULL)
01713      {
01714          // Encode the gpioxxxCnfUlMsg into a datagram
01715          printf ("Encoding datagram...\n");
01716          if (setNotGet)
01717          {
01718              GpioSetCnfUlMsg_t gpioSetCnfUlMsg;
01719 
01720              gpioSetCnfUlMsg.gpioState = *gpioState;
01721              bytesEncoded += gMessageCodec.encodeGpioSetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &gpioSetCnfUlMsg);
01722          }
01723          else
01724          {
01725              GpioGetCnfUlMsg_t gpioGetCnfUlMsg;
01726 
01727              gpioGetCnfUlMsg.gpioState = *gpioState;
01728              bytesEncoded += gMessageCodec.encodeGpioGetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &gpioGetCnfUlMsg);
01729          }
01730 
01731          pDatagram->size = bytesEncoded;
01732          success = true;
01733      }
01734      else
01735      {
01736          assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate send datagram.");
01737      }
01738 
01739      return success;
01740 }
01741 
01742 /// Handle a GpioSetReq message
01743 static bool handleGpioSetReqDlMsg (GpioState_t * pGpioState)
01744 {
01745     bool success = false;
01746 
01747     printf ("\nHandling GpioSetReqDlMsg, gpio %d, inputNotOutput 0x%x, onNotOff 0x%x.\n",
01748             pGpioState->gpio,
01749             pGpioState->inputNotOutput,
01750             pGpioState->onNotOff);
01751 
01752     success = setGpio (pGpioState);
01753 
01754     if (success)
01755     {
01756         success = enqueueGpioSetGetCnfUlMsg (true, pGpioState);
01757     }
01758 
01759     return success;
01760 }
01761 
01762 /// Handle a GpioGetReq message
01763 static bool handleGpioGetReqDlMsg (uint8_t gpio)
01764 {
01765     bool success = false;
01766     GpioState_t gpioState;
01767 
01768     printf ("\nHandling GpioGetReqDlMsg, gpio %d.\n", gpio);
01769 
01770     gpioState.gpio = gpio;
01771     success = getGpio (&gpioState);
01772 
01773     if (success)
01774     {
01775         success = enqueueGpioSetGetCnfUlMsg (false, &gpioState);
01776     }
01777 
01778     return success;
01779 }
01780 
01781 /// Enqueue an LedSetCnf or an LedGetCnf message
01782 static bool enqueueLedSetGetCnfUlMsg (bool setNotGet)
01783 {
01784     bool success = false;
01785     uint32_t bytesEncoded =  0;
01786     Datagram_t * pDatagram;
01787 
01788      printf ("Preparing LedxxxCnfUlMsg response in a datagram...\n");
01789      pDatagram = allocSendDatagram();
01790      if (pDatagram != NULL)
01791      {
01792          // Encode the ledxxxCnfUlMsg into a datagram
01793          printf ("Encoding datagram...\n");
01794          if (setNotGet)
01795          {
01796              LedSetCnfUlMsg_t ledSetCnfUlMsg;
01797 
01798              ledSetCnfUlMsg.onNotOff = readNvContext()->ledOnNotOff;
01799              bytesEncoded += gMessageCodec.encodeLedSetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &ledSetCnfUlMsg);
01800          }
01801          else
01802          {
01803              LedGetCnfUlMsg_t ledGetCnfUlMsg;
01804 
01805              ledGetCnfUlMsg.onNotOff = readNvContext()->ledOnNotOff;
01806              bytesEncoded += gMessageCodec.encodeLedGetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &ledGetCnfUlMsg);
01807          }
01808 
01809          pDatagram->size = bytesEncoded;
01810          success = true;
01811      }
01812      else
01813      {
01814          assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate send datagram.");
01815      }
01816 
01817      return success;
01818 }
01819 
01820 /// Handle an LedSetReq message
01821 static bool handleLedSetReqDlMsg (bool onNotOff)
01822 {
01823     printf ("\nHandling LedSetReqDlMsg, set gLedOnNotOff to 0x%x.\n", onNotOff);
01824     setLed (onNotOff);
01825 
01826     return enqueueLedSetGetCnfUlMsg (true);
01827 }
01828 
01829 /// Handle an LedGetReq message
01830 static bool handleLedGetReqDlMsg (void)
01831 {
01832      printf ("\nHandling LedGetReqDlMsg.\n");
01833 
01834      return enqueueLedSetGetCnfUlMsg (false);
01835 }
01836 
01837 /// Enqueue a FlashSetCnf or a FlashGetCnf message
01838 static bool enqueueFlashSetGetCnfUlMsg (bool setNotGet)
01839 {
01840     bool success = false;
01841     uint32_t bytesEncoded =  0;
01842     Datagram_t * pDatagram;
01843 
01844      printf ("Preparing FlashxxxCnfUlMsg response in a datagram...\n");
01845      pDatagram = allocSendDatagram();
01846      if (pDatagram != NULL)
01847      {
01848          // Encode the flashSetCnfUlMsg or flashGetCnfUlMsg into a datagram
01849          printf ("Encoding datagram...\n");
01850          if (setNotGet)
01851          {
01852              FlashSetCnfUlMsg_t flashSetCnfUlMsg;
01853 
01854              flashSetCnfUlMsg.onNotOff = readNvContext()->flashOnNotOff;
01855              bytesEncoded += gMessageCodec.encodeFlashSetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &flashSetCnfUlMsg);
01856          }
01857          else
01858          {
01859              FlashGetCnfUlMsg_t flashGetCnfUlMsg;
01860 
01861              flashGetCnfUlMsg.onNotOff = readNvContext()->flashOnNotOff;
01862              bytesEncoded += gMessageCodec.encodeFlashGetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &flashGetCnfUlMsg);
01863          }
01864 
01865          pDatagram->size = bytesEncoded;
01866          success = true;
01867      }
01868      else
01869      {
01870          assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate send datagram.");
01871      }
01872 
01873      return success;
01874 }
01875 
01876 /// Handle a FlashSetReq message
01877 static bool handleFlashSetReqDlMsg (bool onNotOff)
01878 {
01879     printf ("\nHandling FlashSetReqDlMsg, set gFlashOnNotOff to 0x%x.\n", onNotOff);
01880     setFlash (onNotOff);
01881 
01882     return enqueueFlashSetGetCnfUlMsg (true);
01883 }
01884 
01885 /// Handle a FlashGetReq message
01886 static bool handleFlashGetReqDlMsg (void)
01887 {
01888     printf ("\nHandling FlashGetReqDlMsg.\n");
01889 
01890     return enqueueFlashSetGetCnfUlMsg (false);
01891 }
01892 
01893 /// Process any received datagrams, queueing any response datagrams
01894 // as appropriate.
01895 static bool processReceivedDatagrams (void)
01896 {
01897     bool success = true;
01898     uint32_t x;
01899     DlMsgUnion_t dlMsg;
01900     MessageCodec::DecodeResult_t decodeResult;
01901     DatagramEntry_t * pEntry;
01902     const char * pBuffer;
01903 
01904 #ifdef DEBUG
01905     printf ("\nProcessing received datagrams...\n");
01906 #endif
01907 
01908     pEntry = &gRecvDatagramListHead;
01909     for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
01910     {
01911         if (pEntry->inUse)
01912         {
01913             printf ("\nProcessing %ld (%ld bytes).\n", x, pEntry->datagram.size);
01914             pBuffer = pEntry->datagram.pBody;
01915 
01916             // Go through the entire datagram buffer looking for messages
01917             while (pBuffer < (pEntry->datagram.pBody + pEntry->datagram.size))
01918             {
01919                 decodeResult = gMessageCodec.decodeDlMsg (&pBuffer, pEntry->datagram.size, &dlMsg);
01920 
01921                 switch (decodeResult)
01922                 {
01923                     case (MessageCodec::DECODE_RESULT_REBOOT_REQ_DL_MSG):
01924                     {
01925                         success = handleRebootReqDlMsg (dlMsg.rebootReqDlMsg.devModeOnNotOff);
01926                     }
01927                     break;
01928                     case (MessageCodec::DECODE_RESULT_SERIAL_NUMBER_GET_REQ_DL_MSG):
01929                     {
01930                         success = handleSerialNumberGetReqDlMsg();
01931                     }
01932                     break;
01933                     case (MessageCodec::DECODE_RESULT_READING_INTERVAL_SET_REQ_DL_MSG):
01934                     {
01935                         success = handleReadingIntervalSetReqDlMsg (dlMsg.readingIntervalSetReqDlMsg.readingIntervalSeconds);
01936                     }
01937                     break;
01938                     case (MessageCodec::DECODE_RESULT_READING_INTERVAL_GET_REQ_DL_MSG):
01939                     {
01940                         success = handleReadingIntervalGetReqDlMsg();
01941                     }
01942                     break;
01943                     case (MessageCodec::DECODE_RESULT_GPIO_SET_REQ_DL_MSG):
01944                     {
01945                         success = handleGpioSetReqDlMsg (&(dlMsg.gpioSetReqDlMsg.gpioState));
01946                     }
01947                     break;
01948                     case (MessageCodec::DECODE_RESULT_GPIO_GET_REQ_DL_MSG):
01949                     {
01950                         success = handleGpioGetReqDlMsg(dlMsg.gpioGetReqDlMsg.gpio);
01951                     }
01952                     break;
01953                     case (MessageCodec::DECODE_RESULT_LED_SET_REQ_DL_MSG):
01954                     {
01955                         success = handleLedSetReqDlMsg (dlMsg.ledSetReqDlMsg.onNotOff);
01956                     }
01957                     break;
01958                     case (MessageCodec::DECODE_RESULT_LED_GET_REQ_DL_MSG):
01959                     {
01960                         success = handleLedGetReqDlMsg();
01961                     }
01962                     break;
01963                     case (MessageCodec::DECODE_RESULT_FLASH_SET_REQ_DL_MSG):
01964                     {
01965                         success = handleFlashSetReqDlMsg (dlMsg.flashSetReqDlMsg.onNotOff);
01966                     }
01967                     break;
01968                     case (MessageCodec::DECODE_RESULT_FLASH_GET_REQ_DL_MSG):
01969                     {
01970                         success = handleFlashGetReqDlMsg ();
01971                     }
01972                     break;
01973                     case (MessageCodec::DECODE_RESULT_FAILURE):
01974                     {
01975                         success = false;
01976                         assertAlways (DEBUG_SOS_PROTOCOL_PROBLEM, "Message decode failure.");
01977                     }
01978                     break;
01979                     case (MessageCodec::DECODE_RESULT_INPUT_TOO_SHORT):
01980                     {
01981                         success = false;
01982                         assertAlways (DEBUG_SOS_PROTOCOL_PROBLEM, "Message decode failure due to input too short.");
01983                     }
01984                     break;
01985                     case (MessageCodec::DECODE_RESULT_OUTPUT_TOO_SHORT):
01986                     {
01987                         success = false;
01988                         assertAlways (DEBUG_SOS_PROTOCOL_PROBLEM, "Message decode failure due to output buffer too short.");
01989                     }
01990                     break;
01991                     case (MessageCodec::DECODE_RESULT_UNKNOWN_MSG_ID):
01992                     {
01993                         success = false;
01994                         assertAlways (DEBUG_SOS_PROTOCOL_PROBLEM, "Unknown message ID.");
01995                     }
01996                     break;
01997                     default:
01998                     {
01999                         success = false;
02000                         assertAlways (DEBUG_SOS_PROTOCOL_PROBLEM, "Unknown decode result: 0x%x.", decodeResult);
02001                     }
02002                     break;
02003                 }
02004             }
02005             pEntry->inUse = false;  // Done with this one now
02006         }
02007         pEntry = pEntry->pNextEntry; // Move to the next entry
02008     }
02009 
02010     freeUnusedRecvDatagrams();
02011 
02012     return success;
02013 }
02014 
02015 #ifdef C027N_USE_SOFT_RADIO
02016   //  SoftModem should be connected to header pins 0 (Rx) and 1 (Tx)
02017   MDMSerial gNeulSoftRadio (D1, D0, 57600, NC, NC);
02018 #else
02019   // When compiling under GCC off-line, this works.
02020   // However, when building under the on-line IDE
02021   // it seems one has to define MDMSerial using the D1 and D0
02022   // pins _outside_ a function, static is just not good enough,
02023   // whereas we must define MDMSerial using MDMTXD and MDMRXD
02024   // _inside_ a function since it depends on some initialisation
02025   // that is performed just before entry to main.
02026   // Hence the lines above.  But I'm leaving this here to
02027   // show how it is meant to work.
02028 
02029   // Create the Neul modem instance
02030   static MDMSerial *getMDMSerial(void)
02031   {
02032   //#ifdef C027N_USE_SOFT_RADIO
02033   //    printf ("\nC027N_USE_SOFT_RADIO is defined.\n");
02034   //    printf ("The on-board modem will be ignored.\n");
02035   //    printf ("SoftModem should be connected to header pins 0 (Rx) and 1 (Tx).\n");
02036   //    static MDMSerial gNeul (D1, D0, 57600, NC, NC);
02037   //#else
02038       static MDMSerial gNeul (MDMTXD, MDMRXD, 57600, NC, NC);
02039   //#endif
02040       return &gNeul;
02041   }
02042 #endif
02043 
02044 // ----------------------------------------------------------------
02045 // PUBLIC FUNCTIONS
02046 // ----------------------------------------------------------------
02047 int realMain (uint8_t * pReserve)
02048 {
02049     bool success = false;
02050 
02051     Serial pc (USBTX, USBRX);
02052 
02053     pc.baud (PC_BAUD_RATE);
02054 
02055     // Use pReserve to stop any attempts by the compiler to get rid of it
02056     printf ("Reserved 0x%08lX-0x%08lX for IAP stack.\n", (long unsigned int) pReserve, (long unsigned int) (pReserve + SIZE_STACK_FOR_IAP - 1));
02057 
02058     printf ("\n%s revision details:\n", __FILE__);
02059     printf ("%s (European time).\n", FILE_DATETIME);
02060     printf ("%s, %s.\n\n", FILE_REV, FILE_CL);
02061 
02062     printf ("This build will still run if no water meter is connected.\n");
02063     printf ("The water volume and serial number will be garbage.\n");
02064 
02065     // Instantiate the Neul modem class
02066 #ifdef C027N_USE_SOFT_RADIO
02067     pgNeul = &gNeulSoftRadio;
02068 #else
02069     pgNeul = getMDMSerial();
02070 #endif
02071 
02072     if (pgNeul != NULL)
02073     {
02074         // Initialise main
02075         success = init();
02076     }
02077     else
02078     {
02079         assertAlways (DEBUG_SOS_GENERIC_FAILURE, "Unable to instantiate modem class.");
02080     }
02081 
02082     if (success)
02083     {
02084         // Initialise the water meter
02085         printf ("Initialising water meter...\n");
02086         //gWaterMeter.setDebugOn(true);
02087         gWaterMeter.init();
02088 
02089         // Initialise the Neul module
02090         printf ("Initialising module...\n");
02091         pgNeul->setDebug(3);  // Normally set to 2, set to 3 for maximum debug
02092         success = pgNeul->init();
02093 
02094         if (success)
02095         {
02096             // Allow the user to configure the module
02097             configureModule();
02098 
02099             if (gModulePhase > MODULE_PHASE_1)
02100             {
02101                 // Wait for registration to complete but
02102                 // only if phase 2 or higher as the CONNECT
02103                 // string was never returned in earlier versions
02104                 printf ("Waiting for device to register...\n");
02105                 success = waitReg (WAIT_REG_S);
02106             }
02107 
02108             if (success)
02109             {
02110                 // Prepare the initial messages in a datagram
02111                 success = queueInitialDatagram();
02112 
02113                 while (success)
02114                 {
02115                     Timer timer;
02116                     uint32_t readingIntervalSeconds = readNvContext()->readingIntervalSeconds;
02117 
02118                     timer.start();
02119 
02120                     // Prepare the periodic messages in a datagram
02121                     success = queuePeriodicDatagram ();
02122 
02123                     // Now do sends and then receives for the interval
02124                     printf ("\nSending and then receiving datagrams for %ld seconds...\n", readingIntervalSeconds);
02125                     while ((timer.read() < readingIntervalSeconds) && success)
02126                     {
02127                         success = sendAndReceive() && processReceivedDatagrams();
02128                         printf (".");
02129                     }
02130                     printf ("\n");
02131                 }
02132 
02133                 assertAlways (DEBUG_SOS_GENERIC_FAILURE, "Exited main loop with success = false.");
02134             }
02135             else
02136             {
02137                 assertAlways (DEBUG_SOS_NETWORK_SEND_PROBLEM, "Registration failed.");
02138             }
02139         }
02140         else
02141         {
02142             assertAlways (DEBUG_SOS_AT_COMMAND_PROBLEM, "Modem initialisation failed.");
02143         }
02144 
02145         // Tidy up
02146         deInit();
02147     }
02148     else
02149     {
02150         assertAlways (DEBUG_SOS_GENERIC_FAILURE, "Initialisation failed.");
02151     }
02152 
02153     return 0;
02154 }
02155 
02156 // This is necessary as the IAP functions use the top SIZE_STACK_FOR_IAP bytes of
02157 // RAM for their own purposes
02158 int main()
02159 {
02160     uint8_t reserve[SIZE_STACK_FOR_IAP];
02161 
02162     return realMain (reserve);
02163 }
02164 
02165 // End Of File