Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: C027_Support_N CIoT_MessagingCommon IapSupport WaterMeterSupport mbed
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
Generated on Wed Jul 13 2022 22:24:28 by
1.7.2