Water Meter demo for C027N.

Dependencies:   C027_Support_N CIoT_MessagingCommon IapSupport WaterMeterSupport mbed

This is the main programme for the CIoT Water Meter Demo. It builds the target code and brings in the Message Codec, IAP (NVRAM) and Water Meter Support libraries. Together with the PC application, contained in /media/uploads/RobMeades/water_meter_demo_2015-05-22.zip, it forms the complete CIoT Water Meter Demo.

Note that the PC application relies on the following:

  • MS Visual Studio for C# 2012 (for compilation),
  • Microsoft .NET 4.5,
  • Microsoft DirectX end-user runtime installed in the following location: <WINDOWS directory>\Microsoft.NET\DirectX for Managed Code\1.0.2902.0\Microsoft.DirectX.AudioVideoPlayback.dll.

Note also that some of the DLL files, e.g. IotMeterDllWrapper.cs, may be referenced in the wrong places by the MSVC project (as this is ripped out of my development folders). Rest assured that all the files you need are there, somewhere (e.g. in the Resources folder), they may just need to be reattached to the project.

Committer:
RobMeades
Date:
Fri May 22 11:45:19 2015 +0000
Revision:
0:e72ea6decc70
Water Meter demo for C027N board.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
RobMeades 0:e72ea6decc70 1 /* Main application file for the device side of the
RobMeades 0:e72ea6decc70 2 * MWC demo 2015.
RobMeades 0:e72ea6decc70 3 *
RobMeades 0:e72ea6decc70 4 * Copyright (C) u-blox Melbourn Ltd
RobMeades 0:e72ea6decc70 5 * u-blox Melbourn Ltd, Melbourn, UK
RobMeades 0:e72ea6decc70 6 *
RobMeades 0:e72ea6decc70 7 * All rights reserved.
RobMeades 0:e72ea6decc70 8 *
RobMeades 0:e72ea6decc70 9 * This source file is the sole property of u-blox Melbourn Ltd.
RobMeades 0:e72ea6decc70 10 * Reproduction or utilization of this source in whole or part is
RobMeades 0:e72ea6decc70 11 * forbidden without the written consent of u-blox Melbourn Ltd.
RobMeades 0:e72ea6decc70 12 */
RobMeades 0:e72ea6decc70 13
RobMeades 0:e72ea6decc70 14 #include "mbed.h"
RobMeades 0:e72ea6decc70 15 #include "IapApi.h"
RobMeades 0:e72ea6decc70 16 #include "MDM.h"
RobMeades 0:e72ea6decc70 17 #include "IotMeterApi.hpp"
RobMeades 0:e72ea6decc70 18 #include "WaterMeterApi.hpp"
RobMeades 0:e72ea6decc70 19
RobMeades 0:e72ea6decc70 20 #define FILE_REV "Revision 1.0"
RobMeades 0:e72ea6decc70 21 #define FILE_CL "Pushed by RobMeades"
RobMeades 0:e72ea6decc70 22 #define FILE_DATETIME "2015/05/15"
RobMeades 0:e72ea6decc70 23
RobMeades 0:e72ea6decc70 24 // ----------------------------------------------------------------
RobMeades 0:e72ea6decc70 25 // GENERAL COMPILE-TIME CONSTANTS
RobMeades 0:e72ea6decc70 26 // ----------------------------------------------------------------
RobMeades 0:e72ea6decc70 27
RobMeades 0:e72ea6decc70 28 // The time for which the flash turns the LED on or off for
RobMeades 0:e72ea6decc70 29 #define FLASH_DURATION_MS 250
RobMeades 0:e72ea6decc70 30
RobMeades 0:e72ea6decc70 31 // The maximum number of datagrams that are available for use
RobMeades 0:e72ea6decc70 32 // at any one time (i.e. the total of send and receive)
RobMeades 0:e72ea6decc70 33 #define MAX_NUM_DATAGRAMS 10
RobMeades 0:e72ea6decc70 34
RobMeades 0:e72ea6decc70 35 // The number of milliseconds to wait for a received message
RobMeades 0:e72ea6decc70 36 // after a send
RobMeades 0:e72ea6decc70 37 #define RECEIVE_DURATION_MS 1000
RobMeades 0:e72ea6decc70 38
RobMeades 0:e72ea6decc70 39 // The number of seconds to wait for device registration
RobMeades 0:e72ea6decc70 40 #define WAIT_REG_S 300
RobMeades 0:e72ea6decc70 41
RobMeades 0:e72ea6decc70 42 // The number of SOS flashes at an assert before restarting
RobMeades 0:e72ea6decc70 43 // if not in development mode; in development mode there
RobMeades 0:e72ea6decc70 44 // is no restart, just flashing forever
RobMeades 0:e72ea6decc70 45 #define NUM_ASSERT_SOS_BEFORE_RESTART 3
RobMeades 0:e72ea6decc70 46
RobMeades 0:e72ea6decc70 47 // Baud rate of the PC interface
RobMeades 0:e72ea6decc70 48 //#define PC_BAUD_RATE 9600
RobMeades 0:e72ea6decc70 49 #define PC_BAUD_RATE 9600
RobMeades 0:e72ea6decc70 50
RobMeades 0:e72ea6decc70 51 // The maximum length of a MACTEST string (as raw bytes)
RobMeades 0:e72ea6decc70 52 #define MACTEST_STRING_MAX_SIZE 48
RobMeades 0:e72ea6decc70 53
RobMeades 0:e72ea6decc70 54 // The time to wait for a user to interrupt to change
RobMeades 0:e72ea6decc70 55 // the mactest string
RobMeades 0:e72ea6decc70 56 #define USER_WAIT_DECISECONDS 50
RobMeades 0:e72ea6decc70 57
RobMeades 0:e72ea6decc70 58 // The size of the stack required by IAP
RobMeades 0:e72ea6decc70 59 #define SIZE_STACK_FOR_IAP 32
RobMeades 0:e72ea6decc70 60
RobMeades 0:e72ea6decc70 61 // An ID for the NVRAM contents so that we
RobMeades 0:e72ea6decc70 62 // can tell if it's there.
RobMeades 0:e72ea6decc70 63 #define NVRAM_ID 0x12345678
RobMeades 0:e72ea6decc70 64
RobMeades 0:e72ea6decc70 65 // NVRAM bytes to write (can be a set of fixed sizes, min 256)
RobMeades 0:e72ea6decc70 66 #define NVRAM_SIZE 256
RobMeades 0:e72ea6decc70 67
RobMeades 0:e72ea6decc70 68 // Macro to convert to upper case
RobMeades 0:e72ea6decc70 69 #define TO_UPPER(x) (((x) >= 'a' && (x) <= 'z') ? x & ~0x20 : x)
RobMeades 0:e72ea6decc70 70
RobMeades 0:e72ea6decc70 71 // Macro to tell is something is odd
RobMeades 0:e72ea6decc70 72 #define IS_ODD(x) (((x) & 0x01) == 0x01 ? true : false)
RobMeades 0:e72ea6decc70 73
RobMeades 0:e72ea6decc70 74 // Macro to tell is something is even
RobMeades 0:e72ea6decc70 75 #define IS_EVEN(x) (((x) & 0x01) == 0x01 ? false : true)
RobMeades 0:e72ea6decc70 76
RobMeades 0:e72ea6decc70 77 // Highlight for talking to the user at the PC side
RobMeades 0:e72ea6decc70 78 #define COLOUR_HIGHLIGHT "\033[33m"
RobMeades 0:e72ea6decc70 79
RobMeades 0:e72ea6decc70 80 // Default colour
RobMeades 0:e72ea6decc70 81 #define COLOUR_DEFAULT "\033[39m"
RobMeades 0:e72ea6decc70 82
RobMeades 0:e72ea6decc70 83 // ----------------------------------------------------------------
RobMeades 0:e72ea6decc70 84 // TYPES
RobMeades 0:e72ea6decc70 85 // ----------------------------------------------------------------
RobMeades 0:e72ea6decc70 86
RobMeades 0:e72ea6decc70 87 /// A type to hold a datagram
RobMeades 0:e72ea6decc70 88 // Used for encoding AT commands on the send side and
RobMeades 0:e72ea6decc70 89 // receiving messages on the receive side.
RobMeades 0:e72ea6decc70 90 typedef struct DatagramTag_t
RobMeades 0:e72ea6decc70 91 {
RobMeades 0:e72ea6decc70 92 uint32_t size;
RobMeades 0:e72ea6decc70 93 char pBody[MAX_DATAGRAM_SIZE_RAW];
RobMeades 0:e72ea6decc70 94 } Datagram_t;
RobMeades 0:e72ea6decc70 95
RobMeades 0:e72ea6decc70 96 /// A linked list entry holding a datagram
RobMeades 0:e72ea6decc70 97 typedef struct DatagramEntryTag_t
RobMeades 0:e72ea6decc70 98 {
RobMeades 0:e72ea6decc70 99 bool inUse;
RobMeades 0:e72ea6decc70 100 Datagram_t datagram;
RobMeades 0:e72ea6decc70 101 DatagramEntryTag_t * pPrevEntry;
RobMeades 0:e72ea6decc70 102 DatagramEntryTag_t * pNextEntry;
RobMeades 0:e72ea6decc70 103
RobMeades 0:e72ea6decc70 104 } DatagramEntry_t;
RobMeades 0:e72ea6decc70 105
RobMeades 0:e72ea6decc70 106 /// Debug flashes
RobMeades 0:e72ea6decc70 107 typedef enum DebugSosTypeTag_t
RobMeades 0:e72ea6decc70 108 {
RobMeades 0:e72ea6decc70 109 DEBUG_SOS_WATER_METER_PROBLEM = WAKE_UP_CODE_WATER_METER_PROBLEM,
RobMeades 0:e72ea6decc70 110 DEBUG_SOS_AT_COMMAND_PROBLEM = WAKE_UP_CODE_AT_COMMAND_PROBLEM,
RobMeades 0:e72ea6decc70 111 DEBUG_SOS_NETWORK_SEND_PROBLEM = WAKE_UP_CODE_NETWORK_SEND_PROBLEM,
RobMeades 0:e72ea6decc70 112 DEBUG_SOS_MEMORY_ALLOC_PROBLEM = WAKE_UP_CODE_MEMORY_ALLOC_PROBLEM,
RobMeades 0:e72ea6decc70 113 DEBUG_SOS_PROTOCOL_PROBLEM = WAKE_UP_CODE_PROTOCOL_PROBLEM,
RobMeades 0:e72ea6decc70 114 DEBUG_SOS_GENERIC_FAILURE = WAKE_UP_CODE_GENERIC_FAILURE,
RobMeades 0:e72ea6decc70 115 DEBUG_SOS_REBOOT = WAKE_UP_CODE_REBOOT,
RobMeades 0:e72ea6decc70 116 } DebugSosType_t;
RobMeades 0:e72ea6decc70 117
RobMeades 0:e72ea6decc70 118 /// Context data, which will be in NVRAM
RobMeades 0:e72ea6decc70 119 // and must be no bigger than NVRAM_SIZE
RobMeades 0:e72ea6decc70 120 typedef struct NvContextTag_t
RobMeades 0:e72ea6decc70 121 {
RobMeades 0:e72ea6decc70 122 uint32_t id; //<! An ID for the NVRAM
RobMeades 0:e72ea6decc70 123 bool devModeOnNotOff; //<! Development mode
RobMeades 0:e72ea6decc70 124 WakeUpCode_t wakeUpCode; //<! Wake-up code
RobMeades 0:e72ea6decc70 125 uint32_t readingIntervalSeconds; //<! The read interval
RobMeades 0:e72ea6decc70 126 bool ledOnNotOff; //<! The LED state
RobMeades 0:e72ea6decc70 127 bool flashOnNotOff; //<! The Flash state
RobMeades 0:e72ea6decc70 128 char mactestString[MACTEST_STRING_MAX_SIZE]; //<! The MACTEST string, only used with phase 1 modules
RobMeades 0:e72ea6decc70 129 //<! this is a string of bytes (so NOT the hex coded form)
RobMeades 0:e72ea6decc70 130 //<! and no terminator is stored
RobMeades 0:e72ea6decc70 131 uint32_t mactestStringSize; //<! The size of the MACTEST string
RobMeades 0:e72ea6decc70 132 } NvContext_t;
RobMeades 0:e72ea6decc70 133
RobMeades 0:e72ea6decc70 134
RobMeades 0:e72ea6decc70 135 typedef union NvramTag_t
RobMeades 0:e72ea6decc70 136 {
RobMeades 0:e72ea6decc70 137 char rawBytes[NVRAM_SIZE];
RobMeades 0:e72ea6decc70 138 NvContext_t nvContext;
RobMeades 0:e72ea6decc70 139 } Nvram_t;
RobMeades 0:e72ea6decc70 140
RobMeades 0:e72ea6decc70 141 // Note that order is important below: modules of newer phases
RobMeades 0:e72ea6decc70 142 // should be of higher values
RobMeades 0:e72ea6decc70 143 typedef enum ModulePhase_t
RobMeades 0:e72ea6decc70 144 {
RobMeades 0:e72ea6decc70 145 MODULE_PHASE_UNKNOWN,
RobMeades 0:e72ea6decc70 146 MODULE_PHASE_1, //<! As used at Mobile World Congress Barcelona 2015
RobMeades 0:e72ea6decc70 147 MODULE_PHASE_2, //<! As used at Mobile World Congress Shanghai 2015
RobMeades 0:e72ea6decc70 148 MODULE_PHASE_3
RobMeades 0:e72ea6decc70 149 } ModulePhase;
RobMeades 0:e72ea6decc70 150
RobMeades 0:e72ea6decc70 151 // ----------------------------------------------------------------
RobMeades 0:e72ea6decc70 152 // PRIVATE VARIABLES
RobMeades 0:e72ea6decc70 153 // ----------------------------------------------------------------
RobMeades 0:e72ea6decc70 154
RobMeades 0:e72ea6decc70 155 // Non-volatile storage area, aligned on a 4-byte boundary
RobMeades 0:e72ea6decc70 156 Nvram_t __attribute__((aligned(4))) nvram;
RobMeades 0:e72ea6decc70 157
RobMeades 0:e72ea6decc70 158 // Instantiate the NVRAM handling code
RobMeades 0:e72ea6decc70 159 static IAP iap;
RobMeades 0:e72ea6decc70 160
RobMeades 0:e72ea6decc70 161 // Pointer to instance of the Neul modem, populated once we
RobMeades 0:e72ea6decc70 162 // get into main() as its constructor requires some initialisation
RobMeades 0:e72ea6decc70 163 // that is only complete on entry into main()
RobMeades 0:e72ea6decc70 164 MDMSerial *pgNeul = NULL;
RobMeades 0:e72ea6decc70 165
RobMeades 0:e72ea6decc70 166 // Instantiate the interface to the water meter
RobMeades 0:e72ea6decc70 167 static WaterMeterHandler gWaterMeter;
RobMeades 0:e72ea6decc70 168
RobMeades 0:e72ea6decc70 169 // Instantiate the messaging API to the C027N
RobMeades 0:e72ea6decc70 170 // as an IoT metering device
RobMeades 0:e72ea6decc70 171 static MessageCodec gMessageCodec;
RobMeades 0:e72ea6decc70 172
RobMeades 0:e72ea6decc70 173 // The module phase
RobMeades 0:e72ea6decc70 174 static ModulePhase gModulePhase = MODULE_PHASE_UNKNOWN;
RobMeades 0:e72ea6decc70 175
RobMeades 0:e72ea6decc70 176 // A good default MACTEST string
RobMeades 0:e72ea6decc70 177 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};
RobMeades 0:e72ea6decc70 178
RobMeades 0:e72ea6decc70 179 // The LED
RobMeades 0:e72ea6decc70 180 static DigitalOut led(LED);
RobMeades 0:e72ea6decc70 181 static const int gpioTable[] = {D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13};
RobMeades 0:e72ea6decc70 182
RobMeades 0:e72ea6decc70 183 // The connected GPIO(s)
RobMeades 0:e72ea6decc70 184 static DigitalOut pump((PinName) gpioTable[GPIO_WATER_PUMP]);
RobMeades 0:e72ea6decc70 185
RobMeades 0:e72ea6decc70 186 // Head of free datagram linked list
RobMeades 0:e72ea6decc70 187 static DatagramEntry_t gFreeDatagramListHeadUnused;
RobMeades 0:e72ea6decc70 188 // Head of send datagram linked list
RobMeades 0:e72ea6decc70 189 static DatagramEntry_t gSendDatagramListHead;
RobMeades 0:e72ea6decc70 190 // Head of receive datagram linked list
RobMeades 0:e72ea6decc70 191 static DatagramEntry_t gRecvDatagramListHead;
RobMeades 0:e72ea6decc70 192
RobMeades 0:e72ea6decc70 193 const char hexTable[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', \
RobMeades 0:e72ea6decc70 194 '9', 'a', 'b', 'c', 'd', 'e', 'f'};
RobMeades 0:e72ea6decc70 195
RobMeades 0:e72ea6decc70 196 // ----------------------------------------------------------------
RobMeades 0:e72ea6decc70 197 // GENERIC PRIVATE FUNCTION PROTOTYPES
RobMeades 0:e72ea6decc70 198 // ----------------------------------------------------------------
RobMeades 0:e72ea6decc70 199
RobMeades 0:e72ea6decc70 200 static void doDebugFlash (uint32_t numberOfFlashes);
RobMeades 0:e72ea6decc70 201 static void debugSos(DebugSosType_t debugSosType);
RobMeades 0:e72ea6decc70 202 #ifdef DEBUG
RobMeades 0:e72ea6decc70 203 static void debugPrintLists (void);
RobMeades 0:e72ea6decc70 204 #endif
RobMeades 0:e72ea6decc70 205 static void getModulePhase (void);
RobMeades 0:e72ea6decc70 206 static bool isValidHex (char digit);
RobMeades 0:e72ea6decc70 207 static uint8_t hexToNibble (char digit);
RobMeades 0:e72ea6decc70 208 static uint8_t hexTobyte (char digit1, char digit2);
RobMeades 0:e72ea6decc70 209 static char peekChar (void);
RobMeades 0:e72ea6decc70 210 static char getChar (void);
RobMeades 0:e72ea6decc70 211 static uint32_t getUserHexString (uint32_t size, char * buf);
RobMeades 0:e72ea6decc70 212 static void printByteString (uint32_t size, const char * buf);
RobMeades 0:e72ea6decc70 213 static void printMactestString (uint32_t size, const char * string);
RobMeades 0:e72ea6decc70 214 static void configureModule (void);
RobMeades 0:e72ea6decc70 215 static void assert (bool condition, DebugSosType_t debugSosType, const char * pFormat, ...);
RobMeades 0:e72ea6decc70 216 static void assertAlways (DebugSosType_t debugSosType, const char * pFormat, ...);
RobMeades 0:e72ea6decc70 217 static bool writeNvContext (Nvram_t * pNvram);
RobMeades 0:e72ea6decc70 218 static NvContext_t * resetNvContext (void);
RobMeades 0:e72ea6decc70 219 static NvContext_t * readNvContext (void);
RobMeades 0:e72ea6decc70 220 static void doSendFlash (void);
RobMeades 0:e72ea6decc70 221 static void doRecvFlash (void);
RobMeades 0:e72ea6decc70 222 static bool setGpio (GpioState_t * pGpioState);
RobMeades 0:e72ea6decc70 223 static bool getGpio (GpioState_t * pGpioState);
RobMeades 0:e72ea6decc70 224 static void setWakeUpCode (WakeUpCode_t wakeUpCode);
RobMeades 0:e72ea6decc70 225 static void setDevMode (bool onNotOff);
RobMeades 0:e72ea6decc70 226 static void setReadingIntervalSeconds (uint32_t readingIntervalSeconds);
RobMeades 0:e72ea6decc70 227 static void setLed (bool onNotOff);
RobMeades 0:e72ea6decc70 228 static void setFlash (bool onNotOff);
RobMeades 0:e72ea6decc70 229 static bool init (void);
RobMeades 0:e72ea6decc70 230 static void deInit (void);
RobMeades 0:e72ea6decc70 231 static Datagram_t * allocDatagram (DatagramEntry_t * pDatagramListHead);
RobMeades 0:e72ea6decc70 232 static Datagram_t * allocSendDatagram (void);
RobMeades 0:e72ea6decc70 233 static Datagram_t * allocRecvDatagram (void);
RobMeades 0:e72ea6decc70 234 static void freeDatagram (Datagram_t *pDatagram, DatagramEntry_t * pDatagramListHead);
RobMeades 0:e72ea6decc70 235 static void freeRecvDatagram (Datagram_t *pDatagram);
RobMeades 0:e72ea6decc70 236 static void freeAllDatagrams (DatagramEntry_t *pDatagramListHead);
RobMeades 0:e72ea6decc70 237 static void freeUnusedDatagrams (DatagramEntry_t *pDatagramListHead);
RobMeades 0:e72ea6decc70 238 static void freeUnusedSendDatagrams (void);
RobMeades 0:e72ea6decc70 239 static void freeUnusedRecvDatagrams (void);
RobMeades 0:e72ea6decc70 240 static bool waitReg (uint32_t durationSeconds);
RobMeades 0:e72ea6decc70 241 static bool sendAndReceive (void);
RobMeades 0:e72ea6decc70 242 static bool queueInitialDatagram (void);
RobMeades 0:e72ea6decc70 243 static bool queuePeriodicDatagram (void);
RobMeades 0:e72ea6decc70 244 static bool handleSerialNumberGetReqDlMsg (void);
RobMeades 0:e72ea6decc70 245 static bool handleRebootReqDlMsg (bool devModeOnNotOff);
RobMeades 0:e72ea6decc70 246 static bool enqueueReadingIntervalSetGetCnfUlMsg (bool setNotGet);
RobMeades 0:e72ea6decc70 247 static bool handleReadingIntervalSetReqDlMsg (uint32_t readingIntervalSeconds);
RobMeades 0:e72ea6decc70 248 static bool handleReadingIntervalGetReqDlMsg (void);
RobMeades 0:e72ea6decc70 249 static bool enqueueGpioSetGetCnfUlMsg (bool setNotGet, GpioState_t * gpioState);
RobMeades 0:e72ea6decc70 250 static bool handleGpioSetReqDlMsg (GpioState_t * pGpioState);
RobMeades 0:e72ea6decc70 251 static bool handleGpioGetReqDlMsg (uint8_t gpio);
RobMeades 0:e72ea6decc70 252 static bool enqueueLedSetGetCnfUlMsg (bool setNotGet);
RobMeades 0:e72ea6decc70 253 static bool handleLedSetReqDlMsg (bool onNotOff);
RobMeades 0:e72ea6decc70 254 static bool handleLedGetReqDlMsg (void);
RobMeades 0:e72ea6decc70 255 static bool enqueueFlashSetGetCnfUlMsg (bool setNotGet);
RobMeades 0:e72ea6decc70 256 static bool handleFlashSetReqDlMsg (bool onNotOff);
RobMeades 0:e72ea6decc70 257 static bool handleFlashGetReqDlMsg (void);
RobMeades 0:e72ea6decc70 258 static bool processReceivedDatagrams (void);
RobMeades 0:e72ea6decc70 259 static MDMSerial *getMDMSerial(void);
RobMeades 0:e72ea6decc70 260
RobMeades 0:e72ea6decc70 261 // ----------------------------------------------------------------
RobMeades 0:e72ea6decc70 262 // GENERIC PRIVATE FUNCTIONS
RobMeades 0:e72ea6decc70 263 // ----------------------------------------------------------------
RobMeades 0:e72ea6decc70 264
RobMeades 0:e72ea6decc70 265 // Debug
RobMeades 0:e72ea6decc70 266 static void doDebugFlash (uint32_t numberOfFlashes)
RobMeades 0:e72ea6decc70 267 {
RobMeades 0:e72ea6decc70 268 uint32_t x;
RobMeades 0:e72ea6decc70 269 uint32_t y;
RobMeades 0:e72ea6decc70 270 bool devModeOnNotOff = readNvContext()->devModeOnNotOff;
RobMeades 0:e72ea6decc70 271
RobMeades 0:e72ea6decc70 272 led = 0;
RobMeades 0:e72ea6decc70 273 wait_ms (1000);
RobMeades 0:e72ea6decc70 274 for (y = 0; (y < NUM_ASSERT_SOS_BEFORE_RESTART) | devModeOnNotOff; y++)
RobMeades 0:e72ea6decc70 275 {
RobMeades 0:e72ea6decc70 276 for (x = 0; x < numberOfFlashes; x++)
RobMeades 0:e72ea6decc70 277 {
RobMeades 0:e72ea6decc70 278 led = !led;
RobMeades 0:e72ea6decc70 279 wait_ms (FLASH_DURATION_MS);
RobMeades 0:e72ea6decc70 280 led = !led;
RobMeades 0:e72ea6decc70 281 wait_ms (FLASH_DURATION_MS);
RobMeades 0:e72ea6decc70 282 }
RobMeades 0:e72ea6decc70 283 wait_ms (2000);
RobMeades 0:e72ea6decc70 284 }
RobMeades 0:e72ea6decc70 285
RobMeades 0:e72ea6decc70 286 // Restart the system and try again
RobMeades 0:e72ea6decc70 287 printf ("Resetting system...\n");
RobMeades 0:e72ea6decc70 288 wait_ms (2000);
RobMeades 0:e72ea6decc70 289 NVIC_SystemReset();
RobMeades 0:e72ea6decc70 290
RobMeades 0:e72ea6decc70 291 }
RobMeades 0:e72ea6decc70 292
RobMeades 0:e72ea6decc70 293 static void debugSos(DebugSosType_t debugSosType)
RobMeades 0:e72ea6decc70 294 {
RobMeades 0:e72ea6decc70 295 switch (debugSosType)
RobMeades 0:e72ea6decc70 296 {
RobMeades 0:e72ea6decc70 297 case (DEBUG_SOS_WATER_METER_PROBLEM):
RobMeades 0:e72ea6decc70 298 {
RobMeades 0:e72ea6decc70 299 doDebugFlash (3);
RobMeades 0:e72ea6decc70 300 }
RobMeades 0:e72ea6decc70 301 break;
RobMeades 0:e72ea6decc70 302 case (DEBUG_SOS_AT_COMMAND_PROBLEM):
RobMeades 0:e72ea6decc70 303 {
RobMeades 0:e72ea6decc70 304 doDebugFlash (4);
RobMeades 0:e72ea6decc70 305 }
RobMeades 0:e72ea6decc70 306 break;
RobMeades 0:e72ea6decc70 307 case (DEBUG_SOS_NETWORK_SEND_PROBLEM):
RobMeades 0:e72ea6decc70 308 {
RobMeades 0:e72ea6decc70 309 doDebugFlash (5);
RobMeades 0:e72ea6decc70 310 }
RobMeades 0:e72ea6decc70 311 break;
RobMeades 0:e72ea6decc70 312 case (DEBUG_SOS_MEMORY_ALLOC_PROBLEM):
RobMeades 0:e72ea6decc70 313 {
RobMeades 0:e72ea6decc70 314 doDebugFlash (6);
RobMeades 0:e72ea6decc70 315 }
RobMeades 0:e72ea6decc70 316 break;
RobMeades 0:e72ea6decc70 317 case (DEBUG_SOS_PROTOCOL_PROBLEM):
RobMeades 0:e72ea6decc70 318 {
RobMeades 0:e72ea6decc70 319 doDebugFlash (7);
RobMeades 0:e72ea6decc70 320 }
RobMeades 0:e72ea6decc70 321 break;
RobMeades 0:e72ea6decc70 322 case (DEBUG_SOS_GENERIC_FAILURE):
RobMeades 0:e72ea6decc70 323 {
RobMeades 0:e72ea6decc70 324 doDebugFlash (8);
RobMeades 0:e72ea6decc70 325 }
RobMeades 0:e72ea6decc70 326 break;
RobMeades 0:e72ea6decc70 327 case (DEBUG_SOS_REBOOT):
RobMeades 0:e72ea6decc70 328 {
RobMeades 0:e72ea6decc70 329 doDebugFlash (9);
RobMeades 0:e72ea6decc70 330 }
RobMeades 0:e72ea6decc70 331 break;
RobMeades 0:e72ea6decc70 332 default:
RobMeades 0:e72ea6decc70 333 {
RobMeades 0:e72ea6decc70 334 doDebugFlash (10);
RobMeades 0:e72ea6decc70 335 }
RobMeades 0:e72ea6decc70 336 break;
RobMeades 0:e72ea6decc70 337 }
RobMeades 0:e72ea6decc70 338 }
RobMeades 0:e72ea6decc70 339
RobMeades 0:e72ea6decc70 340 /// Print out the datagram lists for debugging
RobMeades 0:e72ea6decc70 341 #ifdef DEBUG
RobMeades 0:e72ea6decc70 342 static void debugPrintLists (void)
RobMeades 0:e72ea6decc70 343 {
RobMeades 0:e72ea6decc70 344 uint32_t x;
RobMeades 0:e72ea6decc70 345 DatagramEntry_t * pEntry;
RobMeades 0:e72ea6decc70 346
RobMeades 0:e72ea6decc70 347 printf ("LIST CONTENTS:\n");
RobMeades 0:e72ea6decc70 348
RobMeades 0:e72ea6decc70 349 printf ("Free list head is at 0x%ld.\n", &gFreeDatagramListHeadUnused);
RobMeades 0:e72ea6decc70 350 pEntry = &gFreeDatagramListHeadUnused;
RobMeades 0:e72ea6decc70 351 for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
RobMeades 0:e72ea6decc70 352 {
RobMeades 0:e72ea6decc70 353 printf (" %d: prev 0x%lx, next 0x%lx, inUse 0x%x, datagram.size %d, datagram \"%s\".\n",
RobMeades 0:e72ea6decc70 354 x, pEntry->pPrevEntry, pEntry->pNextEntry, pEntry->inUse, pEntry->datagram.size, pEntry->datagram.pBody);
RobMeades 0:e72ea6decc70 355 pEntry = pEntry->pNextEntry;
RobMeades 0:e72ea6decc70 356 }
RobMeades 0:e72ea6decc70 357
RobMeades 0:e72ea6decc70 358 printf ("Send list head is at 0x%ld.\n", &gSendDatagramListHead);
RobMeades 0:e72ea6decc70 359 pEntry = &gSendDatagramListHead;
RobMeades 0:e72ea6decc70 360 for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
RobMeades 0:e72ea6decc70 361 {
RobMeades 0:e72ea6decc70 362 printf (" %d: prev 0x%lx, next 0x%lx, inUse 0x%x, datagram.size %d, datagram \"%s\".\n",
RobMeades 0:e72ea6decc70 363 x, pEntry->pPrevEntry, pEntry->pNextEntry, pEntry->inUse, pEntry->datagram.size, pEntry->datagram.pBody);
RobMeades 0:e72ea6decc70 364 pEntry = pEntry->pNextEntry;
RobMeades 0:e72ea6decc70 365 }
RobMeades 0:e72ea6decc70 366
RobMeades 0:e72ea6decc70 367 printf ("Recv list head is at 0x%ld.\n", &gRecvDatagramListHead);
RobMeades 0:e72ea6decc70 368 pEntry = &gRecvDatagramListHead;
RobMeades 0:e72ea6decc70 369 for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
RobMeades 0:e72ea6decc70 370 {
RobMeades 0:e72ea6decc70 371 printf (" %d: prev 0x%lx, next 0x%lx, inUse 0x%x, datagram.size %d, datagram \"%s\".\n",
RobMeades 0:e72ea6decc70 372 x, pEntry->pPrevEntry, pEntry->pNextEntry, pEntry->inUse, pEntry->datagram.size, pEntry->datagram.pBody);
RobMeades 0:e72ea6decc70 373 pEntry = pEntry->pNextEntry;
RobMeades 0:e72ea6decc70 374 }
RobMeades 0:e72ea6decc70 375 }
RobMeades 0:e72ea6decc70 376 #endif
RobMeades 0:e72ea6decc70 377
RobMeades 0:e72ea6decc70 378 // Set the phase of the module in a global variable
RobMeades 0:e72ea6decc70 379 static void getModulePhase (void)
RobMeades 0:e72ea6decc70 380 {
RobMeades 0:e72ea6decc70 381 char * pVersion = NULL;
RobMeades 0:e72ea6decc70 382
RobMeades 0:e72ea6decc70 383 pVersion = pgNeul->getVersion();
RobMeades 0:e72ea6decc70 384
RobMeades 0:e72ea6decc70 385 if (pVersion != NULL)
RobMeades 0:e72ea6decc70 386 {
RobMeades 0:e72ea6decc70 387 printf ("Version: \"%s\", so ", pVersion);
RobMeades 0:e72ea6decc70 388 if (strcmp(pVersion, "Neul CIoT Phase 2") == 0)
RobMeades 0:e72ea6decc70 389 {
RobMeades 0:e72ea6decc70 390 gModulePhase = MODULE_PHASE_2;
RobMeades 0:e72ea6decc70 391 printf ("module is MODULE_PHASE_2.\n");
RobMeades 0:e72ea6decc70 392 }
RobMeades 0:e72ea6decc70 393 else if (strcmp(pVersion, "Neul CIoT") == 0)
RobMeades 0:e72ea6decc70 394 {
RobMeades 0:e72ea6decc70 395 gModulePhase = MODULE_PHASE_1;
RobMeades 0:e72ea6decc70 396 printf ("module is MODULE_PHASE_1.\n");
RobMeades 0:e72ea6decc70 397 }
RobMeades 0:e72ea6decc70 398 else
RobMeades 0:e72ea6decc70 399 {
RobMeades 0:e72ea6decc70 400 printf ("module is MODULE_PHASE_UNKNOWN.\n");
RobMeades 0:e72ea6decc70 401 }
RobMeades 0:e72ea6decc70 402 }
RobMeades 0:e72ea6decc70 403 }
RobMeades 0:e72ea6decc70 404
RobMeades 0:e72ea6decc70 405 #if 0
RobMeades 0:e72ea6decc70 406 // Convert to upper case
RobMeades 0:e72ea6decc70 407 // Not using this as found it didn't seem to work for the Chinese using their
RobMeades 0:e72ea6decc70 408 // terminal program. Potential character set issues maybe?
RobMeades 0:e72ea6decc70 409 // Instead, please do a direct comparison against upper and lower case versions
RobMeades 0:e72ea6decc70 410 static char toUpper (char digit)
RobMeades 0:e72ea6decc70 411 {
RobMeades 0:e72ea6decc70 412 if (digit >= 'a' && digit <= 'z')
RobMeades 0:e72ea6decc70 413 {
RobMeades 0:e72ea6decc70 414 digit &= ~0x20;
RobMeades 0:e72ea6decc70 415 }
RobMeades 0:e72ea6decc70 416
RobMeades 0:e72ea6decc70 417 return digit;
RobMeades 0:e72ea6decc70 418 }
RobMeades 0:e72ea6decc70 419 #endif
RobMeades 0:e72ea6decc70 420
RobMeades 0:e72ea6decc70 421 // Return true if digit is a valid hex
RobMeades 0:e72ea6decc70 422 // character, otherwise false
RobMeades 0:e72ea6decc70 423 static bool isValidHex (char digit)
RobMeades 0:e72ea6decc70 424 {
RobMeades 0:e72ea6decc70 425 uint32_t x;
RobMeades 0:e72ea6decc70 426 bool isValid = false;
RobMeades 0:e72ea6decc70 427
RobMeades 0:e72ea6decc70 428 for (x = 0; (x < sizeof (hexTable)) && !isValid; x++)
RobMeades 0:e72ea6decc70 429 {
RobMeades 0:e72ea6decc70 430 if (TO_UPPER(digit) == TO_UPPER(hexTable[x]))
RobMeades 0:e72ea6decc70 431 {
RobMeades 0:e72ea6decc70 432 isValid = true;
RobMeades 0:e72ea6decc70 433 }
RobMeades 0:e72ea6decc70 434 }
RobMeades 0:e72ea6decc70 435
RobMeades 0:e72ea6decc70 436 return isValid;
RobMeades 0:e72ea6decc70 437 }
RobMeades 0:e72ea6decc70 438
RobMeades 0:e72ea6decc70 439 // Take a hex nibble and convert to a byte.
RobMeades 0:e72ea6decc70 440 static uint8_t hexToNibble (char digit)
RobMeades 0:e72ea6decc70 441 {
RobMeades 0:e72ea6decc70 442 uint8_t nibbleValue = 0;
RobMeades 0:e72ea6decc70 443
RobMeades 0:e72ea6decc70 444 digit = TO_UPPER (digit);
RobMeades 0:e72ea6decc70 445 if (isValidHex (digit))
RobMeades 0:e72ea6decc70 446 {
RobMeades 0:e72ea6decc70 447 if (digit >= '0' && digit <= '9')
RobMeades 0:e72ea6decc70 448 {
RobMeades 0:e72ea6decc70 449 nibbleValue = digit - '0';
RobMeades 0:e72ea6decc70 450 }
RobMeades 0:e72ea6decc70 451 else
RobMeades 0:e72ea6decc70 452 {
RobMeades 0:e72ea6decc70 453 if (digit >= 'A' && digit <= 'F')
RobMeades 0:e72ea6decc70 454 {
RobMeades 0:e72ea6decc70 455 nibbleValue = digit - 'A' + 10;
RobMeades 0:e72ea6decc70 456 }
RobMeades 0:e72ea6decc70 457 }
RobMeades 0:e72ea6decc70 458 }
RobMeades 0:e72ea6decc70 459
RobMeades 0:e72ea6decc70 460 return nibbleValue;
RobMeades 0:e72ea6decc70 461 }
RobMeades 0:e72ea6decc70 462
RobMeades 0:e72ea6decc70 463 // Take a hex value made up of digit1 and digit2
RobMeades 0:e72ea6decc70 464 // and return the corresponding byte value.
RobMeades 0:e72ea6decc70 465 // So if digit1 were 'a' and digit2 '3' the hex value
RobMeades 0:e72ea6decc70 466 // would be 0xA3. Invalid hex digits are ignored.
RobMeades 0:e72ea6decc70 467 static uint8_t hexTobyte (char digit1, char digit2)
RobMeades 0:e72ea6decc70 468 {
RobMeades 0:e72ea6decc70 469 return (hexToNibble (digit1) << 4) + hexToNibble (digit2);
RobMeades 0:e72ea6decc70 470 }
RobMeades 0:e72ea6decc70 471
RobMeades 0:e72ea6decc70 472 // See if a character has been entered
RobMeades 0:e72ea6decc70 473 // at the PC serial port and return it,
RobMeades 0:e72ea6decc70 474 // or otherwise return 0.
RobMeades 0:e72ea6decc70 475 static char peekChar (void)
RobMeades 0:e72ea6decc70 476 {
RobMeades 0:e72ea6decc70 477 char input = 0;
RobMeades 0:e72ea6decc70 478 Serial pc (USBTX, USBRX);
RobMeades 0:e72ea6decc70 479
RobMeades 0:e72ea6decc70 480 pc.baud (PC_BAUD_RATE);
RobMeades 0:e72ea6decc70 481
RobMeades 0:e72ea6decc70 482 if (pc.readable())
RobMeades 0:e72ea6decc70 483 {
RobMeades 0:e72ea6decc70 484 input = pc.getc();
RobMeades 0:e72ea6decc70 485 }
RobMeades 0:e72ea6decc70 486
RobMeades 0:e72ea6decc70 487 return input;
RobMeades 0:e72ea6decc70 488 }
RobMeades 0:e72ea6decc70 489
RobMeades 0:e72ea6decc70 490 // Wait for a character to be entered
RobMeades 0:e72ea6decc70 491 // at the PC serial port and return it.
RobMeades 0:e72ea6decc70 492 static char getChar (void)
RobMeades 0:e72ea6decc70 493 {
RobMeades 0:e72ea6decc70 494 Serial pc (USBTX, USBRX);
RobMeades 0:e72ea6decc70 495
RobMeades 0:e72ea6decc70 496 pc.baud (PC_BAUD_RATE);
RobMeades 0:e72ea6decc70 497
RobMeades 0:e72ea6decc70 498 return pc.getc();
RobMeades 0:e72ea6decc70 499 }
RobMeades 0:e72ea6decc70 500
RobMeades 0:e72ea6decc70 501 // Get a string of numbers from the user as a hex
RobMeades 0:e72ea6decc70 502 // string and store it as a string of bytes in buf
RobMeades 0:e72ea6decc70 503 // String entry is terminated with <enter>, which is
RobMeades 0:e72ea6decc70 504 // NOT stored with the string and also no
RobMeades 0:e72ea6decc70 505 // terminator is stored.
RobMeades 0:e72ea6decc70 506 // If characters that aren't a valid part of a hex
RobMeades 0:e72ea6decc70 507 // string are entered they will be ignored.
RobMeades 0:e72ea6decc70 508 static uint32_t getUserHexString (uint32_t size, char * buf)
RobMeades 0:e72ea6decc70 509 {
RobMeades 0:e72ea6decc70 510 char input;
RobMeades 0:e72ea6decc70 511 char hexChar1 = 0;
RobMeades 0:e72ea6decc70 512 bool done = false;
RobMeades 0:e72ea6decc70 513 uint32_t charCount = 0;
RobMeades 0:e72ea6decc70 514 uint32_t byteCount = 0;
RobMeades 0:e72ea6decc70 515 Serial pc (USBTX, USBRX);
RobMeades 0:e72ea6decc70 516
RobMeades 0:e72ea6decc70 517 pc.baud (PC_BAUD_RATE);
RobMeades 0:e72ea6decc70 518
RobMeades 0:e72ea6decc70 519 while (!done && (byteCount < size))
RobMeades 0:e72ea6decc70 520 {
RobMeades 0:e72ea6decc70 521 input = pc.getc();
RobMeades 0:e72ea6decc70 522 if (input == '\r')
RobMeades 0:e72ea6decc70 523 {
RobMeades 0:e72ea6decc70 524 done = true;
RobMeades 0:e72ea6decc70 525 }
RobMeades 0:e72ea6decc70 526 else
RobMeades 0:e72ea6decc70 527 {
RobMeades 0:e72ea6decc70 528 if (isValidHex(input))
RobMeades 0:e72ea6decc70 529 {
RobMeades 0:e72ea6decc70 530 pc.putc(input);
RobMeades 0:e72ea6decc70 531 if (IS_EVEN (charCount))
RobMeades 0:e72ea6decc70 532 {
RobMeades 0:e72ea6decc70 533 hexChar1 = input;
RobMeades 0:e72ea6decc70 534 }
RobMeades 0:e72ea6decc70 535 else
RobMeades 0:e72ea6decc70 536 {
RobMeades 0:e72ea6decc70 537 buf[byteCount] = hexTobyte(hexChar1, input);
RobMeades 0:e72ea6decc70 538 byteCount++;
RobMeades 0:e72ea6decc70 539 }
RobMeades 0:e72ea6decc70 540 charCount++;
RobMeades 0:e72ea6decc70 541 }
RobMeades 0:e72ea6decc70 542 }
RobMeades 0:e72ea6decc70 543 }
RobMeades 0:e72ea6decc70 544
RobMeades 0:e72ea6decc70 545 pc.putc('\n');
RobMeades 0:e72ea6decc70 546
RobMeades 0:e72ea6decc70 547 return byteCount;
RobMeades 0:e72ea6decc70 548 }
RobMeades 0:e72ea6decc70 549
RobMeades 0:e72ea6decc70 550 /// Print a byte string as hex
RobMeades 0:e72ea6decc70 551 static void printByteString (uint32_t size, const char * buf)
RobMeades 0:e72ea6decc70 552 {
RobMeades 0:e72ea6decc70 553 char hexBuf[MACTEST_STRING_MAX_SIZE * 2];
RobMeades 0:e72ea6decc70 554 uint32_t x = 0;
RobMeades 0:e72ea6decc70 555 uint32_t y = 0;
RobMeades 0:e72ea6decc70 556
RobMeades 0:e72ea6decc70 557 for (x = 0; (x < size) && (y < sizeof (hexBuf)); x++)
RobMeades 0:e72ea6decc70 558 {
RobMeades 0:e72ea6decc70 559 hexBuf[y] = hexTable[(buf[x] >> 4) & 0x0f]; // upper nibble
RobMeades 0:e72ea6decc70 560 y++;
RobMeades 0:e72ea6decc70 561 if (y < sizeof (hexBuf))
RobMeades 0:e72ea6decc70 562 {
RobMeades 0:e72ea6decc70 563 hexBuf[y] = hexTable[buf[x] & 0x0f]; // lower nibble
RobMeades 0:e72ea6decc70 564 y++;
RobMeades 0:e72ea6decc70 565 }
RobMeades 0:e72ea6decc70 566 }
RobMeades 0:e72ea6decc70 567
RobMeades 0:e72ea6decc70 568 printf ("%.*s", (int) y, hexBuf);
RobMeades 0:e72ea6decc70 569 }
RobMeades 0:e72ea6decc70 570
RobMeades 0:e72ea6decc70 571 // Print out the AT+MACTEST string
RobMeades 0:e72ea6decc70 572 static void printMactestString (uint32_t size, const char * string)
RobMeades 0:e72ea6decc70 573 {
RobMeades 0:e72ea6decc70 574 if (size > 0)
RobMeades 0:e72ea6decc70 575 {
RobMeades 0:e72ea6decc70 576 printf ("The MACTEST string will be:\n");
RobMeades 0:e72ea6decc70 577 printf ("AT+MACTEST=%d,", (int) size);
RobMeades 0:e72ea6decc70 578 printByteString(size, string);
RobMeades 0:e72ea6decc70 579 printf ("\n");
RobMeades 0:e72ea6decc70 580 }
RobMeades 0:e72ea6decc70 581 else
RobMeades 0:e72ea6decc70 582 {
RobMeades 0:e72ea6decc70 583 printf ("No MACTEST string has been set.\n");
RobMeades 0:e72ea6decc70 584 }
RobMeades 0:e72ea6decc70 585 }
RobMeades 0:e72ea6decc70 586
RobMeades 0:e72ea6decc70 587 // Enter transparent AT command mode until
RobMeades 0:e72ea6decc70 588 // CTRL-C is detected.
RobMeades 0:e72ea6decc70 589 static void transparentMode (void)
RobMeades 0:e72ea6decc70 590 {
RobMeades 0:e72ea6decc70 591 char input;
RobMeades 0:e72ea6decc70 592 bool done = false;
RobMeades 0:e72ea6decc70 593 Serial pc (USBTX, USBRX);
RobMeades 0:e72ea6decc70 594
RobMeades 0:e72ea6decc70 595 pc.baud (PC_BAUD_RATE);
RobMeades 0:e72ea6decc70 596
RobMeades 0:e72ea6decc70 597 while (!done)
RobMeades 0:e72ea6decc70 598 {
RobMeades 0:e72ea6decc70 599 // transfer data from pc to modem
RobMeades 0:e72ea6decc70 600 if (pc.readable() && pgNeul->writeable())
RobMeades 0:e72ea6decc70 601 {
RobMeades 0:e72ea6decc70 602 input = pc.getc();
RobMeades 0:e72ea6decc70 603 if (input == '\x03') // CTRL-C
RobMeades 0:e72ea6decc70 604 {
RobMeades 0:e72ea6decc70 605 done = true;
RobMeades 0:e72ea6decc70 606 }
RobMeades 0:e72ea6decc70 607 else
RobMeades 0:e72ea6decc70 608 {
RobMeades 0:e72ea6decc70 609 pc.putc (input); // echo
RobMeades 0:e72ea6decc70 610 pgNeul->putc (input);
RobMeades 0:e72ea6decc70 611 }
RobMeades 0:e72ea6decc70 612 }
RobMeades 0:e72ea6decc70 613
RobMeades 0:e72ea6decc70 614 // transfer data from modem to pc
RobMeades 0:e72ea6decc70 615 if (pgNeul->readable() && pc.writeable())
RobMeades 0:e72ea6decc70 616 {
RobMeades 0:e72ea6decc70 617 pc.putc (pgNeul->getc());
RobMeades 0:e72ea6decc70 618 }
RobMeades 0:e72ea6decc70 619 }
RobMeades 0:e72ea6decc70 620 }
RobMeades 0:e72ea6decc70 621
RobMeades 0:e72ea6decc70 622 // User configuration of the module
RobMeades 0:e72ea6decc70 623 // Should only be called after the module has been initialised
RobMeades 0:e72ea6decc70 624 static void configureModule (void)
RobMeades 0:e72ea6decc70 625 {
RobMeades 0:e72ea6decc70 626 bool done = false;
RobMeades 0:e72ea6decc70 627 uint32_t x;
RobMeades 0:e72ea6decc70 628
RobMeades 0:e72ea6decc70 629 printf ("%s\n", COLOUR_HIGHLIGHT);
RobMeades 0:e72ea6decc70 630 /* get the phase of the module */
RobMeades 0:e72ea6decc70 631 getModulePhase();
RobMeades 0:e72ea6decc70 632
RobMeades 0:e72ea6decc70 633 printf ("\n");
RobMeades 0:e72ea6decc70 634 if (gModulePhase == MODULE_PHASE_UNKNOWN)
RobMeades 0:e72ea6decc70 635 {
RobMeades 0:e72ea6decc70 636 printf ("Phase of module SW unknown, skipping config...\n");
RobMeades 0:e72ea6decc70 637 }
RobMeades 0:e72ea6decc70 638 else
RobMeades 0:e72ea6decc70 639 {
RobMeades 0:e72ea6decc70 640 if (gModulePhase == MODULE_PHASE_1)
RobMeades 0:e72ea6decc70 641 {
RobMeades 0:e72ea6decc70 642 // Print out the AT+MACTEST command on the debug port and give the PC side
RobMeades 0:e72ea6decc70 643 // some time to change it
RobMeades 0:e72ea6decc70 644 printMactestString (readNvContext()->mactestStringSize, readNvContext()->mactestString);
RobMeades 0:e72ea6decc70 645 printf ("Press 'y' within 5 seconds to change this, 'n' to continue. \n");
RobMeades 0:e72ea6decc70 646 }
RobMeades 0:e72ea6decc70 647 else
RobMeades 0:e72ea6decc70 648 {
RobMeades 0:e72ea6decc70 649 printf ("Press 'y' within 5 seconds to enter AT command mode. \n");
RobMeades 0:e72ea6decc70 650 }
RobMeades 0:e72ea6decc70 651
RobMeades 0:e72ea6decc70 652 for (x = 0; (x < USER_WAIT_DECISECONDS) && !done; x++)
RobMeades 0:e72ea6decc70 653 {
RobMeades 0:e72ea6decc70 654 char input;
RobMeades 0:e72ea6decc70 655 led = !led;
RobMeades 0:e72ea6decc70 656 wait_ms (100);
RobMeades 0:e72ea6decc70 657
RobMeades 0:e72ea6decc70 658 input = peekChar();
RobMeades 0:e72ea6decc70 659
RobMeades 0:e72ea6decc70 660 if (input != 0)
RobMeades 0:e72ea6decc70 661 {
RobMeades 0:e72ea6decc70 662 printf ("You pressed '%c' (0x%x).\n", input, input);
RobMeades 0:e72ea6decc70 663 }
RobMeades 0:e72ea6decc70 664
RobMeades 0:e72ea6decc70 665 if ((input == 'Y') || (input == 'y'))
RobMeades 0:e72ea6decc70 666 {
RobMeades 0:e72ea6decc70 667 uint32_t y;
RobMeades 0:e72ea6decc70 668
RobMeades 0:e72ea6decc70 669 led = 1;
RobMeades 0:e72ea6decc70 670
RobMeades 0:e72ea6decc70 671 if (gModulePhase == MODULE_PHASE_1)
RobMeades 0:e72ea6decc70 672 {
RobMeades 0:e72ea6decc70 673 while (!done)
RobMeades 0:e72ea6decc70 674 {
RobMeades 0:e72ea6decc70 675 char string[MACTEST_STRING_MAX_SIZE];
RobMeades 0:e72ea6decc70 676
RobMeades 0:e72ea6decc70 677 printf ("\n");
RobMeades 0:e72ea6decc70 678 printf ("Enter the new MACTEST string (just the part beyond the\n");
RobMeades 0:e72ea6decc70 679 printf ("comma) and press <enter>, or just press <enter> to clear\n");
RobMeades 0:e72ea6decc70 680 printf ("the current MACTEST string. Backspace/delete will not work\n");
RobMeades 0:e72ea6decc70 681 printf ("but you can check your entry, and try again, before it is\n");
RobMeades 0:e72ea6decc70 682 printf ("committed: ");
RobMeades 0:e72ea6decc70 683 y = getUserHexString (sizeof (string), string);
RobMeades 0:e72ea6decc70 684
RobMeades 0:e72ea6decc70 685 printf ("\n");
RobMeades 0:e72ea6decc70 686 printMactestString (y, string);
RobMeades 0:e72ea6decc70 687
RobMeades 0:e72ea6decc70 688 printf ("\n");
RobMeades 0:e72ea6decc70 689 printf ("Is this correct? Press 'y' to save it, 'n' to try again,\n");
RobMeades 0:e72ea6decc70 690 printf ("any other key to continue without changes. ");
RobMeades 0:e72ea6decc70 691 input = getChar();
RobMeades 0:e72ea6decc70 692 printf ("\nYou pressed '%d'.\n", input);
RobMeades 0:e72ea6decc70 693 if ((input == 'Y') || (input == 'y'))
RobMeades 0:e72ea6decc70 694 {
RobMeades 0:e72ea6decc70 695 printf ("Saving...\n");
RobMeades 0:e72ea6decc70 696 nvram.nvContext.mactestStringSize = y;
RobMeades 0:e72ea6decc70 697 memcpy (nvram.nvContext.mactestString, string, y);
RobMeades 0:e72ea6decc70 698 writeNvContext (&nvram);
RobMeades 0:e72ea6decc70 699 done = true;
RobMeades 0:e72ea6decc70 700 }
RobMeades 0:e72ea6decc70 701 else
RobMeades 0:e72ea6decc70 702 {
RobMeades 0:e72ea6decc70 703 if (input != 'N')
RobMeades 0:e72ea6decc70 704 {
RobMeades 0:e72ea6decc70 705 printf ("OK, continuing...\n");
RobMeades 0:e72ea6decc70 706 done = true;
RobMeades 0:e72ea6decc70 707 }
RobMeades 0:e72ea6decc70 708 }
RobMeades 0:e72ea6decc70 709 }
RobMeades 0:e72ea6decc70 710 }
RobMeades 0:e72ea6decc70 711 else
RobMeades 0:e72ea6decc70 712 {
RobMeades 0:e72ea6decc70 713 printf ("\n");
RobMeades 0:e72ea6decc70 714 printf ("You are now in transparent AT command mode with the modem.\n");
RobMeades 0:e72ea6decc70 715 printf ("Enter whatever commands are required to configure the modem\n");
RobMeades 0:e72ea6decc70 716 printf ("and press CTRL-C to continue.\n");
RobMeades 0:e72ea6decc70 717 transparentMode();
RobMeades 0:e72ea6decc70 718 done = true;
RobMeades 0:e72ea6decc70 719 printf ("\nContinuing...\n");
RobMeades 0:e72ea6decc70 720 }
RobMeades 0:e72ea6decc70 721 }
RobMeades 0:e72ea6decc70 722 else
RobMeades 0:e72ea6decc70 723 {
RobMeades 0:e72ea6decc70 724 if ((input == 'N') || (input == 'n'))
RobMeades 0:e72ea6decc70 725 {
RobMeades 0:e72ea6decc70 726 done = true;
RobMeades 0:e72ea6decc70 727 printf ("OK, continuing...\n");
RobMeades 0:e72ea6decc70 728 }
RobMeades 0:e72ea6decc70 729 }
RobMeades 0:e72ea6decc70 730 }
RobMeades 0:e72ea6decc70 731
RobMeades 0:e72ea6decc70 732 if (x == USER_WAIT_DECISECONDS)
RobMeades 0:e72ea6decc70 733 {
RobMeades 0:e72ea6decc70 734 printf ("Timed out, no key-press detected...\n");
RobMeades 0:e72ea6decc70 735 }
RobMeades 0:e72ea6decc70 736
RobMeades 0:e72ea6decc70 737 if ((gModulePhase == MODULE_PHASE_1) && (readNvContext()->mactestStringSize > 0))
RobMeades 0:e72ea6decc70 738 {
RobMeades 0:e72ea6decc70 739 // Send the mactest string to the module
RobMeades 0:e72ea6decc70 740 // No need to do anything for a phase 2 module SW as those values are stored
RobMeades 0:e72ea6decc70 741 // in NVRAM inside the module
RobMeades 0:e72ea6decc70 742 printf ("Sending the MACTEST string to the module...\n");
RobMeades 0:e72ea6decc70 743 if (pgNeul->sendMactest (readNvContext()->mactestStringSize, readNvContext()->mactestString))
RobMeades 0:e72ea6decc70 744 {
RobMeades 0:e72ea6decc70 745 printf ("Done.\n");
RobMeades 0:e72ea6decc70 746 }
RobMeades 0:e72ea6decc70 747 else
RobMeades 0:e72ea6decc70 748 {
RobMeades 0:e72ea6decc70 749 printf ("Module responded with ERROR.\n");
RobMeades 0:e72ea6decc70 750 }
RobMeades 0:e72ea6decc70 751 }
RobMeades 0:e72ea6decc70 752 }
RobMeades 0:e72ea6decc70 753
RobMeades 0:e72ea6decc70 754 led = 0;
RobMeades 0:e72ea6decc70 755
RobMeades 0:e72ea6decc70 756 printf (COLOUR_DEFAULT);
RobMeades 0:e72ea6decc70 757 }
RobMeades 0:e72ea6decc70 758
RobMeades 0:e72ea6decc70 759 // Asserts
RobMeades 0:e72ea6decc70 760 static void assert (bool condition, DebugSosType_t debugSosType, const char * pFormat, ...)
RobMeades 0:e72ea6decc70 761 {
RobMeades 0:e72ea6decc70 762 if (!condition)
RobMeades 0:e72ea6decc70 763 {
RobMeades 0:e72ea6decc70 764 printf ("\n!!! ASSERT !!! ASSERT !!! ASSERT !!! ASSERT !!! ASSERT !!!\n");
RobMeades 0:e72ea6decc70 765 va_list args;
RobMeades 0:e72ea6decc70 766 va_start (args, pFormat);
RobMeades 0:e72ea6decc70 767 printf (pFormat, args);
RobMeades 0:e72ea6decc70 768 va_end (args);
RobMeades 0:e72ea6decc70 769 printf ("\n!!! ASSERT !!! ASSERT !!! ASSERT !!! ASSERT !!! ASSERT !!!\n\n\n");
RobMeades 0:e72ea6decc70 770 wait_ms (2000);
RobMeades 0:e72ea6decc70 771 setWakeUpCode ((WakeUpCode_t) debugSosType);
RobMeades 0:e72ea6decc70 772 debugSos (debugSosType);
RobMeades 0:e72ea6decc70 773 }
RobMeades 0:e72ea6decc70 774 }
RobMeades 0:e72ea6decc70 775
RobMeades 0:e72ea6decc70 776 static void assertAlways (DebugSosType_t debugSosType, const char * pFormat, ...)
RobMeades 0:e72ea6decc70 777 {
RobMeades 0:e72ea6decc70 778 assert (false, debugSosType, pFormat);
RobMeades 0:e72ea6decc70 779 }
RobMeades 0:e72ea6decc70 780
RobMeades 0:e72ea6decc70 781 /// Write to NVRAM, returning true if successful,
RobMeades 0:e72ea6decc70 782 // otherwise false. The pointer pNvContext must be
RobMeades 0:e72ea6decc70 783 // on a 4 byte boundary and the structure size must
RobMeades 0:e72ea6decc70 784 // be a multiple of 4.
RobMeades 0:e72ea6decc70 785 static bool writeNvContext (Nvram_t * pNvram)
RobMeades 0:e72ea6decc70 786 {
RobMeades 0:e72ea6decc70 787 bool success = false;
RobMeades 0:e72ea6decc70 788 uint32_t iapResult;
RobMeades 0:e72ea6decc70 789
RobMeades 0:e72ea6decc70 790 #ifdef DEBUG
RobMeades 0:e72ea6decc70 791 printf ("Writing structure at 0x%08x to NVRAM.\n", pNvram);
RobMeades 0:e72ea6decc70 792 #endif
RobMeades 0:e72ea6decc70 793 assert (((((uint32_t) pNvram) & 0x03) == 0), DEBUG_SOS_GENERIC_FAILURE, "pNvContext must be on a 4 byte boundary.");
RobMeades 0:e72ea6decc70 794 assert (((sizeof (pNvram->rawBytes) & 0x03) == 0), DEBUG_SOS_GENERIC_FAILURE, "sizeof (pNvram->rawBytes) must be a multiple of 4.");
RobMeades 0:e72ea6decc70 795
RobMeades 0:e72ea6decc70 796 // Blank check: mbed erases all flash contents after downloading a new executable
RobMeades 0:e72ea6decc70 797 iapResult = iap.blank_check (FLASH_SECTOR (USER_FLASH_AREA_START), FLASH_SECTOR (USER_FLASH_AREA_START));
RobMeades 0:e72ea6decc70 798 #ifdef DEBUG
RobMeades 0:e72ea6decc70 799 printf ("NVRAM: blank check result = 0x%x\n", iapResult);
RobMeades 0:e72ea6decc70 800 #endif
RobMeades 0:e72ea6decc70 801
RobMeades 0:e72ea6decc70 802 // Erase sector, if required
RobMeades 0:e72ea6decc70 803 if (iapResult == SECTOR_NOT_BLANK)
RobMeades 0:e72ea6decc70 804 {
RobMeades 0:e72ea6decc70 805 iap.prepare (FLASH_SECTOR (USER_FLASH_AREA_START), FLASH_SECTOR (USER_FLASH_AREA_START));
RobMeades 0:e72ea6decc70 806 iapResult = iap.erase (FLASH_SECTOR (USER_FLASH_AREA_START), FLASH_SECTOR (USER_FLASH_AREA_START));
RobMeades 0:e72ea6decc70 807 #ifdef DEBUG
RobMeades 0:e72ea6decc70 808 printf ("NVRAM: erase result = 0x%x\n", iapResult);
RobMeades 0:e72ea6decc70 809 #endif
RobMeades 0:e72ea6decc70 810 }
RobMeades 0:e72ea6decc70 811
RobMeades 0:e72ea6decc70 812 // Copy RAM to Flash
RobMeades 0:e72ea6decc70 813 iap.prepare (FLASH_SECTOR (USER_FLASH_AREA_START), FLASH_SECTOR (USER_FLASH_AREA_START));
RobMeades 0:e72ea6decc70 814 iapResult = iap.write (&(pNvram->rawBytes[0]), sector_start_adress[FLASH_SECTOR (USER_FLASH_AREA_START)], sizeof (pNvram->rawBytes));
RobMeades 0:e72ea6decc70 815 #ifdef DEBUG
RobMeades 0:e72ea6decc70 816 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);
RobMeades 0:e72ea6decc70 817 #endif
RobMeades 0:e72ea6decc70 818
RobMeades 0:e72ea6decc70 819 // Compare
RobMeades 0:e72ea6decc70 820 iapResult = iap.compare (&(pNvram->rawBytes[0]), sector_start_adress[FLASH_SECTOR (USER_FLASH_AREA_START)], sizeof (pNvram->rawBytes));
RobMeades 0:e72ea6decc70 821 printf ("NVRAM: compare result = \"%s\"\n", iapResult ? "FAILED" : "OK" );
RobMeades 0:e72ea6decc70 822 if (iapResult == CMD_SUCCESS)
RobMeades 0:e72ea6decc70 823 {
RobMeades 0:e72ea6decc70 824 success = true;
RobMeades 0:e72ea6decc70 825 }
RobMeades 0:e72ea6decc70 826
RobMeades 0:e72ea6decc70 827 return success;
RobMeades 0:e72ea6decc70 828 }
RobMeades 0:e72ea6decc70 829
RobMeades 0:e72ea6decc70 830 /// Write defaults to NVRAM and return
RobMeades 0:e72ea6decc70 831 // a pointer to the reset contents.
RobMeades 0:e72ea6decc70 832 static NvContext_t * resetNvContext (void)
RobMeades 0:e72ea6decc70 833 {
RobMeades 0:e72ea6decc70 834 printf ("*** Resetting NVRAM to defaults.\n");
RobMeades 0:e72ea6decc70 835
RobMeades 0:e72ea6decc70 836 nvram.nvContext.id = NVRAM_ID;
RobMeades 0:e72ea6decc70 837 nvram.nvContext.devModeOnNotOff = false;
RobMeades 0:e72ea6decc70 838 nvram.nvContext.wakeUpCode = WAKE_UP_CODE_OK;
RobMeades 0:e72ea6decc70 839 nvram.nvContext.readingIntervalSeconds = DEFAULT_READING_INTERVAL_SECONDS;
RobMeades 0:e72ea6decc70 840 nvram.nvContext.flashOnNotOff = true;
RobMeades 0:e72ea6decc70 841 nvram.nvContext.ledOnNotOff = false;
RobMeades 0:e72ea6decc70 842 memcpy (nvram.nvContext.mactestString, defaultMactestString, sizeof (defaultMactestString));
RobMeades 0:e72ea6decc70 843 nvram.nvContext.mactestStringSize = sizeof (defaultMactestString);
RobMeades 0:e72ea6decc70 844
RobMeades 0:e72ea6decc70 845 // Ignore the return value - must always return an answer
RobMeades 0:e72ea6decc70 846 writeNvContext (&nvram);
RobMeades 0:e72ea6decc70 847
RobMeades 0:e72ea6decc70 848 return &(nvram.nvContext);
RobMeades 0:e72ea6decc70 849 }
RobMeades 0:e72ea6decc70 850
RobMeades 0:e72ea6decc70 851 /// Read from NVRAM, always guaranteed to produce
RobMeades 0:e72ea6decc70 852 // a result (may be default values).
RobMeades 0:e72ea6decc70 853 static NvContext_t * readNvContext (void)
RobMeades 0:e72ea6decc70 854 {
RobMeades 0:e72ea6decc70 855 NvContext_t * pNvContext = NULL;
RobMeades 0:e72ea6decc70 856 uint32_t iapResult;
RobMeades 0:e72ea6decc70 857
RobMeades 0:e72ea6decc70 858 // Blank check
RobMeades 0:e72ea6decc70 859 iapResult = iap.blank_check (FLASH_SECTOR (USER_FLASH_AREA_START), FLASH_SECTOR (USER_FLASH_AREA_START));
RobMeades 0:e72ea6decc70 860
RobMeades 0:e72ea6decc70 861 if (iapResult == SECTOR_NOT_BLANK)
RobMeades 0:e72ea6decc70 862 {
RobMeades 0:e72ea6decc70 863 if (nvram.nvContext.id != NVRAM_ID)
RobMeades 0:e72ea6decc70 864 {
RobMeades 0:e72ea6decc70 865 #ifdef DEBUG
RobMeades 0:e72ea6decc70 866 printf ("Loading NVRAM...\n");
RobMeades 0:e72ea6decc70 867 #endif
RobMeades 0:e72ea6decc70 868 memcpy (&(nvram.rawBytes[0]), (const char *) USER_FLASH_AREA_START, sizeof (nvram.rawBytes));
RobMeades 0:e72ea6decc70 869 }
RobMeades 0:e72ea6decc70 870
RobMeades 0:e72ea6decc70 871 if (nvram.nvContext.id == NVRAM_ID)
RobMeades 0:e72ea6decc70 872 {
RobMeades 0:e72ea6decc70 873 // Contents are valid
RobMeades 0:e72ea6decc70 874 pNvContext = &(nvram.nvContext);
RobMeades 0:e72ea6decc70 875 }
RobMeades 0:e72ea6decc70 876 else
RobMeades 0:e72ea6decc70 877 {
RobMeades 0:e72ea6decc70 878 #ifdef DEBUG
RobMeades 0:e72ea6decc70 879 printf ("NVRAM contents invalid.\n");
RobMeades 0:e72ea6decc70 880 // Contents are not valid so set them up
RobMeades 0:e72ea6decc70 881 #endif
RobMeades 0:e72ea6decc70 882 pNvContext = resetNvContext ();
RobMeades 0:e72ea6decc70 883 }
RobMeades 0:e72ea6decc70 884 }
RobMeades 0:e72ea6decc70 885 else
RobMeades 0:e72ea6decc70 886 {
RobMeades 0:e72ea6decc70 887 #ifdef DEBUG
RobMeades 0:e72ea6decc70 888 printf ("NVRAM blank.\n");
RobMeades 0:e72ea6decc70 889 #endif
RobMeades 0:e72ea6decc70 890 // Contents are not there so set them up
RobMeades 0:e72ea6decc70 891 pNvContext = resetNvContext ();
RobMeades 0:e72ea6decc70 892 }
RobMeades 0:e72ea6decc70 893
RobMeades 0:e72ea6decc70 894 return pNvContext;
RobMeades 0:e72ea6decc70 895 }
RobMeades 0:e72ea6decc70 896
RobMeades 0:e72ea6decc70 897 /// Do the flash thing, should be called on a Send
RobMeades 0:e72ea6decc70 898 static void doSendFlash (void)
RobMeades 0:e72ea6decc70 899 {
RobMeades 0:e72ea6decc70 900 if (readNvContext()->flashOnNotOff)
RobMeades 0:e72ea6decc70 901 {
RobMeades 0:e72ea6decc70 902 led = !led;
RobMeades 0:e72ea6decc70 903 wait_ms (FLASH_DURATION_MS);
RobMeades 0:e72ea6decc70 904 led = !led;
RobMeades 0:e72ea6decc70 905 }
RobMeades 0:e72ea6decc70 906 }
RobMeades 0:e72ea6decc70 907
RobMeades 0:e72ea6decc70 908 /// Do the other flash thing, should be called on a Receive
RobMeades 0:e72ea6decc70 909 static void doRecvFlash (void)
RobMeades 0:e72ea6decc70 910 {
RobMeades 0:e72ea6decc70 911 if (readNvContext()->flashOnNotOff)
RobMeades 0:e72ea6decc70 912 {
RobMeades 0:e72ea6decc70 913 led = !led;
RobMeades 0:e72ea6decc70 914 wait_ms (FLASH_DURATION_MS /4);
RobMeades 0:e72ea6decc70 915 led = !led;
RobMeades 0:e72ea6decc70 916 wait_ms (FLASH_DURATION_MS /4);
RobMeades 0:e72ea6decc70 917 led = !led;
RobMeades 0:e72ea6decc70 918 wait_ms (FLASH_DURATION_MS /4);
RobMeades 0:e72ea6decc70 919 led = !led;
RobMeades 0:e72ea6decc70 920 }
RobMeades 0:e72ea6decc70 921 }
RobMeades 0:e72ea6decc70 922
RobMeades 0:e72ea6decc70 923 /// Set the state of a GPIO
RobMeades 0:e72ea6decc70 924 static bool setGpio (GpioState_t * pGpioState)
RobMeades 0:e72ea6decc70 925 {
RobMeades 0:e72ea6decc70 926 bool success = false;
RobMeades 0:e72ea6decc70 927
RobMeades 0:e72ea6decc70 928 if (pGpioState->gpio < (sizeof (gpioTable) / sizeof (gpioTable[0])))
RobMeades 0:e72ea6decc70 929 {
RobMeades 0:e72ea6decc70 930 if (pGpioState->inputNotOutput)
RobMeades 0:e72ea6decc70 931 {
RobMeades 0:e72ea6decc70 932 DigitalIn((PinName) gpioTable[pGpioState->gpio]);
RobMeades 0:e72ea6decc70 933 }
RobMeades 0:e72ea6decc70 934 else
RobMeades 0:e72ea6decc70 935 {
RobMeades 0:e72ea6decc70 936 DigitalOut * pOutput = new DigitalOut((PinName) gpioTable[pGpioState->gpio]);
RobMeades 0:e72ea6decc70 937 *pOutput = pGpioState->onNotOff;
RobMeades 0:e72ea6decc70 938 }
RobMeades 0:e72ea6decc70 939 success = true;
RobMeades 0:e72ea6decc70 940 }
RobMeades 0:e72ea6decc70 941
RobMeades 0:e72ea6decc70 942 return success;
RobMeades 0:e72ea6decc70 943 }
RobMeades 0:e72ea6decc70 944
RobMeades 0:e72ea6decc70 945 /// Get the state of a GPIO
RobMeades 0:e72ea6decc70 946 static bool getGpio (GpioState_t * pGpioState)
RobMeades 0:e72ea6decc70 947 {
RobMeades 0:e72ea6decc70 948 bool success = false;
RobMeades 0:e72ea6decc70 949
RobMeades 0:e72ea6decc70 950 if (pGpioState->gpio < (sizeof (gpioTable) / sizeof (gpioTable[0])))
RobMeades 0:e72ea6decc70 951 {
RobMeades 0:e72ea6decc70 952 if (pGpioState->inputNotOutput)
RobMeades 0:e72ea6decc70 953 {
RobMeades 0:e72ea6decc70 954 DigitalIn *pInput = new DigitalIn((PinName) gpioTable[pGpioState->gpio]);
RobMeades 0:e72ea6decc70 955 pGpioState->onNotOff = *pInput;
RobMeades 0:e72ea6decc70 956 }
RobMeades 0:e72ea6decc70 957 else
RobMeades 0:e72ea6decc70 958 {
RobMeades 0:e72ea6decc70 959 DigitalOut *pOutput = new DigitalOut((PinName) gpioTable[pGpioState->gpio]);
RobMeades 0:e72ea6decc70 960 pGpioState->onNotOff = *pOutput;
RobMeades 0:e72ea6decc70 961 }
RobMeades 0:e72ea6decc70 962 success = true;
RobMeades 0:e72ea6decc70 963 }
RobMeades 0:e72ea6decc70 964
RobMeades 0:e72ea6decc70 965 return success;
RobMeades 0:e72ea6decc70 966 }
RobMeades 0:e72ea6decc70 967
RobMeades 0:e72ea6decc70 968 /// Set the wake-up code
RobMeades 0:e72ea6decc70 969 static void setWakeUpCode (WakeUpCode_t wakeUpCode)
RobMeades 0:e72ea6decc70 970 {
RobMeades 0:e72ea6decc70 971 if (nvram.nvContext.wakeUpCode != wakeUpCode)
RobMeades 0:e72ea6decc70 972 {
RobMeades 0:e72ea6decc70 973 nvram.nvContext.id = NVRAM_ID;
RobMeades 0:e72ea6decc70 974 nvram.nvContext.wakeUpCode = wakeUpCode;
RobMeades 0:e72ea6decc70 975 writeNvContext (&nvram);
RobMeades 0:e72ea6decc70 976 }
RobMeades 0:e72ea6decc70 977 }
RobMeades 0:e72ea6decc70 978
RobMeades 0:e72ea6decc70 979 /// Set development mode
RobMeades 0:e72ea6decc70 980 static void setDevMode (bool onNotOff)
RobMeades 0:e72ea6decc70 981 {
RobMeades 0:e72ea6decc70 982 if (nvram.nvContext.devModeOnNotOff != onNotOff)
RobMeades 0:e72ea6decc70 983 {
RobMeades 0:e72ea6decc70 984 nvram.nvContext.id = NVRAM_ID;
RobMeades 0:e72ea6decc70 985 nvram.nvContext.devModeOnNotOff = onNotOff;
RobMeades 0:e72ea6decc70 986 writeNvContext (&nvram);
RobMeades 0:e72ea6decc70 987 }
RobMeades 0:e72ea6decc70 988 }
RobMeades 0:e72ea6decc70 989
RobMeades 0:e72ea6decc70 990 /// Set the reading interval in seconds
RobMeades 0:e72ea6decc70 991 static void setReadingIntervalSeconds (uint32_t readingIntervalSeconds)
RobMeades 0:e72ea6decc70 992 {
RobMeades 0:e72ea6decc70 993 if (nvram.nvContext.readingIntervalSeconds != readingIntervalSeconds)
RobMeades 0:e72ea6decc70 994 {
RobMeades 0:e72ea6decc70 995 nvram.nvContext.id = NVRAM_ID;
RobMeades 0:e72ea6decc70 996 nvram.nvContext.readingIntervalSeconds = readingIntervalSeconds;
RobMeades 0:e72ea6decc70 997 writeNvContext (&nvram);
RobMeades 0:e72ea6decc70 998 }
RobMeades 0:e72ea6decc70 999 }
RobMeades 0:e72ea6decc70 1000
RobMeades 0:e72ea6decc70 1001 /// Set the LED state
RobMeades 0:e72ea6decc70 1002 static void setLed (bool onNotOff)
RobMeades 0:e72ea6decc70 1003 {
RobMeades 0:e72ea6decc70 1004 if (nvram.nvContext.ledOnNotOff != onNotOff)
RobMeades 0:e72ea6decc70 1005 {
RobMeades 0:e72ea6decc70 1006 nvram.nvContext.id = NVRAM_ID;
RobMeades 0:e72ea6decc70 1007 nvram.nvContext.ledOnNotOff = onNotOff;
RobMeades 0:e72ea6decc70 1008 writeNvContext (&nvram);
RobMeades 0:e72ea6decc70 1009 }
RobMeades 0:e72ea6decc70 1010 led = nvram.nvContext.ledOnNotOff;
RobMeades 0:e72ea6decc70 1011 }
RobMeades 0:e72ea6decc70 1012
RobMeades 0:e72ea6decc70 1013 /// Set the Flash state
RobMeades 0:e72ea6decc70 1014 static void setFlash (bool onNotOff)
RobMeades 0:e72ea6decc70 1015 {
RobMeades 0:e72ea6decc70 1016 if (nvram.nvContext.flashOnNotOff != onNotOff)
RobMeades 0:e72ea6decc70 1017 {
RobMeades 0:e72ea6decc70 1018 nvram.nvContext.id = NVRAM_ID;
RobMeades 0:e72ea6decc70 1019 nvram.nvContext.flashOnNotOff = onNotOff;
RobMeades 0:e72ea6decc70 1020 writeNvContext (&nvram);
RobMeades 0:e72ea6decc70 1021 }
RobMeades 0:e72ea6decc70 1022 }
RobMeades 0:e72ea6decc70 1023
RobMeades 0:e72ea6decc70 1024 /// Initialise ourselves
RobMeades 0:e72ea6decc70 1025 static bool init (void)
RobMeades 0:e72ea6decc70 1026 {
RobMeades 0:e72ea6decc70 1027 bool success = true;
RobMeades 0:e72ea6decc70 1028 uint32_t x;
RobMeades 0:e72ea6decc70 1029 GpioState_t waterPumpGpio = {GPIO_WATER_PUMP, false, false};
RobMeades 0:e72ea6decc70 1030 DatagramEntry_t * pPrevEntry = &gFreeDatagramListHeadUnused;
RobMeades 0:e72ea6decc70 1031 DatagramEntry_t ** ppEntry = &(gFreeDatagramListHeadUnused.pNextEntry);
RobMeades 0:e72ea6decc70 1032
RobMeades 0:e72ea6decc70 1033 memset (&gFreeDatagramListHeadUnused, 0, sizeof (gFreeDatagramListHeadUnused));
RobMeades 0:e72ea6decc70 1034 memset (&gSendDatagramListHead, 0, sizeof (gSendDatagramListHead));
RobMeades 0:e72ea6decc70 1035 memset (&gRecvDatagramListHead, 0, sizeof (gRecvDatagramListHead));
RobMeades 0:e72ea6decc70 1036
RobMeades 0:e72ea6decc70 1037 // Create a malloc()ed free list attached to the (unused) static
RobMeades 0:e72ea6decc70 1038 // head of the free list
RobMeades 0:e72ea6decc70 1039 for (x = 1; (x < MAX_NUM_DATAGRAMS) && success; x++) // from 1 as it's from head.pNextEntry onwards
RobMeades 0:e72ea6decc70 1040 {
RobMeades 0:e72ea6decc70 1041 *ppEntry = (DatagramEntry_t *) malloc (sizeof (DatagramEntry_t));
RobMeades 0:e72ea6decc70 1042 if (*ppEntry != NULL)
RobMeades 0:e72ea6decc70 1043 {
RobMeades 0:e72ea6decc70 1044 memset (*ppEntry, 0, sizeof (**ppEntry));
RobMeades 0:e72ea6decc70 1045 // Link it in
RobMeades 0:e72ea6decc70 1046 (*ppEntry)->pPrevEntry = pPrevEntry;
RobMeades 0:e72ea6decc70 1047 (*ppEntry)->pNextEntry = NULL;
RobMeades 0:e72ea6decc70 1048 (*ppEntry)->inUse = false;
RobMeades 0:e72ea6decc70 1049 if (pPrevEntry != NULL)
RobMeades 0:e72ea6decc70 1050 {
RobMeades 0:e72ea6decc70 1051 pPrevEntry->pNextEntry = *ppEntry;
RobMeades 0:e72ea6decc70 1052 }
RobMeades 0:e72ea6decc70 1053 pPrevEntry = *ppEntry;
RobMeades 0:e72ea6decc70 1054
RobMeades 0:e72ea6decc70 1055 // Next
RobMeades 0:e72ea6decc70 1056 ppEntry = &((*ppEntry)->pNextEntry);
RobMeades 0:e72ea6decc70 1057 }
RobMeades 0:e72ea6decc70 1058 else
RobMeades 0:e72ea6decc70 1059 {
RobMeades 0:e72ea6decc70 1060 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "failed malloc().");
RobMeades 0:e72ea6decc70 1061 success = false;
RobMeades 0:e72ea6decc70 1062 }
RobMeades 0:e72ea6decc70 1063 }
RobMeades 0:e72ea6decc70 1064
RobMeades 0:e72ea6decc70 1065 #ifdef DEBUG
RobMeades 0:e72ea6decc70 1066 debugPrintLists ();
RobMeades 0:e72ea6decc70 1067 #endif
RobMeades 0:e72ea6decc70 1068
RobMeades 0:e72ea6decc70 1069 if (success)
RobMeades 0:e72ea6decc70 1070 {
RobMeades 0:e72ea6decc70 1071 /* set the water pump control pin to an output and to off */
RobMeades 0:e72ea6decc70 1072 success = setGpio (&waterPumpGpio);
RobMeades 0:e72ea6decc70 1073 assert (success, DEBUG_SOS_GENERIC_FAILURE, "failed to set water pump pin.");
RobMeades 0:e72ea6decc70 1074
RobMeades 0:e72ea6decc70 1075 if (success)
RobMeades 0:e72ea6decc70 1076 {
RobMeades 0:e72ea6decc70 1077 // Check NVRAM
RobMeades 0:e72ea6decc70 1078 printf ("\n=== IAP: NVRAM check ===\n");
RobMeades 0:e72ea6decc70 1079 printf (" device-ID = 0x%08x\n", iap.read_ID());
RobMeades 0:e72ea6decc70 1080 printf (" serial# = 0x%08x\n", iap.read_serial());
RobMeades 0:e72ea6decc70 1081 printf (" CPU running at %ld MHz\n", SystemCoreClock / 1000000);
RobMeades 0:e72ea6decc70 1082 printf (" user reserved flash area: start_address = 0x%08lx\n", (long unsigned int) iap.reserved_flash_area_start());
RobMeades 0:e72ea6decc70 1083 printf (" size = %d bytes\n", iap.reserved_flash_area_size());
RobMeades 0:e72ea6decc70 1084 printf (" read_BootVer = 0x%08x\n", iap.read_BootVer());
RobMeades 0:e72ea6decc70 1085 printf (" local ID value = 0x%08lx\n", readNvContext()->id);
RobMeades 0:e72ea6decc70 1086
RobMeades 0:e72ea6decc70 1087 // And finally, setup the LED.
RobMeades 0:e72ea6decc70 1088 led = readNvContext()->ledOnNotOff;
RobMeades 0:e72ea6decc70 1089 }
RobMeades 0:e72ea6decc70 1090 }
RobMeades 0:e72ea6decc70 1091
RobMeades 0:e72ea6decc70 1092 return success;
RobMeades 0:e72ea6decc70 1093 }
RobMeades 0:e72ea6decc70 1094
RobMeades 0:e72ea6decc70 1095 /// Tidy up
RobMeades 0:e72ea6decc70 1096 static void deInit (void)
RobMeades 0:e72ea6decc70 1097 {
RobMeades 0:e72ea6decc70 1098 uint32_t x = 0;
RobMeades 0:e72ea6decc70 1099 DatagramEntry_t * pEntry = NULL;
RobMeades 0:e72ea6decc70 1100
RobMeades 0:e72ea6decc70 1101 // Return send datagram memory to the free list
RobMeades 0:e72ea6decc70 1102 freeAllDatagrams (&gSendDatagramListHead);
RobMeades 0:e72ea6decc70 1103 // Return receive datagram memory to the free list
RobMeades 0:e72ea6decc70 1104 freeAllDatagrams (&gRecvDatagramListHead);
RobMeades 0:e72ea6decc70 1105
RobMeades 0:e72ea6decc70 1106 // Free the free list from the end
RobMeades 0:e72ea6decc70 1107 pEntry = &gFreeDatagramListHeadUnused;
RobMeades 0:e72ea6decc70 1108 for (x = 0; (pEntry->pNextEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
RobMeades 0:e72ea6decc70 1109 {
RobMeades 0:e72ea6decc70 1110 pEntry = pEntry->pNextEntry;
RobMeades 0:e72ea6decc70 1111 }
RobMeades 0:e72ea6decc70 1112 for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
RobMeades 0:e72ea6decc70 1113 {
RobMeades 0:e72ea6decc70 1114 DatagramEntry_t * pNextOne = pEntry->pPrevEntry;
RobMeades 0:e72ea6decc70 1115 free (pEntry);
RobMeades 0:e72ea6decc70 1116 pEntry = pNextOne;
RobMeades 0:e72ea6decc70 1117 }
RobMeades 0:e72ea6decc70 1118 }
RobMeades 0:e72ea6decc70 1119
RobMeades 0:e72ea6decc70 1120 /// Allocate room for a datagram from the given list, returning a pointer
RobMeades 0:e72ea6decc70 1121 // to it or NULL if unsuccessful
RobMeades 0:e72ea6decc70 1122 static Datagram_t * allocDatagram (DatagramEntry_t * pDatagramListHead)
RobMeades 0:e72ea6decc70 1123 {
RobMeades 0:e72ea6decc70 1124 Datagram_t * pAlloc = NULL;
RobMeades 0:e72ea6decc70 1125 uint32_t x = 0;
RobMeades 0:e72ea6decc70 1126 DatagramEntry_t * pEntry;
RobMeades 0:e72ea6decc70 1127
RobMeades 0:e72ea6decc70 1128 // If there is already an unused entry in the list, just return it
RobMeades 0:e72ea6decc70 1129 pEntry = pDatagramListHead;
RobMeades 0:e72ea6decc70 1130 for (x = 0; (pEntry != NULL) && (pEntry->inUse) && (x < MAX_NUM_DATAGRAMS); x++)
RobMeades 0:e72ea6decc70 1131 {
RobMeades 0:e72ea6decc70 1132 pEntry = pEntry->pNextEntry;
RobMeades 0:e72ea6decc70 1133 }
RobMeades 0:e72ea6decc70 1134
RobMeades 0:e72ea6decc70 1135 if ((pEntry != NULL) && (!pEntry->inUse))
RobMeades 0:e72ea6decc70 1136 {
RobMeades 0:e72ea6decc70 1137 #ifdef DEBUG
RobMeades 0:e72ea6decc70 1138 printf ("allocDatagram: found existing unused entry in list.\n");
RobMeades 0:e72ea6decc70 1139 #endif
RobMeades 0:e72ea6decc70 1140 // Good, use this one
RobMeades 0:e72ea6decc70 1141 memset (&(pEntry->datagram), 0, sizeof (pEntry->datagram));
RobMeades 0:e72ea6decc70 1142 pEntry->inUse = true;
RobMeades 0:e72ea6decc70 1143 pAlloc = &(pEntry->datagram);
RobMeades 0:e72ea6decc70 1144 }
RobMeades 0:e72ea6decc70 1145 else
RobMeades 0:e72ea6decc70 1146 {
RobMeades 0:e72ea6decc70 1147 #ifdef DEBUG
RobMeades 0:e72ea6decc70 1148 printf ("allocDatagram: finding malloc()ed entry in the free list...\n");
RobMeades 0:e72ea6decc70 1149 #endif
RobMeades 0:e72ea6decc70 1150 // Find the malloc()ed entry at the end of the free list
RobMeades 0:e72ea6decc70 1151 pEntry = &gFreeDatagramListHeadUnused;
RobMeades 0:e72ea6decc70 1152 for (x = 0; (pEntry->pNextEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
RobMeades 0:e72ea6decc70 1153 {
RobMeades 0:e72ea6decc70 1154 pEntry = pEntry->pNextEntry;
RobMeades 0:e72ea6decc70 1155 }
RobMeades 0:e72ea6decc70 1156
RobMeades 0:e72ea6decc70 1157 // If there is one, move it to the given list
RobMeades 0:e72ea6decc70 1158 if ((pEntry != NULL) && (pEntry->pNextEntry == NULL) && pEntry != &gFreeDatagramListHeadUnused)
RobMeades 0:e72ea6decc70 1159 {
RobMeades 0:e72ea6decc70 1160 DatagramEntry_t * pWantedEntry = pEntry;
RobMeades 0:e72ea6decc70 1161
RobMeades 0:e72ea6decc70 1162 // Unlink it from the end of the free list
RobMeades 0:e72ea6decc70 1163 if (pWantedEntry->pPrevEntry != NULL)
RobMeades 0:e72ea6decc70 1164 {
RobMeades 0:e72ea6decc70 1165 pWantedEntry->pPrevEntry->pNextEntry = pWantedEntry->pNextEntry;
RobMeades 0:e72ea6decc70 1166 pWantedEntry->pPrevEntry = NULL;
RobMeades 0:e72ea6decc70 1167 }
RobMeades 0:e72ea6decc70 1168
RobMeades 0:e72ea6decc70 1169 // Attach it to the end of the given list
RobMeades 0:e72ea6decc70 1170 pEntry = pDatagramListHead;
RobMeades 0:e72ea6decc70 1171 for (x = 0; (pEntry->pNextEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
RobMeades 0:e72ea6decc70 1172 {
RobMeades 0:e72ea6decc70 1173 pEntry = pEntry->pNextEntry;
RobMeades 0:e72ea6decc70 1174 }
RobMeades 0:e72ea6decc70 1175
RobMeades 0:e72ea6decc70 1176 if (pEntry->pNextEntry == NULL)
RobMeades 0:e72ea6decc70 1177 {
RobMeades 0:e72ea6decc70 1178 pEntry->pNextEntry = pWantedEntry;
RobMeades 0:e72ea6decc70 1179 pWantedEntry->pPrevEntry = pEntry;
RobMeades 0:e72ea6decc70 1180 pWantedEntry->inUse = true;
RobMeades 0:e72ea6decc70 1181 pAlloc = &(pWantedEntry->datagram);
RobMeades 0:e72ea6decc70 1182 }
RobMeades 0:e72ea6decc70 1183 else
RobMeades 0:e72ea6decc70 1184 {
RobMeades 0:e72ea6decc70 1185 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "allocDatagram: failed to find end of list (x = %d).", x);
RobMeades 0:e72ea6decc70 1186 }
RobMeades 0:e72ea6decc70 1187 }
RobMeades 0:e72ea6decc70 1188 else
RobMeades 0:e72ea6decc70 1189 {
RobMeades 0:e72ea6decc70 1190 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "allocDatagram: failed to find malloc()ed entry in free list (x = %d).", x);
RobMeades 0:e72ea6decc70 1191 }
RobMeades 0:e72ea6decc70 1192
RobMeades 0:e72ea6decc70 1193 }
RobMeades 0:e72ea6decc70 1194
RobMeades 0:e72ea6decc70 1195 return pAlloc;
RobMeades 0:e72ea6decc70 1196 }
RobMeades 0:e72ea6decc70 1197
RobMeades 0:e72ea6decc70 1198 /// Allocate room for a send datagram, returning a pointer
RobMeades 0:e72ea6decc70 1199 // to it or to NULL if unsuccessful
RobMeades 0:e72ea6decc70 1200 static Datagram_t * allocSendDatagram (void)
RobMeades 0:e72ea6decc70 1201 {
RobMeades 0:e72ea6decc70 1202 return allocDatagram (&gSendDatagramListHead);
RobMeades 0:e72ea6decc70 1203 }
RobMeades 0:e72ea6decc70 1204
RobMeades 0:e72ea6decc70 1205 /// Allocate room for a receive datagram, returning a pointer
RobMeades 0:e72ea6decc70 1206 // to it or to NULL if unsuccessful
RobMeades 0:e72ea6decc70 1207 static Datagram_t * allocRecvDatagram (void)
RobMeades 0:e72ea6decc70 1208 {
RobMeades 0:e72ea6decc70 1209 return allocDatagram (&gRecvDatagramListHead);
RobMeades 0:e72ea6decc70 1210 }
RobMeades 0:e72ea6decc70 1211
RobMeades 0:e72ea6decc70 1212 /// Free a datagram from the given list
RobMeades 0:e72ea6decc70 1213 static void freeDatagram (Datagram_t *pDatagram, DatagramEntry_t * pDatagramListHead)
RobMeades 0:e72ea6decc70 1214 {
RobMeades 0:e72ea6decc70 1215 uint32_t x = 0;
RobMeades 0:e72ea6decc70 1216 DatagramEntry_t * pEntry;
RobMeades 0:e72ea6decc70 1217
RobMeades 0:e72ea6decc70 1218 if (pDatagram != NULL)
RobMeades 0:e72ea6decc70 1219 {
RobMeades 0:e72ea6decc70 1220 #ifdef DEBUG
RobMeades 0:e72ea6decc70 1221 printf ("Freeing a datagram (at 0x%lx)...\n", pDatagram);
RobMeades 0:e72ea6decc70 1222 #endif
RobMeades 0:e72ea6decc70 1223 // Find the entry in the list
RobMeades 0:e72ea6decc70 1224 pEntry = pDatagramListHead;
RobMeades 0:e72ea6decc70 1225 for (x = 0; (pEntry != NULL) && (&(pEntry->datagram) != pDatagram) && (x < MAX_NUM_DATAGRAMS); x++)
RobMeades 0:e72ea6decc70 1226 {
RobMeades 0:e72ea6decc70 1227 pEntry = pEntry->pNextEntry;
RobMeades 0:e72ea6decc70 1228 }
RobMeades 0:e72ea6decc70 1229
RobMeades 0:e72ea6decc70 1230 if ((pEntry != NULL) && (&(pEntry->datagram) == pDatagram))
RobMeades 0:e72ea6decc70 1231 {
RobMeades 0:e72ea6decc70 1232 DatagramEntry_t * pWantedEntry = pEntry;
RobMeades 0:e72ea6decc70 1233
RobMeades 0:e72ea6decc70 1234 #ifdef DEBUG
RobMeades 0:e72ea6decc70 1235 printf ("Found the datagram.\n");
RobMeades 0:e72ea6decc70 1236 #endif
RobMeades 0:e72ea6decc70 1237 // Found it, mark it as not in use and, if it is a malloc()ed
RobMeades 0:e72ea6decc70 1238 // entry, unlink it from the current list and move it to the
RobMeades 0:e72ea6decc70 1239 // free list
RobMeades 0:e72ea6decc70 1240 pWantedEntry->inUse = false;
RobMeades 0:e72ea6decc70 1241 memset (&(pWantedEntry->datagram), 0, sizeof (pWantedEntry->datagram));
RobMeades 0:e72ea6decc70 1242 if (pWantedEntry != pDatagramListHead)
RobMeades 0:e72ea6decc70 1243 {
RobMeades 0:e72ea6decc70 1244 #ifdef DEBUG
RobMeades 0:e72ea6decc70 1245 printf ("freeDatagram: moving malloc()ed entry to free list.\n");
RobMeades 0:e72ea6decc70 1246 #endif
RobMeades 0:e72ea6decc70 1247 if (pWantedEntry->pPrevEntry != NULL)
RobMeades 0:e72ea6decc70 1248 {
RobMeades 0:e72ea6decc70 1249 pWantedEntry->pPrevEntry->pNextEntry = pWantedEntry->pNextEntry;
RobMeades 0:e72ea6decc70 1250 pWantedEntry->pPrevEntry = NULL;
RobMeades 0:e72ea6decc70 1251 }
RobMeades 0:e72ea6decc70 1252 if (pWantedEntry->pNextEntry != NULL)
RobMeades 0:e72ea6decc70 1253 {
RobMeades 0:e72ea6decc70 1254 pWantedEntry->pNextEntry->pPrevEntry = pWantedEntry->pPrevEntry;
RobMeades 0:e72ea6decc70 1255 pWantedEntry->pNextEntry = NULL;
RobMeades 0:e72ea6decc70 1256 }
RobMeades 0:e72ea6decc70 1257
RobMeades 0:e72ea6decc70 1258 // Find the end of the free list
RobMeades 0:e72ea6decc70 1259 pEntry = &gFreeDatagramListHeadUnused;
RobMeades 0:e72ea6decc70 1260 for (x = 0; (pEntry->pNextEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
RobMeades 0:e72ea6decc70 1261 {
RobMeades 0:e72ea6decc70 1262 pEntry = pEntry->pNextEntry;
RobMeades 0:e72ea6decc70 1263 }
RobMeades 0:e72ea6decc70 1264
RobMeades 0:e72ea6decc70 1265 // Link it there
RobMeades 0:e72ea6decc70 1266 if (pEntry->pNextEntry == NULL)
RobMeades 0:e72ea6decc70 1267 {
RobMeades 0:e72ea6decc70 1268 pEntry->pNextEntry = pWantedEntry;
RobMeades 0:e72ea6decc70 1269 pWantedEntry->pPrevEntry = pEntry;
RobMeades 0:e72ea6decc70 1270 }
RobMeades 0:e72ea6decc70 1271 else
RobMeades 0:e72ea6decc70 1272 {
RobMeades 0:e72ea6decc70 1273 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "freeDatagram: failed to find end of free list (x = %d).", x);
RobMeades 0:e72ea6decc70 1274 }
RobMeades 0:e72ea6decc70 1275 }
RobMeades 0:e72ea6decc70 1276 #ifdef DEBUG
RobMeades 0:e72ea6decc70 1277 else
RobMeades 0:e72ea6decc70 1278 {
RobMeades 0:e72ea6decc70 1279 printf ("freeDatagram: just marking head entry as unused.\n");
RobMeades 0:e72ea6decc70 1280 }
RobMeades 0:e72ea6decc70 1281 #endif
RobMeades 0:e72ea6decc70 1282 }
RobMeades 0:e72ea6decc70 1283 else
RobMeades 0:e72ea6decc70 1284 {
RobMeades 0:e72ea6decc70 1285 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM,
RobMeades 0:e72ea6decc70 1286 "freeDatagram: couldn't find entry in list (pDatagram = 0x%lx, gDatagramListHead = 0x%lx, x = %d).",
RobMeades 0:e72ea6decc70 1287 pDatagram, pDatagramListHead, x);
RobMeades 0:e72ea6decc70 1288 }
RobMeades 0:e72ea6decc70 1289 }
RobMeades 0:e72ea6decc70 1290 else
RobMeades 0:e72ea6decc70 1291 {
RobMeades 0:e72ea6decc70 1292 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "freeDatagram: NULL pointer passed in.");
RobMeades 0:e72ea6decc70 1293 }
RobMeades 0:e72ea6decc70 1294 }
RobMeades 0:e72ea6decc70 1295
RobMeades 0:e72ea6decc70 1296 /// Free a specific datagram from the receive list
RobMeades 0:e72ea6decc70 1297 static void freeRecvDatagram (Datagram_t *pDatagram)
RobMeades 0:e72ea6decc70 1298 {
RobMeades 0:e72ea6decc70 1299 freeDatagram (pDatagram, &gRecvDatagramListHead);
RobMeades 0:e72ea6decc70 1300 }
RobMeades 0:e72ea6decc70 1301
RobMeades 0:e72ea6decc70 1302 // Empty a datagram list (either send or receive)
RobMeades 0:e72ea6decc70 1303 static void freeAllDatagrams (DatagramEntry_t *pDatagramListHead)
RobMeades 0:e72ea6decc70 1304 {
RobMeades 0:e72ea6decc70 1305 uint32_t x;
RobMeades 0:e72ea6decc70 1306 DatagramEntry_t * pEntry = NULL;
RobMeades 0:e72ea6decc70 1307
RobMeades 0:e72ea6decc70 1308 pEntry = pDatagramListHead;
RobMeades 0:e72ea6decc70 1309 for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
RobMeades 0:e72ea6decc70 1310 {
RobMeades 0:e72ea6decc70 1311 pEntry->inUse = false;
RobMeades 0:e72ea6decc70 1312 pEntry = pEntry->pNextEntry;
RobMeades 0:e72ea6decc70 1313 }
RobMeades 0:e72ea6decc70 1314
RobMeades 0:e72ea6decc70 1315 freeUnusedDatagrams(pDatagramListHead);
RobMeades 0:e72ea6decc70 1316 }
RobMeades 0:e72ea6decc70 1317
RobMeades 0:e72ea6decc70 1318 /// Free unused datagrams from the send or receive lists
RobMeades 0:e72ea6decc70 1319 static void freeUnusedDatagrams (DatagramEntry_t *pDatagramListHead)
RobMeades 0:e72ea6decc70 1320 {
RobMeades 0:e72ea6decc70 1321 uint32_t x = 0;
RobMeades 0:e72ea6decc70 1322 DatagramEntry_t * pEntry = NULL;
RobMeades 0:e72ea6decc70 1323
RobMeades 0:e72ea6decc70 1324 if ((pDatagramListHead != NULL) && (pDatagramListHead != &gFreeDatagramListHeadUnused))
RobMeades 0:e72ea6decc70 1325 {
RobMeades 0:e72ea6decc70 1326 // Go to the end of the list
RobMeades 0:e72ea6decc70 1327 pEntry = pDatagramListHead;
RobMeades 0:e72ea6decc70 1328 for (x = 0; (pEntry->pNextEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
RobMeades 0:e72ea6decc70 1329 {
RobMeades 0:e72ea6decc70 1330 pEntry = pEntry->pNextEntry;
RobMeades 0:e72ea6decc70 1331 }
RobMeades 0:e72ea6decc70 1332
RobMeades 0:e72ea6decc70 1333 if ((pEntry != NULL) && (pEntry->pNextEntry == NULL))
RobMeades 0:e72ea6decc70 1334 {
RobMeades 0:e72ea6decc70 1335 // Now work backwards up the list freeing unused things until we get
RobMeades 0:e72ea6decc70 1336 // to the head
RobMeades 0:e72ea6decc70 1337 for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
RobMeades 0:e72ea6decc70 1338 {
RobMeades 0:e72ea6decc70 1339 DatagramEntry_t * pNextOne = pEntry->pPrevEntry;
RobMeades 0:e72ea6decc70 1340 // Check that this entry is unused and not the first static entry then,
RobMeades 0:e72ea6decc70 1341 // if it is, free it
RobMeades 0:e72ea6decc70 1342 if ((!(pEntry->inUse)) && (pEntry != pDatagramListHead))
RobMeades 0:e72ea6decc70 1343 {
RobMeades 0:e72ea6decc70 1344 freeDatagram (&(pEntry->datagram), pDatagramListHead);
RobMeades 0:e72ea6decc70 1345 #ifdef DEBUG
RobMeades 0:e72ea6decc70 1346 printf ("freeUnusedDatagrams: freeing an entry.\n");
RobMeades 0:e72ea6decc70 1347 #endif
RobMeades 0:e72ea6decc70 1348 }
RobMeades 0:e72ea6decc70 1349 pEntry = pNextOne;
RobMeades 0:e72ea6decc70 1350 }
RobMeades 0:e72ea6decc70 1351 }
RobMeades 0:e72ea6decc70 1352 else
RobMeades 0:e72ea6decc70 1353 {
RobMeades 0:e72ea6decc70 1354 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "freeUnusedDatagrams : failed to find end of list (x = %d).", x);
RobMeades 0:e72ea6decc70 1355 }
RobMeades 0:e72ea6decc70 1356 }
RobMeades 0:e72ea6decc70 1357 else
RobMeades 0:e72ea6decc70 1358 {
RobMeades 0:e72ea6decc70 1359 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "freeUnusedDatagrams: NULL or free list head pointer passed in (== 0x%lx).", pDatagramListHead);
RobMeades 0:e72ea6decc70 1360 }
RobMeades 0:e72ea6decc70 1361 }
RobMeades 0:e72ea6decc70 1362
RobMeades 0:e72ea6decc70 1363 /// Free unused datagrams from the send list
RobMeades 0:e72ea6decc70 1364 static void freeUnusedSendDatagrams (void)
RobMeades 0:e72ea6decc70 1365 {
RobMeades 0:e72ea6decc70 1366 freeUnusedDatagrams (&gSendDatagramListHead);
RobMeades 0:e72ea6decc70 1367 }
RobMeades 0:e72ea6decc70 1368
RobMeades 0:e72ea6decc70 1369 /// Free unused datagrams from the receive list
RobMeades 0:e72ea6decc70 1370 static void freeUnusedRecvDatagrams (void)
RobMeades 0:e72ea6decc70 1371 {
RobMeades 0:e72ea6decc70 1372 freeUnusedDatagrams (&gRecvDatagramListHead);
RobMeades 0:e72ea6decc70 1373 }
RobMeades 0:e72ea6decc70 1374
RobMeades 0:e72ea6decc70 1375 /// Wait for the device to register on the network
RobMeades 0:e72ea6decc70 1376 static bool waitReg (uint32_t durationSeconds)
RobMeades 0:e72ea6decc70 1377 {
RobMeades 0:e72ea6decc70 1378 uint32_t count = 0;
RobMeades 0:e72ea6decc70 1379 bool success = false;
RobMeades 0:e72ea6decc70 1380
RobMeades 0:e72ea6decc70 1381 while (!success && (count < durationSeconds))
RobMeades 0:e72ea6decc70 1382 {
RobMeades 0:e72ea6decc70 1383 success = pgNeul->checkNetStatus (NULL);
RobMeades 0:e72ea6decc70 1384 wait_ms (1000);
RobMeades 0:e72ea6decc70 1385 count++;
RobMeades 0:e72ea6decc70 1386 }
RobMeades 0:e72ea6decc70 1387
RobMeades 0:e72ea6decc70 1388 return success;
RobMeades 0:e72ea6decc70 1389 }
RobMeades 0:e72ea6decc70 1390
RobMeades 0:e72ea6decc70 1391 /// Do Sending (working through the inUse datagrams in the Send queue) and
RobMeades 0:e72ea6decc70 1392 // then a Receive of a single datagram (putting it in the Receive queue).
RobMeades 0:e72ea6decc70 1393 // \return true if the send was successful, otherwise false.
RobMeades 0:e72ea6decc70 1394 static bool sendAndReceive (void)
RobMeades 0:e72ea6decc70 1395 {
RobMeades 0:e72ea6decc70 1396 bool success = true; // Set to true as otherwise will fail if there's nothing to send
RobMeades 0:e72ea6decc70 1397 uint32_t x;
RobMeades 0:e72ea6decc70 1398 DatagramEntry_t * pEntry;
RobMeades 0:e72ea6decc70 1399 Datagram_t *pRecvDatagram;
RobMeades 0:e72ea6decc70 1400 bool somethingInRxQueue = false;
RobMeades 0:e72ea6decc70 1401
RobMeades 0:e72ea6decc70 1402 #ifdef DEBUG
RobMeades 0:e72ea6decc70 1403 printf ("\nSending datagram(s)...\n");
RobMeades 0:e72ea6decc70 1404 #endif
RobMeades 0:e72ea6decc70 1405 // Do the sending first
RobMeades 0:e72ea6decc70 1406 pEntry = &gSendDatagramListHead;
RobMeades 0:e72ea6decc70 1407 for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS) && success; x++)
RobMeades 0:e72ea6decc70 1408 {
RobMeades 0:e72ea6decc70 1409 if (pEntry->inUse)
RobMeades 0:e72ea6decc70 1410 {
RobMeades 0:e72ea6decc70 1411 success = false;
RobMeades 0:e72ea6decc70 1412 printf ("\nSending datagram %ld...\n", x);
RobMeades 0:e72ea6decc70 1413 // Send the datagram.
RobMeades 0:e72ea6decc70 1414 if (pgNeul != NULL)
RobMeades 0:e72ea6decc70 1415 {
RobMeades 0:e72ea6decc70 1416 success = pgNeul->datagramSend (pEntry->datagram.size, pEntry->datagram.pBody);
RobMeades 0:e72ea6decc70 1417 }
RobMeades 0:e72ea6decc70 1418
RobMeades 0:e72ea6decc70 1419 if (success)
RobMeades 0:e72ea6decc70 1420 {
RobMeades 0:e72ea6decc70 1421 doSendFlash();
RobMeades 0:e72ea6decc70 1422 printf ("Sent.\n");
RobMeades 0:e72ea6decc70 1423 }
RobMeades 0:e72ea6decc70 1424 else
RobMeades 0:e72ea6decc70 1425 {
RobMeades 0:e72ea6decc70 1426 assertAlways (DEBUG_SOS_NETWORK_SEND_PROBLEM, "Couldn't send datagram.");
RobMeades 0:e72ea6decc70 1427 }
RobMeades 0:e72ea6decc70 1428
RobMeades 0:e72ea6decc70 1429 // Lose it always, don't want to clog up
RobMeades 0:e72ea6decc70 1430 pEntry->inUse = false;
RobMeades 0:e72ea6decc70 1431 }
RobMeades 0:e72ea6decc70 1432 pEntry = pEntry->pNextEntry; // Move to the next entry
RobMeades 0:e72ea6decc70 1433 }
RobMeades 0:e72ea6decc70 1434
RobMeades 0:e72ea6decc70 1435 freeUnusedSendDatagrams();
RobMeades 0:e72ea6decc70 1436
RobMeades 0:e72ea6decc70 1437 // Now the receiving
RobMeades 0:e72ea6decc70 1438 do
RobMeades 0:e72ea6decc70 1439 {
RobMeades 0:e72ea6decc70 1440 somethingInRxQueue = false;
RobMeades 0:e72ea6decc70 1441 pRecvDatagram = allocRecvDatagram ();
RobMeades 0:e72ea6decc70 1442 if (pRecvDatagram != NULL)
RobMeades 0:e72ea6decc70 1443 {
RobMeades 0:e72ea6decc70 1444 #ifdef DEBUG
RobMeades 0:e72ea6decc70 1445 printf ("Checking for downlink...\n");
RobMeades 0:e72ea6decc70 1446 #endif
RobMeades 0:e72ea6decc70 1447 pRecvDatagram->size = sizeof (pRecvDatagram->pBody);
RobMeades 0:e72ea6decc70 1448 // Don't check the return value here (as we don't want to fail
RobMeades 0:e72ea6decc70 1449 // if nothing has been received) check the size returned instead
RobMeades 0:e72ea6decc70 1450 if (pgNeul != NULL)
RobMeades 0:e72ea6decc70 1451 {
RobMeades 0:e72ea6decc70 1452 somethingInRxQueue = pgNeul->datagramRecv ((int *) &(pRecvDatagram->size), pRecvDatagram->pBody, RECEIVE_DURATION_MS);
RobMeades 0:e72ea6decc70 1453 }
RobMeades 0:e72ea6decc70 1454 // If something was received say so, otherwise free the buffer
RobMeades 0:e72ea6decc70 1455 if (somethingInRxQueue && (pRecvDatagram->size > 0))
RobMeades 0:e72ea6decc70 1456 {
RobMeades 0:e72ea6decc70 1457 doRecvFlash ();
RobMeades 0:e72ea6decc70 1458 printf ("A datagram was received.\n");
RobMeades 0:e72ea6decc70 1459 }
RobMeades 0:e72ea6decc70 1460 else
RobMeades 0:e72ea6decc70 1461 {
RobMeades 0:e72ea6decc70 1462 freeRecvDatagram (pRecvDatagram);
RobMeades 0:e72ea6decc70 1463 }
RobMeades 0:e72ea6decc70 1464 }
RobMeades 0:e72ea6decc70 1465 else
RobMeades 0:e72ea6decc70 1466 {
RobMeades 0:e72ea6decc70 1467 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate a datagram for receive.");
RobMeades 0:e72ea6decc70 1468 }
RobMeades 0:e72ea6decc70 1469 }
RobMeades 0:e72ea6decc70 1470 while (somethingInRxQueue);
RobMeades 0:e72ea6decc70 1471
RobMeades 0:e72ea6decc70 1472 return success;
RobMeades 0:e72ea6decc70 1473 }
RobMeades 0:e72ea6decc70 1474
RobMeades 0:e72ea6decc70 1475 /// Prepare an InitInd, plus a SerialNumberInd.
RobMeades 0:e72ea6decc70 1476 // \param indNotCnf if true encode an initInt, else encode an initCnf
RobMeades 0:e72ea6decc70 1477 // \return true if the preparation was successful, otherwise false.
RobMeades 0:e72ea6decc70 1478 static bool queueInitialDatagram (void)
RobMeades 0:e72ea6decc70 1479 {
RobMeades 0:e72ea6decc70 1480 bool success = false;
RobMeades 0:e72ea6decc70 1481 InitIndUlMsg_t initIndUlMsg;
RobMeades 0:e72ea6decc70 1482 SerialNumberIndUlMsg_t serialNumberIndUlMsg;
RobMeades 0:e72ea6decc70 1483 Datagram_t * pDatagram;
RobMeades 0:e72ea6decc70 1484 uint32_t bytesEncoded = 0;
RobMeades 0:e72ea6decc70 1485
RobMeades 0:e72ea6decc70 1486 printf ("\nPreparing initial datagram...\n");
RobMeades 0:e72ea6decc70 1487
RobMeades 0:e72ea6decc70 1488 pDatagram = allocSendDatagram();
RobMeades 0:e72ea6decc70 1489 if (pDatagram != NULL)
RobMeades 0:e72ea6decc70 1490 {
RobMeades 0:e72ea6decc70 1491 printf ("Reading serial number from water meter...\n");
RobMeades 0:e72ea6decc70 1492 // Read the serial number from the water meter
RobMeades 0:e72ea6decc70 1493 gWaterMeter.readSerialNumber (&(serialNumberIndUlMsg.serialNumber));
RobMeades 0:e72ea6decc70 1494 // Ignore the return value and just set success == true so that the code
RobMeades 0:e72ea6decc70 1495 // can run without a water meter attached.
RobMeades 0:e72ea6decc70 1496 success = true;
RobMeades 0:e72ea6decc70 1497 if (success)
RobMeades 0:e72ea6decc70 1498 {
RobMeades 0:e72ea6decc70 1499 printf ("Serial number is %ld.\n", serialNumberIndUlMsg.serialNumber);
RobMeades 0:e72ea6decc70 1500
RobMeades 0:e72ea6decc70 1501 // Encode the InitInd and SerialNumberInd messages into a datagram
RobMeades 0:e72ea6decc70 1502 printf ("Encoding datagram...\n");
RobMeades 0:e72ea6decc70 1503
RobMeades 0:e72ea6decc70 1504 // Set up the InitInd contents
RobMeades 0:e72ea6decc70 1505 initIndUlMsg.wakeUpCode = readNvContext()->wakeUpCode;
RobMeades 0:e72ea6decc70 1506 printf ("Wake-up code is 0x%x.\n", initIndUlMsg.wakeUpCode);
RobMeades 0:e72ea6decc70 1507
RobMeades 0:e72ea6decc70 1508 setWakeUpCode (WAKE_UP_CODE_OK);
RobMeades 0:e72ea6decc70 1509 bytesEncoded += gMessageCodec.encodeInitIndUlMsg (&(pDatagram->pBody[bytesEncoded]), &initIndUlMsg);
RobMeades 0:e72ea6decc70 1510 bytesEncoded += gMessageCodec.encodeSerialNumberIndUlMsg (&(pDatagram->pBody[bytesEncoded]), &serialNumberIndUlMsg);
RobMeades 0:e72ea6decc70 1511 pDatagram->size = bytesEncoded;
RobMeades 0:e72ea6decc70 1512 }
RobMeades 0:e72ea6decc70 1513 else
RobMeades 0:e72ea6decc70 1514 {
RobMeades 0:e72ea6decc70 1515 assertAlways (DEBUG_SOS_WATER_METER_PROBLEM, "Failed to read serial number from water meter.");
RobMeades 0:e72ea6decc70 1516 }
RobMeades 0:e72ea6decc70 1517 }
RobMeades 0:e72ea6decc70 1518 else
RobMeades 0:e72ea6decc70 1519 {
RobMeades 0:e72ea6decc70 1520 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate send datagram.");
RobMeades 0:e72ea6decc70 1521 }
RobMeades 0:e72ea6decc70 1522
RobMeades 0:e72ea6decc70 1523 return success;
RobMeades 0:e72ea6decc70 1524 }
RobMeades 0:e72ea6decc70 1525
RobMeades 0:e72ea6decc70 1526 /// Prepare the periodic datagram.
RobMeades 0:e72ea6decc70 1527 // \return true if the preparation was successful, otherwise false.
RobMeades 0:e72ea6decc70 1528 static bool queuePeriodicDatagram (void)
RobMeades 0:e72ea6decc70 1529 {
RobMeades 0:e72ea6decc70 1530 bool success = false;
RobMeades 0:e72ea6decc70 1531 VolumeIndUlMsg_t volumeIndMsg;
RobMeades 0:e72ea6decc70 1532 RssiIndUlMsg_t rssiIndMsg;
RobMeades 0:e72ea6decc70 1533 uint32_t bytesEncoded = 0;
RobMeades 0:e72ea6decc70 1534 Datagram_t * pDatagram;
RobMeades 0:e72ea6decc70 1535
RobMeades 0:e72ea6decc70 1536 printf ("\nPreparing periodic datagram...\n");
RobMeades 0:e72ea6decc70 1537
RobMeades 0:e72ea6decc70 1538 pDatagram = allocSendDatagram();
RobMeades 0:e72ea6decc70 1539 if (pDatagram != NULL)
RobMeades 0:e72ea6decc70 1540 {
RobMeades 0:e72ea6decc70 1541 // Read the volume in litres
RobMeades 0:e72ea6decc70 1542 printf ("Reading volume from water meter...\n");
RobMeades 0:e72ea6decc70 1543 gWaterMeter.readLitres (&(volumeIndMsg.volumeLitres));
RobMeades 0:e72ea6decc70 1544 printf ("Volume is %ld litres.\n", volumeIndMsg.volumeLitres);
RobMeades 0:e72ea6decc70 1545
RobMeades 0:e72ea6decc70 1546 // Ignore the return value and just set success == true so that the code
RobMeades 0:e72ea6decc70 1547 // can run without a water meter attached.
RobMeades 0:e72ea6decc70 1548 success = true;
RobMeades 0:e72ea6decc70 1549
RobMeades 0:e72ea6decc70 1550 if (success)
RobMeades 0:e72ea6decc70 1551 {
RobMeades 0:e72ea6decc70 1552 // Read the RSSI
RobMeades 0:e72ea6decc70 1553 printf ("Reading RSSI from module...\n");
RobMeades 0:e72ea6decc70 1554 if (pgNeul != NULL)
RobMeades 0:e72ea6decc70 1555 {
RobMeades 0:e72ea6decc70 1556 success = pgNeul->getRssi ((int *) &(rssiIndMsg.rssi));
RobMeades 0:e72ea6decc70 1557 printf ("RSSI is %ld.\n", rssiIndMsg.rssi);
RobMeades 0:e72ea6decc70 1558 }
RobMeades 0:e72ea6decc70 1559 if (success)
RobMeades 0:e72ea6decc70 1560 {
RobMeades 0:e72ea6decc70 1561 printf ("Encoding datagram...\n");
RobMeades 0:e72ea6decc70 1562 // Encode the VolumeInd and RssiInd messages into a datagram
RobMeades 0:e72ea6decc70 1563 bytesEncoded += gMessageCodec.encodeVolumeIndUlMsg (&(pDatagram->pBody[bytesEncoded]), &volumeIndMsg);
RobMeades 0:e72ea6decc70 1564 bytesEncoded += gMessageCodec.encodeRssiIndUlMsg (&(pDatagram->pBody[bytesEncoded]), &rssiIndMsg);
RobMeades 0:e72ea6decc70 1565 pDatagram->size = bytesEncoded;
RobMeades 0:e72ea6decc70 1566 }
RobMeades 0:e72ea6decc70 1567 else
RobMeades 0:e72ea6decc70 1568 {
RobMeades 0:e72ea6decc70 1569 assertAlways (DEBUG_SOS_AT_COMMAND_PROBLEM, "Failed to read RSSI from module.");
RobMeades 0:e72ea6decc70 1570 }
RobMeades 0:e72ea6decc70 1571 }
RobMeades 0:e72ea6decc70 1572 else
RobMeades 0:e72ea6decc70 1573 {
RobMeades 0:e72ea6decc70 1574 assertAlways (DEBUG_SOS_WATER_METER_PROBLEM, "Failed to read volume from water meter.");
RobMeades 0:e72ea6decc70 1575 }
RobMeades 0:e72ea6decc70 1576 }
RobMeades 0:e72ea6decc70 1577 else
RobMeades 0:e72ea6decc70 1578 {
RobMeades 0:e72ea6decc70 1579 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate send datagram.");
RobMeades 0:e72ea6decc70 1580 }
RobMeades 0:e72ea6decc70 1581
RobMeades 0:e72ea6decc70 1582 return success;
RobMeades 0:e72ea6decc70 1583 }
RobMeades 0:e72ea6decc70 1584
RobMeades 0:e72ea6decc70 1585 /// Handle a SerialNumberGetReq message
RobMeades 0:e72ea6decc70 1586 static bool handleSerialNumberGetReqDlMsg (void)
RobMeades 0:e72ea6decc70 1587 {
RobMeades 0:e72ea6decc70 1588 bool success = false;
RobMeades 0:e72ea6decc70 1589 SerialNumberGetCnfUlMsg_t serialNumberGetCnfUlMsg;
RobMeades 0:e72ea6decc70 1590 uint32_t bytesEncoded = 0;
RobMeades 0:e72ea6decc70 1591 Datagram_t * pDatagram;
RobMeades 0:e72ea6decc70 1592
RobMeades 0:e72ea6decc70 1593 printf ("\nHandling SerialNumberGetReqDlMsg.\n");
RobMeades 0:e72ea6decc70 1594 printf ("Reading serial number from water meter...\n");
RobMeades 0:e72ea6decc70 1595 // Read the serial number from the water meter
RobMeades 0:e72ea6decc70 1596 gWaterMeter.readSerialNumber (&(serialNumberGetCnfUlMsg.serialNumber));
RobMeades 0:e72ea6decc70 1597
RobMeades 0:e72ea6decc70 1598 // Ignore the return value and just set success == true so that the code
RobMeades 0:e72ea6decc70 1599 // can run without a water meter attached.
RobMeades 0:e72ea6decc70 1600 success = true;
RobMeades 0:e72ea6decc70 1601
RobMeades 0:e72ea6decc70 1602 if (success)
RobMeades 0:e72ea6decc70 1603 {
RobMeades 0:e72ea6decc70 1604 printf ("Serial number is %ld.\n", serialNumberGetCnfUlMsg.serialNumber);
RobMeades 0:e72ea6decc70 1605 printf ("Preparing SerialNumberGetCnfUlMsg response in a datagram...\n");
RobMeades 0:e72ea6decc70 1606 pDatagram = allocSendDatagram();
RobMeades 0:e72ea6decc70 1607 if (pDatagram != NULL)
RobMeades 0:e72ea6decc70 1608 {
RobMeades 0:e72ea6decc70 1609 // Encode the serialNumberGetCnfUlMsg into a datagram
RobMeades 0:e72ea6decc70 1610 printf ("Encoding datagram...\n");
RobMeades 0:e72ea6decc70 1611
RobMeades 0:e72ea6decc70 1612 bytesEncoded += gMessageCodec.encodeSerialNumberGetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &serialNumberGetCnfUlMsg);
RobMeades 0:e72ea6decc70 1613
RobMeades 0:e72ea6decc70 1614 pDatagram->size = bytesEncoded;
RobMeades 0:e72ea6decc70 1615 success = true;
RobMeades 0:e72ea6decc70 1616 }
RobMeades 0:e72ea6decc70 1617 else
RobMeades 0:e72ea6decc70 1618 {
RobMeades 0:e72ea6decc70 1619 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate send datagram.");
RobMeades 0:e72ea6decc70 1620 }
RobMeades 0:e72ea6decc70 1621 }
RobMeades 0:e72ea6decc70 1622 else
RobMeades 0:e72ea6decc70 1623 {
RobMeades 0:e72ea6decc70 1624 assertAlways (DEBUG_SOS_WATER_METER_PROBLEM, "Failed to read volume from water meter.");
RobMeades 0:e72ea6decc70 1625 }
RobMeades 0:e72ea6decc70 1626
RobMeades 0:e72ea6decc70 1627 return success;
RobMeades 0:e72ea6decc70 1628 }
RobMeades 0:e72ea6decc70 1629
RobMeades 0:e72ea6decc70 1630 /// Handle a RebootReq message
RobMeades 0:e72ea6decc70 1631 static bool handleRebootReqDlMsg (bool devModeOnNotOff)
RobMeades 0:e72ea6decc70 1632 {
RobMeades 0:e72ea6decc70 1633 bool success = true;
RobMeades 0:e72ea6decc70 1634 printf ("\nHandling RebootReqDlMsg, devMode is 0x%d.\n", devModeOnNotOff);
RobMeades 0:e72ea6decc70 1635
RobMeades 0:e72ea6decc70 1636 setDevMode (devModeOnNotOff);
RobMeades 0:e72ea6decc70 1637
RobMeades 0:e72ea6decc70 1638 wait_ms (1000);
RobMeades 0:e72ea6decc70 1639
RobMeades 0:e72ea6decc70 1640 printf ("Resetting system...\n");
RobMeades 0:e72ea6decc70 1641 wait_ms (2000);
RobMeades 0:e72ea6decc70 1642 NVIC_SystemReset();
RobMeades 0:e72ea6decc70 1643
RobMeades 0:e72ea6decc70 1644 return success;
RobMeades 0:e72ea6decc70 1645 }
RobMeades 0:e72ea6decc70 1646
RobMeades 0:e72ea6decc70 1647 /// Enqueue a ReadingIntervalSetCnf or a ReadingIntervalGetCnf message
RobMeades 0:e72ea6decc70 1648 static bool enqueueReadingIntervalSetGetCnfUlMsg (bool setNotGet)
RobMeades 0:e72ea6decc70 1649 {
RobMeades 0:e72ea6decc70 1650 bool success = false;
RobMeades 0:e72ea6decc70 1651 uint32_t bytesEncoded = 0;
RobMeades 0:e72ea6decc70 1652 Datagram_t * pDatagram;
RobMeades 0:e72ea6decc70 1653
RobMeades 0:e72ea6decc70 1654 printf ("Preparing ReadingIntervalxxxCnfUlMsg response...\n");
RobMeades 0:e72ea6decc70 1655 pDatagram = allocSendDatagram();
RobMeades 0:e72ea6decc70 1656 if (pDatagram != NULL)
RobMeades 0:e72ea6decc70 1657 {
RobMeades 0:e72ea6decc70 1658 // Encode the ledxxxCnfUlMsg into a datagram
RobMeades 0:e72ea6decc70 1659 printf ("Encoding datagram...\n");
RobMeades 0:e72ea6decc70 1660 if (setNotGet)
RobMeades 0:e72ea6decc70 1661 {
RobMeades 0:e72ea6decc70 1662 ReadingIntervalSetCnfUlMsg_t readingIntervalSetCnfUlMsg;
RobMeades 0:e72ea6decc70 1663
RobMeades 0:e72ea6decc70 1664 readingIntervalSetCnfUlMsg.readingIntervalSeconds = readNvContext()->readingIntervalSeconds;
RobMeades 0:e72ea6decc70 1665 bytesEncoded += gMessageCodec.encodeReadingIntervalSetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &readingIntervalSetCnfUlMsg);
RobMeades 0:e72ea6decc70 1666 }
RobMeades 0:e72ea6decc70 1667 else
RobMeades 0:e72ea6decc70 1668 {
RobMeades 0:e72ea6decc70 1669 ReadingIntervalGetCnfUlMsg_t readingIntervalGetCnfUlMsg;
RobMeades 0:e72ea6decc70 1670
RobMeades 0:e72ea6decc70 1671 readingIntervalGetCnfUlMsg.readingIntervalSeconds = readNvContext()->readingIntervalSeconds;
RobMeades 0:e72ea6decc70 1672 bytesEncoded += gMessageCodec.encodeReadingIntervalGetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &readingIntervalGetCnfUlMsg);
RobMeades 0:e72ea6decc70 1673 }
RobMeades 0:e72ea6decc70 1674
RobMeades 0:e72ea6decc70 1675 pDatagram->size = bytesEncoded;
RobMeades 0:e72ea6decc70 1676 success = true;
RobMeades 0:e72ea6decc70 1677 }
RobMeades 0:e72ea6decc70 1678 else
RobMeades 0:e72ea6decc70 1679 {
RobMeades 0:e72ea6decc70 1680 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate send datagram.");
RobMeades 0:e72ea6decc70 1681 }
RobMeades 0:e72ea6decc70 1682
RobMeades 0:e72ea6decc70 1683 return success;
RobMeades 0:e72ea6decc70 1684 }
RobMeades 0:e72ea6decc70 1685
RobMeades 0:e72ea6decc70 1686 /// Handle a ReadingIntervalSetReq message
RobMeades 0:e72ea6decc70 1687 static bool handleReadingIntervalSetReqDlMsg (uint32_t readingIntervalSeconds)
RobMeades 0:e72ea6decc70 1688 {
RobMeades 0:e72ea6decc70 1689 printf ("\nHandling ReadingIntervalSetReqDlMsg, set to %ld.\n", readingIntervalSeconds);
RobMeades 0:e72ea6decc70 1690 setReadingIntervalSeconds (readingIntervalSeconds);
RobMeades 0:e72ea6decc70 1691
RobMeades 0:e72ea6decc70 1692 return enqueueReadingIntervalSetGetCnfUlMsg (true);
RobMeades 0:e72ea6decc70 1693 }
RobMeades 0:e72ea6decc70 1694
RobMeades 0:e72ea6decc70 1695 /// Handle a ReadingIntervalGetReq message
RobMeades 0:e72ea6decc70 1696 static bool handleReadingIntervalGetReqDlMsg (void)
RobMeades 0:e72ea6decc70 1697 {
RobMeades 0:e72ea6decc70 1698 printf ("\nHandling ReadingIntervalGetReqDlMsg.\n");
RobMeades 0:e72ea6decc70 1699
RobMeades 0:e72ea6decc70 1700 return enqueueReadingIntervalSetGetCnfUlMsg (false);
RobMeades 0:e72ea6decc70 1701 }
RobMeades 0:e72ea6decc70 1702
RobMeades 0:e72ea6decc70 1703 /// Enqueue a GpioSetCnf or a GpioGetCnf message
RobMeades 0:e72ea6decc70 1704 static bool enqueueGpioSetGetCnfUlMsg (bool setNotGet, GpioState_t * gpioState)
RobMeades 0:e72ea6decc70 1705 {
RobMeades 0:e72ea6decc70 1706 bool success = false;
RobMeades 0:e72ea6decc70 1707 uint32_t bytesEncoded = 0;
RobMeades 0:e72ea6decc70 1708 Datagram_t * pDatagram;
RobMeades 0:e72ea6decc70 1709
RobMeades 0:e72ea6decc70 1710 printf ("Preparing GpioxxxCnfUlMsg response in a datagram...\n");
RobMeades 0:e72ea6decc70 1711 pDatagram = allocSendDatagram();
RobMeades 0:e72ea6decc70 1712 if (pDatagram != NULL)
RobMeades 0:e72ea6decc70 1713 {
RobMeades 0:e72ea6decc70 1714 // Encode the gpioxxxCnfUlMsg into a datagram
RobMeades 0:e72ea6decc70 1715 printf ("Encoding datagram...\n");
RobMeades 0:e72ea6decc70 1716 if (setNotGet)
RobMeades 0:e72ea6decc70 1717 {
RobMeades 0:e72ea6decc70 1718 GpioSetCnfUlMsg_t gpioSetCnfUlMsg;
RobMeades 0:e72ea6decc70 1719
RobMeades 0:e72ea6decc70 1720 gpioSetCnfUlMsg.gpioState = *gpioState;
RobMeades 0:e72ea6decc70 1721 bytesEncoded += gMessageCodec.encodeGpioSetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &gpioSetCnfUlMsg);
RobMeades 0:e72ea6decc70 1722 }
RobMeades 0:e72ea6decc70 1723 else
RobMeades 0:e72ea6decc70 1724 {
RobMeades 0:e72ea6decc70 1725 GpioGetCnfUlMsg_t gpioGetCnfUlMsg;
RobMeades 0:e72ea6decc70 1726
RobMeades 0:e72ea6decc70 1727 gpioGetCnfUlMsg.gpioState = *gpioState;
RobMeades 0:e72ea6decc70 1728 bytesEncoded += gMessageCodec.encodeGpioGetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &gpioGetCnfUlMsg);
RobMeades 0:e72ea6decc70 1729 }
RobMeades 0:e72ea6decc70 1730
RobMeades 0:e72ea6decc70 1731 pDatagram->size = bytesEncoded;
RobMeades 0:e72ea6decc70 1732 success = true;
RobMeades 0:e72ea6decc70 1733 }
RobMeades 0:e72ea6decc70 1734 else
RobMeades 0:e72ea6decc70 1735 {
RobMeades 0:e72ea6decc70 1736 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate send datagram.");
RobMeades 0:e72ea6decc70 1737 }
RobMeades 0:e72ea6decc70 1738
RobMeades 0:e72ea6decc70 1739 return success;
RobMeades 0:e72ea6decc70 1740 }
RobMeades 0:e72ea6decc70 1741
RobMeades 0:e72ea6decc70 1742 /// Handle a GpioSetReq message
RobMeades 0:e72ea6decc70 1743 static bool handleGpioSetReqDlMsg (GpioState_t * pGpioState)
RobMeades 0:e72ea6decc70 1744 {
RobMeades 0:e72ea6decc70 1745 bool success = false;
RobMeades 0:e72ea6decc70 1746
RobMeades 0:e72ea6decc70 1747 printf ("\nHandling GpioSetReqDlMsg, gpio %d, inputNotOutput 0x%x, onNotOff 0x%x.\n",
RobMeades 0:e72ea6decc70 1748 pGpioState->gpio,
RobMeades 0:e72ea6decc70 1749 pGpioState->inputNotOutput,
RobMeades 0:e72ea6decc70 1750 pGpioState->onNotOff);
RobMeades 0:e72ea6decc70 1751
RobMeades 0:e72ea6decc70 1752 success = setGpio (pGpioState);
RobMeades 0:e72ea6decc70 1753
RobMeades 0:e72ea6decc70 1754 if (success)
RobMeades 0:e72ea6decc70 1755 {
RobMeades 0:e72ea6decc70 1756 success = enqueueGpioSetGetCnfUlMsg (true, pGpioState);
RobMeades 0:e72ea6decc70 1757 }
RobMeades 0:e72ea6decc70 1758
RobMeades 0:e72ea6decc70 1759 return success;
RobMeades 0:e72ea6decc70 1760 }
RobMeades 0:e72ea6decc70 1761
RobMeades 0:e72ea6decc70 1762 /// Handle a GpioGetReq message
RobMeades 0:e72ea6decc70 1763 static bool handleGpioGetReqDlMsg (uint8_t gpio)
RobMeades 0:e72ea6decc70 1764 {
RobMeades 0:e72ea6decc70 1765 bool success = false;
RobMeades 0:e72ea6decc70 1766 GpioState_t gpioState;
RobMeades 0:e72ea6decc70 1767
RobMeades 0:e72ea6decc70 1768 printf ("\nHandling GpioGetReqDlMsg, gpio %d.\n", gpio);
RobMeades 0:e72ea6decc70 1769
RobMeades 0:e72ea6decc70 1770 gpioState.gpio = gpio;
RobMeades 0:e72ea6decc70 1771 success = getGpio (&gpioState);
RobMeades 0:e72ea6decc70 1772
RobMeades 0:e72ea6decc70 1773 if (success)
RobMeades 0:e72ea6decc70 1774 {
RobMeades 0:e72ea6decc70 1775 success = enqueueGpioSetGetCnfUlMsg (false, &gpioState);
RobMeades 0:e72ea6decc70 1776 }
RobMeades 0:e72ea6decc70 1777
RobMeades 0:e72ea6decc70 1778 return success;
RobMeades 0:e72ea6decc70 1779 }
RobMeades 0:e72ea6decc70 1780
RobMeades 0:e72ea6decc70 1781 /// Enqueue an LedSetCnf or an LedGetCnf message
RobMeades 0:e72ea6decc70 1782 static bool enqueueLedSetGetCnfUlMsg (bool setNotGet)
RobMeades 0:e72ea6decc70 1783 {
RobMeades 0:e72ea6decc70 1784 bool success = false;
RobMeades 0:e72ea6decc70 1785 uint32_t bytesEncoded = 0;
RobMeades 0:e72ea6decc70 1786 Datagram_t * pDatagram;
RobMeades 0:e72ea6decc70 1787
RobMeades 0:e72ea6decc70 1788 printf ("Preparing LedxxxCnfUlMsg response in a datagram...\n");
RobMeades 0:e72ea6decc70 1789 pDatagram = allocSendDatagram();
RobMeades 0:e72ea6decc70 1790 if (pDatagram != NULL)
RobMeades 0:e72ea6decc70 1791 {
RobMeades 0:e72ea6decc70 1792 // Encode the ledxxxCnfUlMsg into a datagram
RobMeades 0:e72ea6decc70 1793 printf ("Encoding datagram...\n");
RobMeades 0:e72ea6decc70 1794 if (setNotGet)
RobMeades 0:e72ea6decc70 1795 {
RobMeades 0:e72ea6decc70 1796 LedSetCnfUlMsg_t ledSetCnfUlMsg;
RobMeades 0:e72ea6decc70 1797
RobMeades 0:e72ea6decc70 1798 ledSetCnfUlMsg.onNotOff = readNvContext()->ledOnNotOff;
RobMeades 0:e72ea6decc70 1799 bytesEncoded += gMessageCodec.encodeLedSetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &ledSetCnfUlMsg);
RobMeades 0:e72ea6decc70 1800 }
RobMeades 0:e72ea6decc70 1801 else
RobMeades 0:e72ea6decc70 1802 {
RobMeades 0:e72ea6decc70 1803 LedGetCnfUlMsg_t ledGetCnfUlMsg;
RobMeades 0:e72ea6decc70 1804
RobMeades 0:e72ea6decc70 1805 ledGetCnfUlMsg.onNotOff = readNvContext()->ledOnNotOff;
RobMeades 0:e72ea6decc70 1806 bytesEncoded += gMessageCodec.encodeLedGetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &ledGetCnfUlMsg);
RobMeades 0:e72ea6decc70 1807 }
RobMeades 0:e72ea6decc70 1808
RobMeades 0:e72ea6decc70 1809 pDatagram->size = bytesEncoded;
RobMeades 0:e72ea6decc70 1810 success = true;
RobMeades 0:e72ea6decc70 1811 }
RobMeades 0:e72ea6decc70 1812 else
RobMeades 0:e72ea6decc70 1813 {
RobMeades 0:e72ea6decc70 1814 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate send datagram.");
RobMeades 0:e72ea6decc70 1815 }
RobMeades 0:e72ea6decc70 1816
RobMeades 0:e72ea6decc70 1817 return success;
RobMeades 0:e72ea6decc70 1818 }
RobMeades 0:e72ea6decc70 1819
RobMeades 0:e72ea6decc70 1820 /// Handle an LedSetReq message
RobMeades 0:e72ea6decc70 1821 static bool handleLedSetReqDlMsg (bool onNotOff)
RobMeades 0:e72ea6decc70 1822 {
RobMeades 0:e72ea6decc70 1823 printf ("\nHandling LedSetReqDlMsg, set gLedOnNotOff to 0x%x.\n", onNotOff);
RobMeades 0:e72ea6decc70 1824 setLed (onNotOff);
RobMeades 0:e72ea6decc70 1825
RobMeades 0:e72ea6decc70 1826 return enqueueLedSetGetCnfUlMsg (true);
RobMeades 0:e72ea6decc70 1827 }
RobMeades 0:e72ea6decc70 1828
RobMeades 0:e72ea6decc70 1829 /// Handle an LedGetReq message
RobMeades 0:e72ea6decc70 1830 static bool handleLedGetReqDlMsg (void)
RobMeades 0:e72ea6decc70 1831 {
RobMeades 0:e72ea6decc70 1832 printf ("\nHandling LedGetReqDlMsg.\n");
RobMeades 0:e72ea6decc70 1833
RobMeades 0:e72ea6decc70 1834 return enqueueLedSetGetCnfUlMsg (false);
RobMeades 0:e72ea6decc70 1835 }
RobMeades 0:e72ea6decc70 1836
RobMeades 0:e72ea6decc70 1837 /// Enqueue a FlashSetCnf or a FlashGetCnf message
RobMeades 0:e72ea6decc70 1838 static bool enqueueFlashSetGetCnfUlMsg (bool setNotGet)
RobMeades 0:e72ea6decc70 1839 {
RobMeades 0:e72ea6decc70 1840 bool success = false;
RobMeades 0:e72ea6decc70 1841 uint32_t bytesEncoded = 0;
RobMeades 0:e72ea6decc70 1842 Datagram_t * pDatagram;
RobMeades 0:e72ea6decc70 1843
RobMeades 0:e72ea6decc70 1844 printf ("Preparing FlashxxxCnfUlMsg response in a datagram...\n");
RobMeades 0:e72ea6decc70 1845 pDatagram = allocSendDatagram();
RobMeades 0:e72ea6decc70 1846 if (pDatagram != NULL)
RobMeades 0:e72ea6decc70 1847 {
RobMeades 0:e72ea6decc70 1848 // Encode the flashSetCnfUlMsg or flashGetCnfUlMsg into a datagram
RobMeades 0:e72ea6decc70 1849 printf ("Encoding datagram...\n");
RobMeades 0:e72ea6decc70 1850 if (setNotGet)
RobMeades 0:e72ea6decc70 1851 {
RobMeades 0:e72ea6decc70 1852 FlashSetCnfUlMsg_t flashSetCnfUlMsg;
RobMeades 0:e72ea6decc70 1853
RobMeades 0:e72ea6decc70 1854 flashSetCnfUlMsg.onNotOff = readNvContext()->flashOnNotOff;
RobMeades 0:e72ea6decc70 1855 bytesEncoded += gMessageCodec.encodeFlashSetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &flashSetCnfUlMsg);
RobMeades 0:e72ea6decc70 1856 }
RobMeades 0:e72ea6decc70 1857 else
RobMeades 0:e72ea6decc70 1858 {
RobMeades 0:e72ea6decc70 1859 FlashGetCnfUlMsg_t flashGetCnfUlMsg;
RobMeades 0:e72ea6decc70 1860
RobMeades 0:e72ea6decc70 1861 flashGetCnfUlMsg.onNotOff = readNvContext()->flashOnNotOff;
RobMeades 0:e72ea6decc70 1862 bytesEncoded += gMessageCodec.encodeFlashGetCnfUlMsg (&(pDatagram->pBody[bytesEncoded]), &flashGetCnfUlMsg);
RobMeades 0:e72ea6decc70 1863 }
RobMeades 0:e72ea6decc70 1864
RobMeades 0:e72ea6decc70 1865 pDatagram->size = bytesEncoded;
RobMeades 0:e72ea6decc70 1866 success = true;
RobMeades 0:e72ea6decc70 1867 }
RobMeades 0:e72ea6decc70 1868 else
RobMeades 0:e72ea6decc70 1869 {
RobMeades 0:e72ea6decc70 1870 assertAlways (DEBUG_SOS_MEMORY_ALLOC_PROBLEM, "Couldn't allocate send datagram.");
RobMeades 0:e72ea6decc70 1871 }
RobMeades 0:e72ea6decc70 1872
RobMeades 0:e72ea6decc70 1873 return success;
RobMeades 0:e72ea6decc70 1874 }
RobMeades 0:e72ea6decc70 1875
RobMeades 0:e72ea6decc70 1876 /// Handle a FlashSetReq message
RobMeades 0:e72ea6decc70 1877 static bool handleFlashSetReqDlMsg (bool onNotOff)
RobMeades 0:e72ea6decc70 1878 {
RobMeades 0:e72ea6decc70 1879 printf ("\nHandling FlashSetReqDlMsg, set gFlashOnNotOff to 0x%x.\n", onNotOff);
RobMeades 0:e72ea6decc70 1880 setFlash (onNotOff);
RobMeades 0:e72ea6decc70 1881
RobMeades 0:e72ea6decc70 1882 return enqueueFlashSetGetCnfUlMsg (true);
RobMeades 0:e72ea6decc70 1883 }
RobMeades 0:e72ea6decc70 1884
RobMeades 0:e72ea6decc70 1885 /// Handle a FlashGetReq message
RobMeades 0:e72ea6decc70 1886 static bool handleFlashGetReqDlMsg (void)
RobMeades 0:e72ea6decc70 1887 {
RobMeades 0:e72ea6decc70 1888 printf ("\nHandling FlashGetReqDlMsg.\n");
RobMeades 0:e72ea6decc70 1889
RobMeades 0:e72ea6decc70 1890 return enqueueFlashSetGetCnfUlMsg (false);
RobMeades 0:e72ea6decc70 1891 }
RobMeades 0:e72ea6decc70 1892
RobMeades 0:e72ea6decc70 1893 /// Process any received datagrams, queueing any response datagrams
RobMeades 0:e72ea6decc70 1894 // as appropriate.
RobMeades 0:e72ea6decc70 1895 static bool processReceivedDatagrams (void)
RobMeades 0:e72ea6decc70 1896 {
RobMeades 0:e72ea6decc70 1897 bool success = true;
RobMeades 0:e72ea6decc70 1898 uint32_t x;
RobMeades 0:e72ea6decc70 1899 DlMsgUnion_t dlMsg;
RobMeades 0:e72ea6decc70 1900 MessageCodec::DecodeResult_t decodeResult;
RobMeades 0:e72ea6decc70 1901 DatagramEntry_t * pEntry;
RobMeades 0:e72ea6decc70 1902 const char * pBuffer;
RobMeades 0:e72ea6decc70 1903
RobMeades 0:e72ea6decc70 1904 #ifdef DEBUG
RobMeades 0:e72ea6decc70 1905 printf ("\nProcessing received datagrams...\n");
RobMeades 0:e72ea6decc70 1906 #endif
RobMeades 0:e72ea6decc70 1907
RobMeades 0:e72ea6decc70 1908 pEntry = &gRecvDatagramListHead;
RobMeades 0:e72ea6decc70 1909 for (x = 0; (pEntry != NULL) && (x < MAX_NUM_DATAGRAMS); x++)
RobMeades 0:e72ea6decc70 1910 {
RobMeades 0:e72ea6decc70 1911 if (pEntry->inUse)
RobMeades 0:e72ea6decc70 1912 {
RobMeades 0:e72ea6decc70 1913 printf ("\nProcessing %ld (%ld bytes).\n", x, pEntry->datagram.size);
RobMeades 0:e72ea6decc70 1914 pBuffer = pEntry->datagram.pBody;
RobMeades 0:e72ea6decc70 1915
RobMeades 0:e72ea6decc70 1916 // Go through the entire datagram buffer looking for messages
RobMeades 0:e72ea6decc70 1917 while (pBuffer < (pEntry->datagram.pBody + pEntry->datagram.size))
RobMeades 0:e72ea6decc70 1918 {
RobMeades 0:e72ea6decc70 1919 decodeResult = gMessageCodec.decodeDlMsg (&pBuffer, pEntry->datagram.size, &dlMsg);
RobMeades 0:e72ea6decc70 1920
RobMeades 0:e72ea6decc70 1921 switch (decodeResult)
RobMeades 0:e72ea6decc70 1922 {
RobMeades 0:e72ea6decc70 1923 case (MessageCodec::DECODE_RESULT_REBOOT_REQ_DL_MSG):
RobMeades 0:e72ea6decc70 1924 {
RobMeades 0:e72ea6decc70 1925 success = handleRebootReqDlMsg (dlMsg.rebootReqDlMsg.devModeOnNotOff);
RobMeades 0:e72ea6decc70 1926 }
RobMeades 0:e72ea6decc70 1927 break;
RobMeades 0:e72ea6decc70 1928 case (MessageCodec::DECODE_RESULT_SERIAL_NUMBER_GET_REQ_DL_MSG):
RobMeades 0:e72ea6decc70 1929 {
RobMeades 0:e72ea6decc70 1930 success = handleSerialNumberGetReqDlMsg();
RobMeades 0:e72ea6decc70 1931 }
RobMeades 0:e72ea6decc70 1932 break;
RobMeades 0:e72ea6decc70 1933 case (MessageCodec::DECODE_RESULT_READING_INTERVAL_SET_REQ_DL_MSG):
RobMeades 0:e72ea6decc70 1934 {
RobMeades 0:e72ea6decc70 1935 success = handleReadingIntervalSetReqDlMsg (dlMsg.readingIntervalSetReqDlMsg.readingIntervalSeconds);
RobMeades 0:e72ea6decc70 1936 }
RobMeades 0:e72ea6decc70 1937 break;
RobMeades 0:e72ea6decc70 1938 case (MessageCodec::DECODE_RESULT_READING_INTERVAL_GET_REQ_DL_MSG):
RobMeades 0:e72ea6decc70 1939 {
RobMeades 0:e72ea6decc70 1940 success = handleReadingIntervalGetReqDlMsg();
RobMeades 0:e72ea6decc70 1941 }
RobMeades 0:e72ea6decc70 1942 break;
RobMeades 0:e72ea6decc70 1943 case (MessageCodec::DECODE_RESULT_GPIO_SET_REQ_DL_MSG):
RobMeades 0:e72ea6decc70 1944 {
RobMeades 0:e72ea6decc70 1945 success = handleGpioSetReqDlMsg (&(dlMsg.gpioSetReqDlMsg.gpioState));
RobMeades 0:e72ea6decc70 1946 }
RobMeades 0:e72ea6decc70 1947 break;
RobMeades 0:e72ea6decc70 1948 case (MessageCodec::DECODE_RESULT_GPIO_GET_REQ_DL_MSG):
RobMeades 0:e72ea6decc70 1949 {
RobMeades 0:e72ea6decc70 1950 success = handleGpioGetReqDlMsg(dlMsg.gpioGetReqDlMsg.gpio);
RobMeades 0:e72ea6decc70 1951 }
RobMeades 0:e72ea6decc70 1952 break;
RobMeades 0:e72ea6decc70 1953 case (MessageCodec::DECODE_RESULT_LED_SET_REQ_DL_MSG):
RobMeades 0:e72ea6decc70 1954 {
RobMeades 0:e72ea6decc70 1955 success = handleLedSetReqDlMsg (dlMsg.ledSetReqDlMsg.onNotOff);
RobMeades 0:e72ea6decc70 1956 }
RobMeades 0:e72ea6decc70 1957 break;
RobMeades 0:e72ea6decc70 1958 case (MessageCodec::DECODE_RESULT_LED_GET_REQ_DL_MSG):
RobMeades 0:e72ea6decc70 1959 {
RobMeades 0:e72ea6decc70 1960 success = handleLedGetReqDlMsg();
RobMeades 0:e72ea6decc70 1961 }
RobMeades 0:e72ea6decc70 1962 break;
RobMeades 0:e72ea6decc70 1963 case (MessageCodec::DECODE_RESULT_FLASH_SET_REQ_DL_MSG):
RobMeades 0:e72ea6decc70 1964 {
RobMeades 0:e72ea6decc70 1965 success = handleFlashSetReqDlMsg (dlMsg.flashSetReqDlMsg.onNotOff);
RobMeades 0:e72ea6decc70 1966 }
RobMeades 0:e72ea6decc70 1967 break;
RobMeades 0:e72ea6decc70 1968 case (MessageCodec::DECODE_RESULT_FLASH_GET_REQ_DL_MSG):
RobMeades 0:e72ea6decc70 1969 {
RobMeades 0:e72ea6decc70 1970 success = handleFlashGetReqDlMsg ();
RobMeades 0:e72ea6decc70 1971 }
RobMeades 0:e72ea6decc70 1972 break;
RobMeades 0:e72ea6decc70 1973 case (MessageCodec::DECODE_RESULT_FAILURE):
RobMeades 0:e72ea6decc70 1974 {
RobMeades 0:e72ea6decc70 1975 success = false;
RobMeades 0:e72ea6decc70 1976 assertAlways (DEBUG_SOS_PROTOCOL_PROBLEM, "Message decode failure.");
RobMeades 0:e72ea6decc70 1977 }
RobMeades 0:e72ea6decc70 1978 break;
RobMeades 0:e72ea6decc70 1979 case (MessageCodec::DECODE_RESULT_INPUT_TOO_SHORT):
RobMeades 0:e72ea6decc70 1980 {
RobMeades 0:e72ea6decc70 1981 success = false;
RobMeades 0:e72ea6decc70 1982 assertAlways (DEBUG_SOS_PROTOCOL_PROBLEM, "Message decode failure due to input too short.");
RobMeades 0:e72ea6decc70 1983 }
RobMeades 0:e72ea6decc70 1984 break;
RobMeades 0:e72ea6decc70 1985 case (MessageCodec::DECODE_RESULT_OUTPUT_TOO_SHORT):
RobMeades 0:e72ea6decc70 1986 {
RobMeades 0:e72ea6decc70 1987 success = false;
RobMeades 0:e72ea6decc70 1988 assertAlways (DEBUG_SOS_PROTOCOL_PROBLEM, "Message decode failure due to output buffer too short.");
RobMeades 0:e72ea6decc70 1989 }
RobMeades 0:e72ea6decc70 1990 break;
RobMeades 0:e72ea6decc70 1991 case (MessageCodec::DECODE_RESULT_UNKNOWN_MSG_ID):
RobMeades 0:e72ea6decc70 1992 {
RobMeades 0:e72ea6decc70 1993 success = false;
RobMeades 0:e72ea6decc70 1994 assertAlways (DEBUG_SOS_PROTOCOL_PROBLEM, "Unknown message ID.");
RobMeades 0:e72ea6decc70 1995 }
RobMeades 0:e72ea6decc70 1996 break;
RobMeades 0:e72ea6decc70 1997 default:
RobMeades 0:e72ea6decc70 1998 {
RobMeades 0:e72ea6decc70 1999 success = false;
RobMeades 0:e72ea6decc70 2000 assertAlways (DEBUG_SOS_PROTOCOL_PROBLEM, "Unknown decode result: 0x%x.", decodeResult);
RobMeades 0:e72ea6decc70 2001 }
RobMeades 0:e72ea6decc70 2002 break;
RobMeades 0:e72ea6decc70 2003 }
RobMeades 0:e72ea6decc70 2004 }
RobMeades 0:e72ea6decc70 2005 pEntry->inUse = false; // Done with this one now
RobMeades 0:e72ea6decc70 2006 }
RobMeades 0:e72ea6decc70 2007 pEntry = pEntry->pNextEntry; // Move to the next entry
RobMeades 0:e72ea6decc70 2008 }
RobMeades 0:e72ea6decc70 2009
RobMeades 0:e72ea6decc70 2010 freeUnusedRecvDatagrams();
RobMeades 0:e72ea6decc70 2011
RobMeades 0:e72ea6decc70 2012 return success;
RobMeades 0:e72ea6decc70 2013 }
RobMeades 0:e72ea6decc70 2014
RobMeades 0:e72ea6decc70 2015 #ifdef C027N_USE_SOFT_RADIO
RobMeades 0:e72ea6decc70 2016 // SoftModem should be connected to header pins 0 (Rx) and 1 (Tx)
RobMeades 0:e72ea6decc70 2017 MDMSerial gNeulSoftRadio (D1, D0, 57600, NC, NC);
RobMeades 0:e72ea6decc70 2018 #else
RobMeades 0:e72ea6decc70 2019 // When compiling under GCC off-line, this works.
RobMeades 0:e72ea6decc70 2020 // However, when building under the on-line IDE
RobMeades 0:e72ea6decc70 2021 // it seems one has to define MDMSerial using the D1 and D0
RobMeades 0:e72ea6decc70 2022 // pins _outside_ a function, static is just not good enough,
RobMeades 0:e72ea6decc70 2023 // whereas we must define MDMSerial using MDMTXD and MDMRXD
RobMeades 0:e72ea6decc70 2024 // _inside_ a function since it depends on some initialisation
RobMeades 0:e72ea6decc70 2025 // that is performed just before entry to main.
RobMeades 0:e72ea6decc70 2026 // Hence the lines above. But I'm leaving this here to
RobMeades 0:e72ea6decc70 2027 // show how it is meant to work.
RobMeades 0:e72ea6decc70 2028
RobMeades 0:e72ea6decc70 2029 // Create the Neul modem instance
RobMeades 0:e72ea6decc70 2030 static MDMSerial *getMDMSerial(void)
RobMeades 0:e72ea6decc70 2031 {
RobMeades 0:e72ea6decc70 2032 //#ifdef C027N_USE_SOFT_RADIO
RobMeades 0:e72ea6decc70 2033 // printf ("\nC027N_USE_SOFT_RADIO is defined.\n");
RobMeades 0:e72ea6decc70 2034 // printf ("The on-board modem will be ignored.\n");
RobMeades 0:e72ea6decc70 2035 // printf ("SoftModem should be connected to header pins 0 (Rx) and 1 (Tx).\n");
RobMeades 0:e72ea6decc70 2036 // static MDMSerial gNeul (D1, D0, 57600, NC, NC);
RobMeades 0:e72ea6decc70 2037 //#else
RobMeades 0:e72ea6decc70 2038 static MDMSerial gNeul (MDMTXD, MDMRXD, 57600, NC, NC);
RobMeades 0:e72ea6decc70 2039 //#endif
RobMeades 0:e72ea6decc70 2040 return &gNeul;
RobMeades 0:e72ea6decc70 2041 }
RobMeades 0:e72ea6decc70 2042 #endif
RobMeades 0:e72ea6decc70 2043
RobMeades 0:e72ea6decc70 2044 // ----------------------------------------------------------------
RobMeades 0:e72ea6decc70 2045 // PUBLIC FUNCTIONS
RobMeades 0:e72ea6decc70 2046 // ----------------------------------------------------------------
RobMeades 0:e72ea6decc70 2047 int realMain (uint8_t * pReserve)
RobMeades 0:e72ea6decc70 2048 {
RobMeades 0:e72ea6decc70 2049 bool success = false;
RobMeades 0:e72ea6decc70 2050
RobMeades 0:e72ea6decc70 2051 Serial pc (USBTX, USBRX);
RobMeades 0:e72ea6decc70 2052
RobMeades 0:e72ea6decc70 2053 pc.baud (PC_BAUD_RATE);
RobMeades 0:e72ea6decc70 2054
RobMeades 0:e72ea6decc70 2055 // Use pReserve to stop any attempts by the compiler to get rid of it
RobMeades 0:e72ea6decc70 2056 printf ("Reserved 0x%08lX-0x%08lX for IAP stack.\n", (long unsigned int) pReserve, (long unsigned int) (pReserve + SIZE_STACK_FOR_IAP - 1));
RobMeades 0:e72ea6decc70 2057
RobMeades 0:e72ea6decc70 2058 printf ("\n%s revision details:\n", __FILE__);
RobMeades 0:e72ea6decc70 2059 printf ("%s (European time).\n", FILE_DATETIME);
RobMeades 0:e72ea6decc70 2060 printf ("%s, %s.\n\n", FILE_REV, FILE_CL);
RobMeades 0:e72ea6decc70 2061
RobMeades 0:e72ea6decc70 2062 printf ("This build will still run if no water meter is connected.\n");
RobMeades 0:e72ea6decc70 2063 printf ("The water volume and serial number will be garbage.\n");
RobMeades 0:e72ea6decc70 2064
RobMeades 0:e72ea6decc70 2065 // Instantiate the Neul modem class
RobMeades 0:e72ea6decc70 2066 #ifdef C027N_USE_SOFT_RADIO
RobMeades 0:e72ea6decc70 2067 pgNeul = &gNeulSoftRadio;
RobMeades 0:e72ea6decc70 2068 #else
RobMeades 0:e72ea6decc70 2069 pgNeul = getMDMSerial();
RobMeades 0:e72ea6decc70 2070 #endif
RobMeades 0:e72ea6decc70 2071
RobMeades 0:e72ea6decc70 2072 if (pgNeul != NULL)
RobMeades 0:e72ea6decc70 2073 {
RobMeades 0:e72ea6decc70 2074 // Initialise main
RobMeades 0:e72ea6decc70 2075 success = init();
RobMeades 0:e72ea6decc70 2076 }
RobMeades 0:e72ea6decc70 2077 else
RobMeades 0:e72ea6decc70 2078 {
RobMeades 0:e72ea6decc70 2079 assertAlways (DEBUG_SOS_GENERIC_FAILURE, "Unable to instantiate modem class.");
RobMeades 0:e72ea6decc70 2080 }
RobMeades 0:e72ea6decc70 2081
RobMeades 0:e72ea6decc70 2082 if (success)
RobMeades 0:e72ea6decc70 2083 {
RobMeades 0:e72ea6decc70 2084 // Initialise the water meter
RobMeades 0:e72ea6decc70 2085 printf ("Initialising water meter...\n");
RobMeades 0:e72ea6decc70 2086 //gWaterMeter.setDebugOn(true);
RobMeades 0:e72ea6decc70 2087 gWaterMeter.init();
RobMeades 0:e72ea6decc70 2088
RobMeades 0:e72ea6decc70 2089 // Initialise the Neul module
RobMeades 0:e72ea6decc70 2090 printf ("Initialising module...\n");
RobMeades 0:e72ea6decc70 2091 pgNeul->setDebug(3); // Normally set to 2, set to 3 for maximum debug
RobMeades 0:e72ea6decc70 2092 success = pgNeul->init();
RobMeades 0:e72ea6decc70 2093
RobMeades 0:e72ea6decc70 2094 if (success)
RobMeades 0:e72ea6decc70 2095 {
RobMeades 0:e72ea6decc70 2096 // Allow the user to configure the module
RobMeades 0:e72ea6decc70 2097 configureModule();
RobMeades 0:e72ea6decc70 2098
RobMeades 0:e72ea6decc70 2099 if (gModulePhase > MODULE_PHASE_1)
RobMeades 0:e72ea6decc70 2100 {
RobMeades 0:e72ea6decc70 2101 // Wait for registration to complete but
RobMeades 0:e72ea6decc70 2102 // only if phase 2 or higher as the CONNECT
RobMeades 0:e72ea6decc70 2103 // string was never returned in earlier versions
RobMeades 0:e72ea6decc70 2104 printf ("Waiting for device to register...\n");
RobMeades 0:e72ea6decc70 2105 success = waitReg (WAIT_REG_S);
RobMeades 0:e72ea6decc70 2106 }
RobMeades 0:e72ea6decc70 2107
RobMeades 0:e72ea6decc70 2108 if (success)
RobMeades 0:e72ea6decc70 2109 {
RobMeades 0:e72ea6decc70 2110 // Prepare the initial messages in a datagram
RobMeades 0:e72ea6decc70 2111 success = queueInitialDatagram();
RobMeades 0:e72ea6decc70 2112
RobMeades 0:e72ea6decc70 2113 while (success)
RobMeades 0:e72ea6decc70 2114 {
RobMeades 0:e72ea6decc70 2115 Timer timer;
RobMeades 0:e72ea6decc70 2116 uint32_t readingIntervalSeconds = readNvContext()->readingIntervalSeconds;
RobMeades 0:e72ea6decc70 2117
RobMeades 0:e72ea6decc70 2118 timer.start();
RobMeades 0:e72ea6decc70 2119
RobMeades 0:e72ea6decc70 2120 // Prepare the periodic messages in a datagram
RobMeades 0:e72ea6decc70 2121 success = queuePeriodicDatagram ();
RobMeades 0:e72ea6decc70 2122
RobMeades 0:e72ea6decc70 2123 // Now do sends and then receives for the interval
RobMeades 0:e72ea6decc70 2124 printf ("\nSending and then receiving datagrams for %ld seconds...\n", readingIntervalSeconds);
RobMeades 0:e72ea6decc70 2125 while ((timer.read() < readingIntervalSeconds) && success)
RobMeades 0:e72ea6decc70 2126 {
RobMeades 0:e72ea6decc70 2127 success = sendAndReceive() && processReceivedDatagrams();
RobMeades 0:e72ea6decc70 2128 printf (".");
RobMeades 0:e72ea6decc70 2129 }
RobMeades 0:e72ea6decc70 2130 printf ("\n");
RobMeades 0:e72ea6decc70 2131 }
RobMeades 0:e72ea6decc70 2132
RobMeades 0:e72ea6decc70 2133 assertAlways (DEBUG_SOS_GENERIC_FAILURE, "Exited main loop with success = false.");
RobMeades 0:e72ea6decc70 2134 }
RobMeades 0:e72ea6decc70 2135 else
RobMeades 0:e72ea6decc70 2136 {
RobMeades 0:e72ea6decc70 2137 assertAlways (DEBUG_SOS_NETWORK_SEND_PROBLEM, "Registration failed.");
RobMeades 0:e72ea6decc70 2138 }
RobMeades 0:e72ea6decc70 2139 }
RobMeades 0:e72ea6decc70 2140 else
RobMeades 0:e72ea6decc70 2141 {
RobMeades 0:e72ea6decc70 2142 assertAlways (DEBUG_SOS_AT_COMMAND_PROBLEM, "Modem initialisation failed.");
RobMeades 0:e72ea6decc70 2143 }
RobMeades 0:e72ea6decc70 2144
RobMeades 0:e72ea6decc70 2145 // Tidy up
RobMeades 0:e72ea6decc70 2146 deInit();
RobMeades 0:e72ea6decc70 2147 }
RobMeades 0:e72ea6decc70 2148 else
RobMeades 0:e72ea6decc70 2149 {
RobMeades 0:e72ea6decc70 2150 assertAlways (DEBUG_SOS_GENERIC_FAILURE, "Initialisation failed.");
RobMeades 0:e72ea6decc70 2151 }
RobMeades 0:e72ea6decc70 2152
RobMeades 0:e72ea6decc70 2153 return 0;
RobMeades 0:e72ea6decc70 2154 }
RobMeades 0:e72ea6decc70 2155
RobMeades 0:e72ea6decc70 2156 // This is necessary as the IAP functions use the top SIZE_STACK_FOR_IAP bytes of
RobMeades 0:e72ea6decc70 2157 // RAM for their own purposes
RobMeades 0:e72ea6decc70 2158 int main()
RobMeades 0:e72ea6decc70 2159 {
RobMeades 0:e72ea6decc70 2160 uint8_t reserve[SIZE_STACK_FOR_IAP];
RobMeades 0:e72ea6decc70 2161
RobMeades 0:e72ea6decc70 2162 return realMain (reserve);
RobMeades 0:e72ea6decc70 2163 }
RobMeades 0:e72ea6decc70 2164
RobMeades 0:e72ea6decc70 2165 // End Of File