A simple CIoT message protocol, used in the Water Meter Demos.
This library provides a small messaging protocol for a CIoT device, intended for use with the Water Meter Demo. As well as building for the C027 target, files are included for building a C DLL and, from that, a C Sharp DLL which can be linked into the PC-end of the Water Meter Demo (see the .ZIP file stored in the Wiki of the Water Meter Demo project) to provide end-to-end messaging with complete transparency. Since these PC files cannot be built inside mbed the source files are post-fixed with a ".txt" extension to keep them out of the way.
If a water pump is to be switched on/off as part of the demo, an interface circuit is required, which is described on the Wiki of the WaterMeterSupport library.
Revision 0:5c46cb3be899, committed 2015-05-22
- Comitter:
- RobMeades
- Date:
- Fri May 22 11:41:38 2015 +0000
- Commit message:
- Initial commit of CIoT message protocol, used for water meter demo demonstrations, to mbed cloud.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/IotMeterApi.hpp Fri May 22 11:41:38 2015 +0000
@@ -0,0 +1,423 @@
+/* C027N/water-meter interface definition for Water Meter Demo
+ *
+ * Copyright (C) u-blox Melbourn Ltd
+ * u-blox Melbourn Ltd, Melbourn, UK
+ *
+ * All rights reserved.
+ *
+ * This source file is the sole property of u-blox Melbourn Ltd.
+ * Reproduction or utilization of this source in whole or part is
+ * forbidden without the written consent of u-blox Melbourn Ltd.
+ */
+
+#ifndef IOT_METER_API_HPP
+#define IOT_METER_API_HPP
+
+/**
+ * @file iot_meter_api.h
+ * This file defines the API to the C027N/water-meter device
+ * for the MWC demo 2015.
+ */
+
+#include <IotMeterMsgs.hpp>
+
+// ----------------------------------------------------------------
+// HARDWARE
+// The code in this library is setup to expect a Water Pump Relay,
+// a Crydom D2425, to be connected through this circuit:
+//
+// C027N board D2425 (Water Pump Relay)
+//
+// 5V o------------o
+// |
+// | |
+// | | 180 Ohm
+// | |
+// |
+// o--------------o '+3' pin
+// 10k Ohm |
+// ___ /
+// D7 o--|___|--| (transistor)
+// _\/
+// |
+// |
+// |
+// Gnd o-----------o--------------o '4' pin
+//
+// ----------------------------------------------------------------
+
+// ----------------------------------------------------------------
+// GENERAL COMPILE-TIME CONSTANTS
+// ----------------------------------------------------------------
+
+/// The maximum length of a raw datagram in bytes
+#define MAX_DATAGRAM_SIZE_RAW 20
+
+// The GPIO that the water pump is connected to on the C027N board
+#define GPIO_WATER_PUMP 7
+
+// ----------------------------------------------------------------
+// CLASSES
+// ----------------------------------------------------------------
+
+class MessageCodec {
+public:
+
+ // ----------------------------------------------------------------
+ // MESSAGE ENCODING FUNCTIONS
+ // ----------------------------------------------------------------
+
+ /// Encode an uplink message that is sent at power-on of the
+ // device. Indicates that the device has been initialised. After
+ // transmission of this message meter readings will be returned
+ // at the indicated rate.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeInitIndUlMsg (char * pBuffer,
+ InitIndUlMsg_t * pMsg);
+
+ /// Encode a downlink message that reboots the device.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeRebootReqDlMsg (char * pBuffer,
+ RebootReqDlMsg_t *pMsg);
+
+ /// Encode an uplink message containing the current meter reading.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeVolumeIndUlMsg (char * pBuffer,
+ VolumeIndUlMsg_t * pMsg);
+
+ /// Encode an uplink message containing the current RSSI reading.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeRssiIndUlMsg (char * pBuffer,
+ RssiIndUlMsg_t * pMsg);
+
+ /// Encode a downlink message that sets the reading interval
+ // of the water meter.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \return The number of bytes encoded.
+ uint32_t encodeSerialNumberGetReqDlMsg (char * pBuffer);
+
+ /// Encode an uplink message that is sent as a response to a
+ // SerialNumberGetReqDlMsg.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeSerialNumberGetCnfUlMsg (char * pBuffer,
+ SerialNumberGetCnfUlMsg_t * pMsg);
+
+ /// Encode an uplink message that is sent at power-on of the
+ // device and in response to an InitReqDlMsg. Indicates the
+ // serial number of the device.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeSerialNumberIndUlMsg (char * pBuffer,
+ SerialNumberIndUlMsg_t * pMsg);
+
+ /// Encode a downlink message that retrieves the reading interval.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeReadingIntervalGetReqDlMsg (char * pBuffer);
+
+ /// Encode an uplink message that is sent as a response to a
+ // ReadingIntervalGetReqDlMsg.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeReadingIntervalGetCnfUlMsg (char * pBuffer,
+ ReadingIntervalGetCnfUlMsg_t * pMsg);
+
+ /// Encode a downlink message that sets the reading interval.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \return The number of bytes encoded.
+ uint32_t encodeReadingIntervalSetReqDlMsg (char * pBuffer,
+ ReadingIntervalSetReqDlMsg_t * pMsg);
+
+ /// Encode an uplink message that is sent as a response to a
+ // ReadingIntervalSetReqDlMsg.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeReadingIntervalSetCnfUlMsg (char * pBuffer,
+ ReadingIntervalSetCnfUlMsg_t * pMsg);
+
+ /// Encode a downlink message that gets the state of a GPIO
+ // on the C027N board.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \return The number of bytes encoded.
+ uint32_t encodeGpioGetReqDlMsg (char * pBuffer,
+ GpioGetReqDlMsg_t *pMsg);
+
+ /// Encode an uplink message that is sent as a response to a
+ // GpioGetReqDlMsg.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeGpioGetCnfUlMsg (char * pBuffer,
+ GpioGetCnfUlMsg_t * pMsg);
+
+ /// Encode a downlink message that sets the state of a GPIO
+ // on the C027N board.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeGpioSetReqDlMsg (char * pBuffer,
+ GpioSetReqDlMsg_t * pMsg);
+
+ /// Encode an uplink message that is sent as a response to a
+ // GpioSetReqDlMsg.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeGpioSetCnfUlMsg (char * pBuffer,
+ GpioSetCnfUlMsg_t * pMsg);
+
+ /// Encode a downlink message that gets the steady state of the
+ // red LED on the C027N board.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \return The number of bytes encoded.
+ uint32_t encodeLedGetReqDlMsg (char * pBuffer);
+
+ /// Encode an uplink message that is sent as a response to an
+ // LedGetReqDlMsg.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeLedGetCnfUlMsg (char * pBuffer,
+ LedGetCnfUlMsg_t * pMsg);
+
+ /// Encode a downlink message that sets the steady state of
+ // the red LED.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeLedSetReqDlMsg (char * pBuffer,
+ LedSetReqDlMsg_t * pMsg);
+
+ /// Encode an uplink message that is sent as a response to an
+ // LedSetReqDlMsg.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeLedSetCnfUlMsg (char * pBuffer,
+ LedSetCnfUlMsg_t * pMsg);
+
+ /// Encode a downlink message that sets the red LED to flash when
+ // a message is being sent/received (or not). If LedSetReqDlMsg
+ // has set the LED to ON the flash will be 'inverted', i.e. the
+ // red LED will blink off when a message is being transmitted
+ // or received instead.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeFlashSetReqDlMsg (char * pBuffer,
+ FlashSetReqDlMsg_t * pMsg);
+
+ /// Encode an uplink message that is sent as a response to a
+ // FlashSetReqDlMsg.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeFlashSetCnfUlMsg (char * pBuffer,
+ FlashSetCnfUlMsg_t * pMsg);
+
+ /// Encode a downlink message that gets the red LED to flash when
+ // a message is being sent/received (or not). If LedSetReqDlMsg
+ // has set the LED to ON the flash will be 'inverted', i.e. the
+ // red LED will blink off when a message is being transmitted
+ // or received instead.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeFlashGetReqDlMsg (char * pBuffer);
+
+ /// Encode an uplink message that is sent as a response to a
+ // FlashGetReqDlMsg.
+ // \param pBuffer A pointer to the buffer to encode into. The
+ // buffer length must be at least MAX_MESSAGE_SIZE long
+ // \param pMsg A pointer to the message to send.
+ // \return The number of bytes encoded.
+ uint32_t encodeFlashGetCnfUlMsg (char * pBuffer,
+ FlashGetCnfUlMsg_t * pMsg);
+
+ // ----------------------------------------------------------------
+ // MESSAGE DECODING FUNCTIONS
+ // ----------------------------------------------------------------
+
+ /// The outcome of message decoding.
+ //
+ // !!! When you add anything to the generic of UL sections
+ // here (but not the DL bits as C# never decodes a DL thing),
+ // align it with the DLL exported version in the dll wrapper files
+ // so that the C# application can decode it.
+ typedef enum DecodeResultTag_t
+ {
+ DECODE_RESULT_FAILURE = 0, //!< Generic failed decode.
+ DECODE_RESULT_INPUT_TOO_SHORT, //!< Not enough input bytes.
+ DECODE_RESULT_OUTPUT_TOO_SHORT, //!< Not enough room in the
+ //! output.
+ DECODE_RESULT_UNKNOWN_MSG_ID, //!< Rogue message ID.
+ DECODE_RESULT_DL_MSG_BASE = 0x40, //!< From here on are the
+ //! downlink messages.
+ // !!! If you add one here
+ // update the next line !!!
+ DECODE_RESULT_REBOOT_REQ_DL_MSG = DECODE_RESULT_DL_MSG_BASE,
+ DECODE_RESULT_SERIAL_NUMBER_GET_REQ_DL_MSG,
+ DECODE_RESULT_READING_INTERVAL_SET_REQ_DL_MSG,
+ DECODE_RESULT_READING_INTERVAL_GET_REQ_DL_MSG,
+ DECODE_RESULT_GPIO_SET_REQ_DL_MSG,
+ DECODE_RESULT_GPIO_GET_REQ_DL_MSG,
+ DECODE_RESULT_LED_SET_REQ_DL_MSG,
+ DECODE_RESULT_LED_GET_REQ_DL_MSG,
+ DECODE_RESULT_FLASH_SET_REQ_DL_MSG,
+ DECODE_RESULT_FLASH_GET_REQ_DL_MSG, // !!! If you add one here
+ // update the next line !!!
+ MAX_DL_REQ_MSG = DECODE_RESULT_FLASH_GET_REQ_DL_MSG,
+ DECODE_RESULT_UL_MSG_BASE = 0x80, //!< From here on are the
+ //! uplink messages.
+ DECODE_RESULT_INIT_IND_UL_MSG = DECODE_RESULT_UL_MSG_BASE,
+ DECODE_RESULT_SERIAL_NUMBER_IND_UL_MSG,
+ DECODE_RESULT_SERIAL_NUMBER_GET_CNF_UL_MSG,
+ DECODE_RESULT_VOLUME_IND_UL_MSG,
+ DECODE_RESULT_RSSI_IND_UL_MSG,
+ DECODE_RESULT_READING_INTERVAL_SET_CNF_UL_MSG,
+ DECODE_RESULT_READING_INTERVAL_GET_CNF_UL_MSG,
+ DECODE_RESULT_GPIO_SET_CNF_UL_MSG,
+ DECODE_RESULT_GPIO_GET_CNF_UL_MSG,
+ DECODE_RESULT_LED_SET_CNF_UL_MSG,
+ DECODE_RESULT_LED_GET_CNF_UL_MSG,
+ DECODE_RESULT_FLASH_SET_CNF_UL_MSG,
+ DECODE_RESULT_FLASH_GET_CNF_UL_MSG, // !!! If you add one here update
+ // the next line !!!
+ MAX_UL_REQ_MSG = DECODE_RESULT_FLASH_GET_CNF_UL_MSG,
+ MAX_NUM_DECODE_RESULTS //!< The maximum number of
+ //! decode results.
+ } DecodeResult_t;
+
+ /// Decode a downlink message. When a datagram has been received
+ // this function should be called iteratively to decode all the
+ // messages contained within it. The result, in pOutputBuffer,
+ // should be cast by the calling function to DlMsgUnion_t and
+ // the relevant member selected according to the
+ // DecodeResult_t code.
+ // \param ppInBuffer A pointer to the pointer to decode from.
+ // On completion this is pointing to the next byte that
+ // could be decoded, after the currently decoded message,
+ // in the buffer.
+ // \param sizeInBuffer The number of bytes left to decode.
+ // \param pOutBuffer A pointer to the buffer to write the
+ // result into.
+ // \param pBytesDecoded A pointer to a place to write the number
+ // of bytes decoded.
+ // \return The result of the decoding, which hopefully says
+ // what message has been decoded.
+ DecodeResult_t decodeDlMsg (const char ** ppInBuffer,
+ uint32_t sizeInBuffer,
+ DlMsgUnion_t * pOutBuffer);
+
+ /// Decode an uplink message. When a datagram has been received
+ // this function should be called iteratively to decode all the
+ // messages contained within it. The result, in pOutputBuffer,
+ // should be cast by the calling function to UlMsgUnion_t and
+ // the relevant member selected according to the
+ // DecodeResult_t code.
+ // \param ppInBuffer A pointer to the pointer to decode from.
+ // On completion this is pointing to the next byte that
+ // could be decoded, after the currently decoded message,
+ // in the buffer.
+ // \param sizeInBuffer The number of bytes left to decode.
+ // \param pOutBuffer A pointer to the buffer to write the
+ // result into.
+ // \return The result of the decoding, which hopefully says
+ // what message has been decoded.
+ DecodeResult_t decodeUlMsg (const char ** ppInBuffer,
+ uint32_t sizeInBuffer,
+ UlMsgUnion_t * pOutBuffer);
+
+ // ----------------------------------------------------------------
+ // MISC FUNCTIONS
+ // ----------------------------------------------------------------
+
+ /// Only used in the DLL form, sets up the "printf()" function
+ // for logging.
+ // \param guiPrintToConsole the printf function.
+ void initDll (void (*guiPrintToConsole) (const char *));
+
+ /// User callback function for "printf()" logging.
+ static void (*mp_guiPrintToConsole) (const char *);
+
+private:
+ /// Encode a boolean value.
+ // \param pBuffer A pointer to where the encoded
+ // value should be placed.
+ // \param value The Boolean value.
+ // \return The number of bytes encoded.
+ uint32_t encodeBool (char * pBuffer, bool value);
+ /// Decode a Boolean value.
+ // \param ppBuffer A pointer to the pointer to decode.
+ // On completion this points to the location after the
+ // bool in the input buffer.
+ // \return The decoded value.
+ bool decodeBool (const char ** ppBuffer);
+ /// Encode a uint32_t value.
+ // \param pBuffer A pointer to the value to decode.
+ // \param value The value.
+ // \return The number of bytes encoded.
+ uint32_t encodeUint32 (char * pBuffer, uint32_t value);
+ /// Decode a uint32_t value.
+ // \param ppBuffer A pointer to the pointer to decode.
+ // On completion this points to the location after the
+ // uint32 in the input buffer.
+ uint32_t decodeUint32 (const char ** ppBuffer);
+ /// Encode GpioState.
+ // \param pBuffer A pointer to the value to decode.
+ // \param gGpioState A pointer to the place to put the
+ // GPIO Sate.
+ // \return The number of bytes encoded.
+ uint32_t encodeGpioState (char * pBuffer, GpioState_t *pGpioState);
+ /// Decode Gpio_State_t.
+ // \param gGpioState_t a pointer to a place to put the
+ // decoded GPIO state.
+ // \param ppBuffer A pointer to the pointer to decode.
+ // On completion this points to the location after the
+ // uint32 in the input buffer.
+ void decodeGpioState (GpioState_t * pGpioState,
+ const char ** ppBuffer);
+ /// Log a message for debugging, "printf()" style.
+ // \param pFormat The printf() stle parameters.
+ void logMsg (const char * pFormat, ...);
+};
+
+#endif
+
+// End Of File
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/IotMeterDllWrapper.cpp.txt Fri May 22 11:41:38 2015 +0000
@@ -0,0 +1,234 @@
+/* DLL wrapper for C027N/water-meter message handling functions
+ * for MWC demo 2015
+ *
+ * Copyright (C) u-blox Melbourn Ltd
+ * u-blox Melbourn Ltd, Melbourn, UK
+ *
+ * All rights reserved.
+ *
+ * This source file is the sole property of u-blox Melbourn Ltd.
+ * Reproduction or utilization of this source in whole or part is
+ * forbidden without the written consent of u-blox Melbourn Ltd.
+ */
+
+/**
+ * @file iot_meter_dll_wrapper.cpp
+ * This file implements the encapsulation necessary to
+ * call the CPP Message Handling functions from C#.
+ */
+#include <stdint.h>
+#include <IotMeterApi.hpp>
+#include <IotMeterDllWrapper.hpp>
+#include "windows.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Instantiate a messageHandler
+ MessageCodec gMessageCodec;
+
+ // ----------------------------------------------------------------
+ // CONSTANTS
+ // ----------------------------------------------------------------
+
+ uint32_t __cdecl maxDatagramSizeRaw (void)
+ {
+ return MAX_DATAGRAM_SIZE_RAW;
+ }
+
+ uint32_t __cdecl gpioWaterPump (void)
+ {
+ return GPIO_WATER_PUMP;
+ }
+
+ // ----------------------------------------------------------------
+ // PRIVATE FUNCTIONS
+ // ----------------------------------------------------------------
+
+ // ----------------------------------------------------------------
+ // MESSAGE ENCODE WRAPPER FUNCTIONS
+ // ----------------------------------------------------------------
+
+ // Wrap encodeRebootReqDlMsg
+ uint32_t __cdecl encodeRebootReqDlMsg (char * pBuffer,
+ bool devModeOnNotOff)
+ {
+ RebootReqDlMsg_t msg;
+ msg.devModeOnNotOff = devModeOnNotOff;
+
+ return gMessageCodec.encodeRebootReqDlMsg (pBuffer, &msg);
+ }
+
+ // Wrap encodeSerialNumberGetReqDlMsg
+ uint32_t __cdecl encodeSerialNumberGetReqDlMsg (char * pBuffer)
+ {
+ return gMessageCodec.encodeSerialNumberGetReqDlMsg (pBuffer);
+ }
+
+ // Wrap encodeReadingIntervalSetReqDlMsg
+ uint32_t __cdecl encodeReadingIntervalSetReqDlMsg (char * pBuffer,
+ uint32_t readingIntervalSeconds)
+ {
+ ReadingIntervalSetReqDlMsg_t msg;
+ msg.readingIntervalSeconds = readingIntervalSeconds;
+
+ return gMessageCodec.encodeReadingIntervalSetReqDlMsg (pBuffer, &msg);
+ }
+
+ // Wrap encodeReadingIntervalGetReqDlMsg
+ uint32_t __cdecl encodeReadingIntervalGetReqDlMsg (char * pBuffer)
+ {
+ return gMessageCodec.encodeReadingIntervalGetReqDlMsg (pBuffer);
+ }
+
+ // Wrap encodeGpioSetReqDlMsg
+ uint32_t __cdecl encodeGpioSetReqDlMsg (char * pBuffer,
+ uint8_t gpio,
+ bool inputNotOutput,
+ bool onNotOff)
+ {
+ GpioSetReqDlMsg_t msg;
+ msg.gpioState.gpio = gpio;
+ msg.gpioState.inputNotOutput = inputNotOutput;
+ msg.gpioState.onNotOff = onNotOff;
+
+ return gMessageCodec.encodeGpioSetReqDlMsg (pBuffer, &msg);
+ }
+
+ // Wrap encodeGpioGetReqDlMsg
+ uint32_t __cdecl encodeGpioGetReqDlMsg (char * pBuffer,
+ uint32_t gpio)
+ {
+ GpioGetReqDlMsg_t msg;
+ msg.gpio = (uint8_t) gpio;
+
+ return gMessageCodec.encodeGpioGetReqDlMsg (pBuffer, &msg);
+ }
+
+ // Wrap encodeLedSetReqDlMsg
+ uint32_t __cdecl encodeLedSetReqDlMsg (char * pBuffer,
+ bool onNotOff)
+ {
+ LedSetReqDlMsg_t msg;
+ msg.onNotOff = onNotOff;
+
+ return gMessageCodec.encodeLedSetReqDlMsg (pBuffer, &msg);
+ }
+
+ // Wrap encodeLedGetReqDlMsg
+ uint32_t __cdecl encodeLedGetReqDlMsg (char * pBuffer)
+ {
+ return gMessageCodec.encodeLedGetReqDlMsg (pBuffer);
+ }
+
+ // Wrap encodeFlashSetReqDlMsg
+ uint32_t __cdecl encodeFlashSetReqDlMsg (char * pBuffer,
+ bool onNotOff)
+ {
+ FlashSetReqDlMsg_t msg;
+ msg.onNotOff = onNotOff;
+
+ return gMessageCodec.encodeFlashSetReqDlMsg (pBuffer, &msg);
+ }
+
+ // Wrap encodeFlashGetReqDlMsg
+ uint32_t __cdecl encodeFlashGetReqDlMsg (char * pBuffer)
+ {
+ return gMessageCodec.encodeFlashGetReqDlMsg (pBuffer);
+ }
+
+ // ----------------------------------------------------------------
+ // MESSAGE DECODE WRAPPER FUNCTIONS
+ // ----------------------------------------------------------------
+
+ // Unpack a gpioState struct from with a uint32_t value
+ void __cdecl unpackGpioState (uint32_t value,
+ uint32_t *pGpio,
+ bool * pInputNotOutput,
+ bool * pOnNotOff)
+ {
+ *pGpio = (uint32_t) ((value & 0x00FF0000) >> 16);
+ if (pInputNotOutput != NULL)
+ {
+ *pInputNotOutput = (bool) ((value & 0x0000FF00) >> 8);
+ }
+ if (pOnNotOff != NULL)
+ {
+ *pOnNotOff = (bool) (value & 0x000000FF);
+ }
+ }
+
+ // Wrap decodeUlMsg
+ uint32_t __cdecl decodeUlMsg (const char ** ppInBuffer,
+ uint32_t sizeInBuffer,
+ uint32_t * pContents)
+ {
+ MessageCodec::DecodeResult_t decodeResult;
+ UlMsgUnion_t outBuffer;
+ decodeResult = gMessageCodec.decodeUlMsg (ppInBuffer,
+ sizeInBuffer,
+ &outBuffer);
+ switch (decodeResult)
+ {
+ case (MessageCodec::DECODE_RESULT_INIT_IND_UL_MSG):
+ *pContents = (uint32_t) outBuffer.initIndUlMsg.wakeUpCode;
+ break;
+ case (MessageCodec::DECODE_RESULT_SERIAL_NUMBER_GET_CNF_UL_MSG):
+ *pContents = outBuffer.serialNumberCnfUlMsg.serialNumber;
+ break;
+ case (MessageCodec::DECODE_RESULT_SERIAL_NUMBER_IND_UL_MSG):
+ *pContents = outBuffer.serialNumberIndUlMsg.serialNumber;
+ break;
+ case (MessageCodec::DECODE_RESULT_VOLUME_IND_UL_MSG):
+ *pContents = outBuffer.volumeIndUlMsg.volumeLitres;
+ break;
+ case (MessageCodec::DECODE_RESULT_RSSI_IND_UL_MSG):
+ *pContents = outBuffer.rssiIndUlMsg.rssi;
+ break;
+ case (MessageCodec::DECODE_RESULT_READING_INTERVAL_SET_CNF_UL_MSG):
+ *pContents = outBuffer.readingIntervalSetCnfUlMsg.readingIntervalSeconds;
+ break;
+ case (MessageCodec::DECODE_RESULT_READING_INTERVAL_GET_CNF_UL_MSG):
+ *pContents = outBuffer.readingIntervalGetCnfUlMsg.readingIntervalSeconds;
+ break;
+ case (MessageCodec::DECODE_RESULT_GPIO_SET_CNF_UL_MSG):
+ *pContents = (uint32_t) outBuffer.gpioSetCnfUlMsg;
+ break;
+ case (MessageCodec::DECODE_RESULT_GPIO_GET_CNF_UL_MSG):
+ *pContents = (uint32_t) outBuffer.gpioGetCnfUlMsg;
+ break;
+ case (MessageCodec::DECODE_RESULT_LED_SET_CNF_UL_MSG):
+ *pContents = (uint32_t) outBuffer.ledSetCnfUlMsg.onNotOff;
+ break;
+ case (MessageCodec::DECODE_RESULT_LED_GET_CNF_UL_MSG):
+ *pContents = (uint32_t) outBuffer.ledGetCnfUlMsg.onNotOff;
+ break;
+ case (MessageCodec::DECODE_RESULT_FLASH_SET_CNF_UL_MSG):
+ *pContents = (uint32_t) outBuffer.flashSetCnfUlMsg.onNotOff;
+ break;
+ case (MessageCodec::DECODE_RESULT_FLASH_GET_CNF_UL_MSG):
+ *pContents = (uint32_t) outBuffer.flashGetCnfUlMsg.onNotOff;
+ break;
+ default:
+ // The decodeResult will be left as Unknown message
+ break;
+ }
+
+ return decodeResult;
+ }
+
+ // ----------------------------------------------------------------
+ // MISC FUNCTIONS
+ // ----------------------------------------------------------------
+
+ void initDll (void (*printToConsole) (const char *))
+ {
+ gMessageCodec.initDll (printToConsole);
+ }
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+// End Of File
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/IotMeterDllWrapper.cs.txt Fri May 22 11:41:38 2015 +0000
@@ -0,0 +1,222 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using Microsoft.Win32.SafeHandles;
+using System.Threading;
+
+namespace MessageCodec
+{
+ /// <summary>
+ /// This is a wrapper around the native dll for MessageCodec calls
+ /// </summary>
+ public class MessageCodec_dll
+ {
+
+ [DllImport ("Kernel32.dll")]
+ extern static SafeFileHandle GetStdHandle(Int32 nStdHandle);
+
+ /// <summary>
+ /// Windows specific calls to load a library at runtime
+ /// </summary>
+
+ [DllImport ("kernel32.dll")]
+ internal static extern IntPtr LoadLibrary(String dllname);
+
+ /// <summary>
+ /// Windows specific call to get the address of a entry in a dll
+ /// </summary>
+
+ [DllImport ("kernel32.dll")]
+ internal static extern IntPtr GetProcAddress(IntPtr hModule, String procname);
+
+ /// The outcome of message decoding.
+ // !!! ORDER IS IMPORTANT AND THIS MUST align with the generic
+ // and UL (but not DL as the C# DLL is not intended to decode
+ // a DL message) portions of the C typedef DecodeResult_t.
+ public enum CSDecodeResult
+ {
+ DECODE_RESULT_FAILURE = 0, //!< Generic failed decode.
+ DECODE_RESULT_INPUT_TOO_SHORT, //!< Not enough input bytes.
+ DECODE_RESULT_OUTPUT_TOO_SHORT, //!< Not enough room in the
+ //! output.
+ DECODE_RESULT_UNKNOWN_MSG_ID, //!< Rogue message ID.
+ DECODE_RESULT_UL_MSG_BASE = 0x80, //!< From here on are the
+ //! uplink messages.
+ DECODE_RESULT_INIT_IND_UL_MSG = DECODE_RESULT_UL_MSG_BASE,
+ DECODE_RESULT_SERIAL_NUMBER_IND_UL_MSG,
+ DECODE_RESULT_SERIAL_NUMBER_CNF_UL_MSG,
+ DECODE_RESULT_VOLUME_IND_UL_MSG,
+ DECODE_RESULT_RSSI_IND_UL_MSG,
+ DECODE_RESULT_READING_INTERVAL_SET_CNF_UL_MSG,
+ DECODE_RESULT_READING_INTERVAL_GET_CNF_UL_MSG,
+ DECODE_RESULT_GPIO_SET_CNF_UL_MSG,
+ DECODE_RESULT_GPIO_GET_CNF_UL_MSG,
+ DECODE_RESULT_LED_SET_CNF_UL_MSG,
+ DECODE_RESULT_LED_GET_CNF_UL_MSG,
+ DECODE_RESULT_FLASH_SET_CNF_UL_MSG,
+ DECODE_RESULT_FLASH_GET_CNF_UL_MSG, // !!! If you add one here update
+ // the next line !!!
+ MAX_UL_REQ_MSG = DECODE_RESULT_FLASH_GET_CNF_UL_MSG,
+ MAX_NUM_DECODE_RESULTS //!< The maximum number of
+ //! decode results.
+ };
+
+ // uint32_t __cdecl maxDatagramSizeRaw (void);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public unsafe delegate UInt32 _maxDatagramSizeRaw ();
+ public _maxDatagramSizeRaw maxDatagramSizeRaw;
+
+ // uint32_t __cdecl gpioWaterPump (void);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public unsafe delegate UInt32 _gpioWaterPump();
+ public _gpioWaterPump gpioWaterPump;
+
+ // uint32_t __cdecl encodeRebootReqDlMsg (char * pBuffer,
+ // bool devModeOnNotOff);
+ [UnmanagedFunctionPointer (CallingConvention.Cdecl)]
+ public unsafe delegate UInt32 _encodeRebootReqDlMsg(byte* pBuffer,
+ Boolean devModeOnNotOff);
+ public _encodeRebootReqDlMsg encodeRebootReqDlMsg;
+
+ // uint32_t __cdecl encodeSerialNumberGetReqDlMsg (char * pBuffer);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public unsafe delegate UInt32 _encodeSerialNumberGetReqDlMsg(byte* pBuffer);
+ public _encodeSerialNumberGetReqDlMsg encodeSerialNumberGetReqDlMsg;
+
+ // uint32_t __cdecl encodeReadingIntervalSetReqDlMsg (char * pBuffer,
+ // UInt32 readingIntervalSeconds);
+ [UnmanagedFunctionPointer (CallingConvention.Cdecl)]
+ public unsafe delegate UInt32 _encodeReadingIntervalSetReqDlMsg(byte* pBuffer,
+ UInt32 readingIntervalSeconds);
+ public _encodeReadingIntervalSetReqDlMsg encodeReadingIntervalSetReqDlMsg;
+
+ // uint32_t __cdecl encodeReadingIntervalGetReqDlMsg (char * pBuffer);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public unsafe delegate UInt32 _encodeReadingIntervalGetReqDlMsg(byte* pBuffer);
+ public _encodeReadingIntervalGetReqDlMsg encodeReadingIntervalGetReqDlMsg;
+
+ // uint32_t __cdecl encodeGpioSetReqDlMsg (char * pBuffer,
+ // uint8_t gpio,
+ // bool inputNotOutput,
+ // bool onNotOff);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public unsafe delegate UInt32 _encodeGpioSetReqDlMsg(byte* pBuffer,
+ UInt32 gpio,
+ Boolean inputNotOutput,
+ Boolean onNotOff);
+ public _encodeGpioSetReqDlMsg encodeGpioSetReqDlMsg;
+
+ // uint32_t __cdecl encodeGpioGetReqDlMsg (char * pBuffer,
+ // uint8_t gpio);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public unsafe delegate UInt32 _encodeGpioGetReqDlMsg(byte* pBuffer,
+ UInt32 gpio);
+ public _encodeGpioGetReqDlMsg encodeGpioGetReqDlMsg;
+
+ // uint32_t __cdecl encodeLedSetReqDlMsg (char * pBuffer,
+ // bool onNotOff);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public unsafe delegate UInt32 _encodeLedSetReqDlMsg(byte* pBuffer,
+ Boolean onNotOff);
+ public _encodeLedSetReqDlMsg encodeLedSetReqDlMsg;
+
+ // uint32_t __cdecl encodeLedGetReqDlMsg (char * pBuffer);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public unsafe delegate UInt32 _encodeLedGetReqDlMsg(byte* pBuffer);
+ public _encodeLedGetReqDlMsg encodeLedGetReqDlMsg;
+
+ // uint32_t __cdecl encodeFlashSetReqDlMsg (char * pBuffer,
+ // bool onNotOff);
+ [UnmanagedFunctionPointer (CallingConvention.Cdecl)]
+ public unsafe delegate UInt32 _encodeFlashSetReqDlMsg(byte * pBuffer,
+ Boolean onNotOff);
+ public _encodeFlashSetReqDlMsg encodeFlashSetReqDlMsg;
+
+ // uint32_t __cdecl encodeFlashGetReqDlMsg (char * pBuffer);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public unsafe delegate UInt32 _encodeFlashGetReqDlMsg(byte* pBuffer);
+ public _encodeFlashGetReqDlMsg encodeFlashGetReqDlMsg;
+
+ // void __cdecl unpackGpioState (uint32_t value,
+ // uint32_t *pGpio,
+ // bool * pInputNotOutput,
+ // bool * pOnNotOff);
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public unsafe delegate void _unpackGpioState(UInt32 value,
+ UInt32* pGpio,
+ Boolean *pInputNotOutput,
+ Boolean *pOnNotOff);
+ public _unpackGpioState unpackGpioState;
+
+ // CsDecodeResult_t __cdecl decodeUlMsg (const char ** ppInBuffer,
+ // uint32_t sizeInBuffer,
+ // uint32_t * pContents);
+ [UnmanagedFunctionPointer (CallingConvention.Cdecl)]
+ public unsafe delegate CSDecodeResult _decodeUlMsg(byte** ppInBuffer,
+ UInt32 sizeInBuffer,
+ UInt32* pContents);
+ public _decodeUlMsg decodeUlMsg;
+
+ [UnmanagedFunctionPointer (CallingConvention.Cdecl)]
+ public delegate void guiPrintToConsoleCallback(StringBuilder data);
+
+ [UnmanagedFunctionPointer (CallingConvention.Cdecl)]
+ public delegate void _initDll([MarshalAs (UnmanagedType.FunctionPtr)] guiPrintToConsoleCallback callbackPointer);
+ public _initDll initDll;
+
+ void guiPrintToConsole(StringBuilder data)
+ {
+ if (onConsoleTrace != null)
+ {
+ onConsoleTrace (data.ToString ());
+ }
+ }
+
+ /// <summary>
+ /// Load the dll and do the bindings
+ /// </summary>
+ /// <param name="dllLocation">location of dll</param>
+ public void bindDll(string dllLocation)
+ {
+ IntPtr ptrDll = LoadLibrary (dllLocation);
+
+ if (ptrDll == IntPtr.Zero) throw new Exception (String.Format ("Cannot find {0}", dllLocation));
+
+ maxDatagramSizeRaw = (_maxDatagramSizeRaw)bindItem(ptrDll, "maxDatagramSizeRaw", typeof(_maxDatagramSizeRaw));
+ gpioWaterPump = (_gpioWaterPump)bindItem(ptrDll, "gpioWaterPump", typeof(_gpioWaterPump));
+ encodeRebootReqDlMsg = (_encodeRebootReqDlMsg)bindItem(ptrDll, "encodeRebootReqDlMsg", typeof(_encodeRebootReqDlMsg));
+ encodeSerialNumberGetReqDlMsg = (_encodeSerialNumberGetReqDlMsg)bindItem(ptrDll, "encodeSerialNumberGetReqDlMsg", typeof(_encodeSerialNumberGetReqDlMsg));
+ encodeReadingIntervalSetReqDlMsg = (_encodeReadingIntervalSetReqDlMsg)bindItem(ptrDll, "encodeReadingIntervalSetReqDlMsg", typeof(_encodeReadingIntervalSetReqDlMsg));
+ encodeReadingIntervalGetReqDlMsg = (_encodeReadingIntervalGetReqDlMsg)bindItem(ptrDll, "encodeReadingIntervalGetReqDlMsg", typeof(_encodeReadingIntervalGetReqDlMsg));
+ encodeGpioSetReqDlMsg = (_encodeGpioSetReqDlMsg)bindItem(ptrDll, "encodeGpioSetReqDlMsg", typeof(_encodeGpioSetReqDlMsg));
+ encodeGpioGetReqDlMsg = (_encodeGpioGetReqDlMsg)bindItem(ptrDll, "encodeGpioGetReqDlMsg", typeof(_encodeGpioGetReqDlMsg));
+ encodeLedSetReqDlMsg = (_encodeLedSetReqDlMsg)bindItem(ptrDll, "encodeLedSetReqDlMsg", typeof(_encodeLedSetReqDlMsg));
+ encodeLedGetReqDlMsg = (_encodeLedGetReqDlMsg)bindItem(ptrDll, "encodeLedGetReqDlMsg", typeof(_encodeLedGetReqDlMsg));
+ encodeFlashSetReqDlMsg = (_encodeFlashSetReqDlMsg)bindItem(ptrDll, "encodeFlashSetReqDlMsg", typeof(_encodeFlashSetReqDlMsg));
+ encodeFlashGetReqDlMsg = (_encodeFlashGetReqDlMsg)bindItem(ptrDll, "encodeFlashGetReqDlMsg", typeof(_encodeFlashGetReqDlMsg));
+ unpackGpioState = (_unpackGpioState)bindItem(ptrDll, "unpackGpioState", typeof(_unpackGpioState));
+ decodeUlMsg = (_decodeUlMsg)bindItem(ptrDll, "decodeUlMsg", typeof(_decodeUlMsg));
+ initDll = (_initDll)bindItem (ptrDll, "initDll", typeof (_initDll));
+ initDll (guiPrintToConsole);
+ }
+
+ public object bindItem(IntPtr ptrDll, string dllFuncName, Type type)
+ {
+ // Get pointer to dllexport function
+ IntPtr procaddr = GetProcAddress (ptrDll, dllFuncName);
+ if (procaddr == IntPtr.Zero) throw new Exception (String.Format ("Cannot find {0}", dllFuncName));
+
+ // Bind it to the function
+ Object result = Marshal.GetDelegateForFunctionPointer (procaddr, type);
+ if (result == null) throw new Exception (String.Format ("Cannot bind to {0}", dllFuncName));
+
+ return result;
+ }
+
+ public delegate void ConsoleTrace(string data);
+ public event ConsoleTrace onConsoleTrace;
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/IotMeterDllWrapper.hpp.txt Fri May 22 11:41:38 2015 +0000
@@ -0,0 +1,66 @@
+/* DLL wrapper for C027N/water-meter message handling functions
+ * for MWC demo 2015
+ *
+ * Copyright (C) u-blox Melbourn Ltd
+ * u-blox Melbourn Ltd, Melbourn, UK
+ *
+ * All rights reserved.
+ *
+ * This source file is the sole property of u-blox Melbourn Ltd.
+ * Reproduction or utilization of this source in whole or part is
+ * forbidden without the written consent of u-blox Melbourn Ltd.
+ */
+
+#ifndef IOT_METER_DLL_WRAPPER_HPP
+#define IOT_METER_DLL_WRAPPER_HPP
+
+/**
+ * @file iot_meter_dll_wrapper.h
+ * This file defines the encapsulation necessary to
+ * call the CPP Message Handling functions from C#.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ #define DLL __declspec(dllexport)
+
+ DLL uint32_t __cdecl maxDatagramSizeRaw (void);
+ DLL uint32_t __cdecl gpioWaterPump (void);
+
+ DLL uint32_t __cdecl encodeRebootReqDlMsg (char * pBuffer,
+ bool devModeOnNotOff);
+ DLL uint32_t __cdecl encodeSerialNumberGetReqDlMsg (char * pBuffer);
+ DLL uint32_t __cdecl encodeReadingIntervalSetReqDlMsg (char * pBuffer,
+ uint32_t readingIntervalSeconds);
+ DLL uint32_t __cdecl encodeReadingIntervalGetReqDlMsg (char * pBuffer);
+ DLL uint32_t __cdecl encodeGpioSetReqDlMsg (char * pBuffer,
+ uint8_t gpio,
+ bool inputNotOutput,
+ bool onNotOff);
+ DLL uint32_t __cdecl encodeGpioGetReqDlMsg (char * pBuffer,
+ uint32_t gpio);
+ DLL uint32_t __cdecl encodeLedSetReqDlMsg (char * pBuffer,
+ bool onNotOff);
+ DLL uint32_t __cdecl encodeLedGetReqDlMsg (char * pBuffer);
+ DLL uint32_t __cdecl encodeFlashSetReqDlMsg (char * pBuffer,
+ bool onNotOff);
+ DLL uint32_t __cdecl encodeFlashGetReqDlMsg (char * pBuffer);
+ DLL void __cdecl unpackGpioState (uint32_t value,
+ uint32_t *pGpio,
+ bool * pInputNotOutput,
+ bool * pOnNotOff);
+ DLL uint32_t __cdecl decodeUlMsg (const char ** ppInBuffer,
+ uint32_t sizeInBuffer,
+ uint32_t * pContents);
+
+ DLL void initDll (void (*guiPrintToConsole) (const char *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+// End Of File
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/IotMeterMsgCodec.cpp Fri May 22 11:41:38 2015 +0000
@@ -0,0 +1,728 @@
+/* C027N/water-meter interface for Water Meter Demo
+ *
+ * Copyright (C) u-blox Melbourn Ltd
+ * u-blox Melbourn Ltd, Melbourn, UK
+ *
+ * All rights reserved.
+ *
+ * This source file is the sole property of u-blox Melbourn Ltd.
+ * Reproduction or utilization of this source in whole or part is
+ * forbidden without the written consent of u-blox Melbourn Ltd.
+ */
+
+/**
+ * @file iot_meter_msg_handler.cpp
+ * This file implements the API to the C027N/water-meter device
+ * for the MWC demo 2015.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdarg.h> // for va_...
+#include <string.h> // for memcpy()
+#include <IotMeterApi.hpp>
+
+#ifdef DEBUG
+#define MESSAGE_CODEC_LOGMSG(...) MessageCodec::logMsg(__VA_ARGS__)
+#else
+#define MESSAGE_CODEC_LOGMSG(...)
+#endif
+
+// ----------------------------------------------------------------
+// GENERAL COMPILE-TIME CONSTANTS
+// ----------------------------------------------------------------
+
+/// The max size of a debug message (including terminator)
+#define MAX_DEBUG_MESSAGE_LEN 128
+
+// ----------------------------------------------------------------
+// PRIVATE VARIABLES
+// ----------------------------------------------------------------
+
+void (*MessageCodec::mp_guiPrintToConsole) (const char*) = NULL;
+
+// ----------------------------------------------------------------
+// ON-AIR MESSAGE IDs
+// ----------------------------------------------------------------
+
+/// The message IDs in the downlink direction (i.e. to the
+// C027/water-meter device). Note that 'over the air' these
+// are cast into an uint8_t.
+typedef enum MsgIdDlTag_t
+{
+ REBOOT_REQ_DL_MSG, //!< Reboot the C027N/water-meter
+ //! device.
+ SERIAL_NUMBER_GET_REQ_DL_MSG, //!< Get the serial number of the
+ //! water-meter.
+ READING_INTERVAL_SET_REQ_DL_MSG, //!< Set the rate at which readings
+ //! are returned by the C027N/water-meter
+ //! device.
+ READING_INTERVAL_GET_REQ_DL_MSG, //!< Get the rate at which readings
+ //! are returned by the C027N/water-meter
+ //! device.
+ GPIO_SET_REQ_DL_MSG, //!< Set the state of a GPIO on the
+ //! C027N board.
+ GPIO_GET_REQ_DL_MSG, //!< Get the state of a GPIO on the
+ //! C027N board.
+ LED_SET_REQ_DL_MSG, //!< Set the steady state of the red
+ //! LED on the C027 board.
+ LED_GET_REQ_DL_MSG, //!< Get the steady state of the red
+ //! LED on the C027 board.
+ FLASH_SET_REQ_DL_MSG, //!< Set the LED on the C027/water-meter
+ //! device to flash when a reading is
+ //! being sent (or not).
+ FLASH_GET_REQ_DL_MSG, //!< Get whether the LED on the C027/
+ //! flashes when a mesage is
+ //! being sent/received (or not).
+ MAX_NUM_DL_MSGS //!< The maximum number of downlink
+ //! messages.
+} MsgIdDl_t;
+
+/// The message IDs in the uplink direction (i.e. from the
+// C027N/water-meter device). Note that 'over the air' these are
+// cast into an uint8_t.
+typedef enum MsgIdUlTag_t
+{
+ INIT_IND_UL_MSG, //!< Power on of the C027N/water meter
+ //! device has completed.
+ SERIAL_NUMBER_IND_UL_MSG, //!< The serial number of the water meter.
+ VOLUME_IND_UL_MSG, //!< The current water meter reading.
+ RSSI_IND_UL_MSG, //!< The current RSSI reading from the
+ //! radio module.
+ SERIAL_NUMBER_GET_CNF_UL_MSG, //!< The serial number of the water-meter.
+ READING_INTERVAL_SET_CNF_UL_MSG, //!< The rate at which readings are
+ //! returned by the C027/water-meter device.
+ READING_INTERVAL_GET_CNF_UL_MSG, //!< The rate at which readings are
+ //! returned by the C027/water-meter device.
+ GPIO_SET_CNF_UL_MSG, //!< The state of a GPIO on the C027 board.
+ GPIO_GET_CNF_UL_MSG, //!< The state of a GPIO on the C027 board.
+ LED_SET_CNF_UL_MSG, //!< The steady state of the red LED on
+ //! the C027/water-meter device.
+ LED_GET_CNF_UL_MSG, //!< The steady state of the red LED on
+ //! the C027/water-meter device.
+ FLASH_SET_CNF_UL_MSG, //!< Whether the LED on the C027/water
+ //! meter device is set to flash when a
+ //! message is being sent/received (or not).
+ FLASH_GET_CNF_UL_MSG, //!< Whether the LED on the C027/water
+ //! meter device is set to flash when a
+ //! message is being sent/received (or not).
+ MAX_NUM_UL_MSGS //!< The maximum number of uplink messages.
+} MsgIdUl_t;
+
+// ----------------------------------------------------------------
+// GENERIC PRIVATE FUNCTIONS
+// ----------------------------------------------------------------
+
+/// Encode a boolean value, noting that this is contained
+// in a 32 bytes coded value.
+uint32_t MessageCodec::encodeBool (char * pBuffer, bool value)
+{
+ uint32_t numBytesEncoded = 4;
+
+ memset (pBuffer, 0, 4);
+ pBuffer[3] = value;
+
+ return numBytesEncoded;
+}
+
+/// Decode a boolean value, noting that this is contained
+// in a 32 bytes coded value.
+bool MessageCodec::decodeBool (const char ** ppBuffer)
+{
+ uint32_t value = 0;
+ bool boolValue = false;
+
+ value += ((**ppBuffer) & 0xFF) << 24;
+ (*ppBuffer)++;
+ value += ((**ppBuffer) & 0xFF) << 16;
+ (*ppBuffer)++;
+ value += ((**ppBuffer) & 0xFF) << 8;
+ (*ppBuffer)++;
+ value += ((**ppBuffer) & 0xFF) ;
+ (*ppBuffer)++;
+
+ if (value)
+ {
+ boolValue = true;
+ }
+
+ return boolValue;
+}
+
+/// Encode an int32
+uint32_t MessageCodec::encodeUint32 (char * pBuffer, uint32_t value)
+{
+ uint32_t numBytesEncoded = 4;
+
+ pBuffer[0] = 0xff & (value >> 24);
+ pBuffer[1] = 0xff & (value >> 16);
+ pBuffer[2] = 0xff & (value >> 8);
+ pBuffer[3] = 0xff & value;
+
+ return numBytesEncoded;
+}
+
+/// Decode an int32
+uint32_t MessageCodec::decodeUint32 (const char ** ppBuffer)
+{
+ uint32_t value = 0;
+
+ value += ((**ppBuffer) & 0xFF) << 24;
+ (*ppBuffer)++;
+ value += ((**ppBuffer) & 0xFF) << 16;
+ (*ppBuffer)++;
+ value += ((**ppBuffer) & 0xFF) << 8;
+ (*ppBuffer)++;
+ value += ((**ppBuffer) & 0xFF);
+ (*ppBuffer)++;
+
+ return value;
+}
+
+/// Encode GpioState
+uint32_t MessageCodec::encodeGpioState (char * pBuffer, GpioState_t *pGpioState)
+
+{
+ uint32_t numBytesEncoded = 0;
+
+ pBuffer[numBytesEncoded] = 0;
+ numBytesEncoded++;
+ pBuffer[numBytesEncoded] = pGpioState->gpio;
+ numBytesEncoded++;
+ pBuffer[numBytesEncoded] = pGpioState->inputNotOutput;
+ numBytesEncoded++;
+ pBuffer[numBytesEncoded] = pGpioState->onNotOff;
+ numBytesEncoded++;
+
+ return numBytesEncoded;
+}
+
+
+// Decode GpioState
+void MessageCodec::decodeGpioState (GpioState_t * pGpioState, const char ** ppBuffer)
+{
+ // Ignore the first byte as it's empty
+ (*ppBuffer)++;
+ pGpioState->gpio = (uint8_t) ((**ppBuffer) & 0xFF);
+ (*ppBuffer)++;
+ pGpioState->inputNotOutput = (bool) ((**ppBuffer) & 0xFF);
+ (*ppBuffer)++;
+ pGpioState->onNotOff = (bool) ((**ppBuffer) & 0xFF);
+ (*ppBuffer)++;
+}
+
+// ----------------------------------------------------------------
+// MESSAGE ENCODING FUNCTIONS
+// ----------------------------------------------------------------
+
+uint32_t MessageCodec::encodeInitIndUlMsg (char * pBuffer,
+ InitIndUlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding InitIndUlMsg, ID 0x%.2x, ", INIT_IND_UL_MSG);
+ pBuffer[numBytesEncoded] = INIT_IND_UL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeUint32 (&(pBuffer[numBytesEncoded]), (uint32_t) pMsg->wakeUpCode);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeRebootReqDlMsg (char * pBuffer,
+ RebootReqDlMsg_t *pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ pBuffer[numBytesEncoded] = REBOOT_REQ_DL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeBool (&(pBuffer[numBytesEncoded]), pMsg->devModeOnNotOff);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeSerialNumberIndUlMsg (char * pBuffer,
+ SerialNumberIndUlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding SerialNumberIndUlMsg, ID 0x%.2x, ", SERIAL_NUMBER_IND_UL_MSG);
+ pBuffer[numBytesEncoded] = SERIAL_NUMBER_IND_UL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeUint32 (&(pBuffer[numBytesEncoded]), pMsg->serialNumber);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeVolumeIndUlMsg (char * pBuffer,
+ VolumeIndUlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding VolumeIndUlMsg, ID 0x%.2x, ", VOLUME_IND_UL_MSG);
+ pBuffer[numBytesEncoded] = VOLUME_IND_UL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeUint32 (&(pBuffer[numBytesEncoded]), pMsg->volumeLitres);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeRssiIndUlMsg (char * pBuffer,
+ RssiIndUlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding RssiIndUlMsg, ID 0x%.2x, ", RSSI_IND_UL_MSG);
+ pBuffer[numBytesEncoded] = RSSI_IND_UL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeUint32 (&(pBuffer[numBytesEncoded]), pMsg->rssi);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeSerialNumberGetReqDlMsg (char * pBuffer)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding SerialNumberGetReqDlMsg, ID 0x%.2x, ", SERIAL_NUMBER_GET_REQ_DL_MSG);
+ pBuffer[numBytesEncoded] = SERIAL_NUMBER_GET_REQ_DL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeBool (&(pBuffer[numBytesEncoded]), 0); // Encode packing as all
+ // messages must have a body
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeSerialNumberGetCnfUlMsg (char * pBuffer,
+ SerialNumberGetCnfUlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding SerialNumberGetCnfUlMsg, ID 0x%.2x, ", SERIAL_NUMBER_GET_CNF_UL_MSG);
+ pBuffer[numBytesEncoded] = SERIAL_NUMBER_GET_CNF_UL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeUint32 (&(pBuffer[numBytesEncoded]), pMsg->serialNumber);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeReadingIntervalSetReqDlMsg (char * pBuffer,
+ ReadingIntervalSetReqDlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding ReadingIntervalSetReqDlMsg, ID 0x%.2x, ", READING_INTERVAL_SET_REQ_DL_MSG);
+ pBuffer[numBytesEncoded] = READING_INTERVAL_SET_REQ_DL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeUint32 (&(pBuffer[numBytesEncoded]), pMsg->readingIntervalSeconds);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeReadingIntervalSetCnfUlMsg (char * pBuffer,
+ ReadingIntervalSetCnfUlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding ReadingIntervalSetCnfUlMsg, ID 0x%.2x, ", READING_INTERVAL_SET_CNF_UL_MSG);
+ pBuffer[numBytesEncoded] = READING_INTERVAL_SET_CNF_UL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeUint32 (&(pBuffer[numBytesEncoded]), pMsg->readingIntervalSeconds);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeReadingIntervalGetReqDlMsg (char * pBuffer)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding ReadingIntervalGetReqDlMsg, ID 0x%.2x, ", READING_INTERVAL_GET_REQ_DL_MSG);
+ pBuffer[numBytesEncoded] = READING_INTERVAL_GET_REQ_DL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeBool (&(pBuffer[numBytesEncoded]), 0); // Encode packing as all
+ // messages must have a body
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeReadingIntervalGetCnfUlMsg (char * pBuffer,
+ ReadingIntervalGetCnfUlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding ReadingIntervalGetCnfUlMsg, ID 0x%.2x, ", READING_INTERVAL_GET_CNF_UL_MSG);
+ pBuffer[numBytesEncoded] = READING_INTERVAL_GET_CNF_UL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeUint32 (&(pBuffer[numBytesEncoded]), pMsg->readingIntervalSeconds);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeGpioSetReqDlMsg (char * pBuffer,
+ GpioSetReqDlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding GpioSetReqDlMsg, ID 0x%.2x, ", GPIO_SET_REQ_DL_MSG);
+ pBuffer[numBytesEncoded] = GPIO_SET_REQ_DL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeGpioState (&(pBuffer[numBytesEncoded]), &(pMsg->gpioState));
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeGpioSetCnfUlMsg (char * pBuffer,
+ GpioSetCnfUlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding GpioSetCnfUlMsg, ID 0x%.2x, ", GPIO_SET_CNF_UL_MSG);
+ pBuffer[numBytesEncoded] = GPIO_SET_CNF_UL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeGpioState (&(pBuffer[numBytesEncoded]), &(pMsg->gpioState));
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeGpioGetReqDlMsg (char * pBuffer,
+ GpioGetReqDlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding GpioGetReqDlMsg, ID 0x%.2x, ", LED_GET_REQ_DL_MSG);
+ pBuffer[numBytesEncoded] = GPIO_GET_REQ_DL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeUint32 (&(pBuffer[numBytesEncoded]), (uint32_t) pMsg->gpio);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeGpioGetCnfUlMsg (char * pBuffer,
+ GpioGetCnfUlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding GpioGetCnfUlMsg, ID 0x%.2x, ", LED_GET_CNF_UL_MSG);
+ pBuffer[numBytesEncoded] = GPIO_GET_CNF_UL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeGpioState (&(pBuffer[numBytesEncoded]), &(pMsg->gpioState));
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeLedSetReqDlMsg (char * pBuffer,
+ LedSetReqDlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding LedSetReqDlMsg, ID 0x%.2x, ", LED_SET_REQ_DL_MSG);
+ pBuffer[numBytesEncoded] = LED_SET_REQ_DL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeBool (&(pBuffer[numBytesEncoded]), pMsg->onNotOff);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeLedSetCnfUlMsg (char * pBuffer,
+ LedSetCnfUlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding LedSetCnfUlMsg, ID 0x%.2x, ", LED_SET_CNF_UL_MSG);
+ pBuffer[numBytesEncoded] = LED_SET_CNF_UL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeBool (&(pBuffer[numBytesEncoded]), pMsg->onNotOff);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeLedGetReqDlMsg (char * pBuffer)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding LedGetReqDlMsg, ID 0x%.2x, ", LED_GET_REQ_DL_MSG);
+ pBuffer[numBytesEncoded] = LED_GET_REQ_DL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeBool (&(pBuffer[numBytesEncoded]), 0); // Encode packing as all
+ // messages must have a body
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeLedGetCnfUlMsg (char * pBuffer,
+ LedGetCnfUlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding LedGetCnfUlMsg, ID 0x%.2x, ", LED_GET_CNF_UL_MSG);
+ pBuffer[numBytesEncoded] = LED_GET_CNF_UL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeBool (&(pBuffer[numBytesEncoded]), pMsg->onNotOff);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeFlashSetReqDlMsg (char * pBuffer,
+ FlashSetReqDlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding FlashSetReqDlMsg, ID 0x%.2x, ", FLASH_SET_REQ_DL_MSG);
+ pBuffer[numBytesEncoded] = FLASH_SET_REQ_DL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeBool (&(pBuffer[numBytesEncoded]), pMsg->onNotOff);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeFlashSetCnfUlMsg (char * pBuffer,
+ FlashSetCnfUlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding FlashSetCnfUlMs, ID 0x%.2x, ", FLASH_SET_CNF_UL_MSG);
+ pBuffer[numBytesEncoded] = FLASH_SET_CNF_UL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeBool (&(pBuffer[numBytesEncoded]), pMsg->onNotOff);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeFlashGetReqDlMsg (char * pBuffer)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding FlashGetReqDlMsg, ID 0x%.2x, ", FLASH_GET_REQ_DL_MSG);
+ pBuffer[numBytesEncoded] = FLASH_GET_REQ_DL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeBool (&(pBuffer[numBytesEncoded]), 0); // Encode packing as all
+ // messages must have a body
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+uint32_t MessageCodec::encodeFlashGetCnfUlMsg (char * pBuffer,
+ FlashGetCnfUlMsg_t * pMsg)
+{
+ uint32_t numBytesEncoded = 0;
+
+ MESSAGE_CODEC_LOGMSG ("Encoding FlashGetCnfUlMs, ID 0x%.2x, ", FLASH_GET_CNF_UL_MSG);
+ pBuffer[numBytesEncoded] = FLASH_GET_CNF_UL_MSG;
+ numBytesEncoded++;
+ numBytesEncoded += encodeBool (&(pBuffer[numBytesEncoded]), pMsg->onNotOff);
+ MESSAGE_CODEC_LOGMSG ("%d bytes encoded.\n", numBytesEncoded);
+
+ return numBytesEncoded;
+}
+
+// ----------------------------------------------------------------
+// MESSAGE DECODING FUNCTIONS
+// ----------------------------------------------------------------
+MessageCodec::DecodeResult_t MessageCodec::decodeDlMsg (const char ** ppInBuffer,
+ uint32_t sizeInBuffer,
+ DlMsgUnion_t * pOutBuffer)
+{
+ MsgIdDl_t msgId;
+ DecodeResult_t decodeResult = DECODE_RESULT_FAILURE;
+
+ if (sizeInBuffer < MAX_MESSAGE_SIZE)
+ {
+ decodeResult = DECODE_RESULT_INPUT_TOO_SHORT;
+ }
+ else
+ {
+ decodeResult = DECODE_RESULT_UNKNOWN_MSG_ID;
+ // First byte should be a valid DL message ID
+ msgId = (MsgIdDl_t) **ppInBuffer;
+ (*ppInBuffer)++;
+ if (msgId < MAX_NUM_DL_MSGS)
+ {
+ switch (msgId)
+ {
+ case REBOOT_REQ_DL_MSG:
+ decodeResult = DECODE_RESULT_REBOOT_REQ_DL_MSG;
+ pOutBuffer->rebootReqDlMsg.devModeOnNotOff = decodeBool (ppInBuffer);
+ break;
+ case SERIAL_NUMBER_GET_REQ_DL_MSG:
+ decodeResult = DECODE_RESULT_SERIAL_NUMBER_GET_REQ_DL_MSG;
+ decodeUint32 (ppInBuffer); // Must decode the rest of the dummy message;
+ break;
+ case READING_INTERVAL_SET_REQ_DL_MSG:
+ decodeResult = DECODE_RESULT_READING_INTERVAL_SET_REQ_DL_MSG;
+ pOutBuffer->readingIntervalSetReqDlMsg.readingIntervalSeconds = decodeUint32 (ppInBuffer);
+ break;
+ case READING_INTERVAL_GET_REQ_DL_MSG:
+ decodeResult = DECODE_RESULT_READING_INTERVAL_GET_REQ_DL_MSG;
+ decodeUint32 (ppInBuffer); // Must decode the rest of the dummy message;
+ break;
+ case GPIO_SET_REQ_DL_MSG:
+ decodeResult = DECODE_RESULT_GPIO_SET_REQ_DL_MSG;
+ decodeGpioState (&(pOutBuffer->gpioSetReqDlMsg.gpioState), ppInBuffer);
+ break;
+ case GPIO_GET_REQ_DL_MSG:
+ decodeResult = DECODE_RESULT_GPIO_GET_REQ_DL_MSG;
+ pOutBuffer->gpioGetReqDlMsg.gpio = (uint8_t) decodeUint32 (ppInBuffer);
+ break;
+ case LED_SET_REQ_DL_MSG:
+ decodeResult = DECODE_RESULT_LED_SET_REQ_DL_MSG;
+ pOutBuffer->ledSetReqDlMsg.onNotOff = decodeBool (ppInBuffer);
+ break;
+ case LED_GET_REQ_DL_MSG:
+ decodeResult = DECODE_RESULT_LED_GET_REQ_DL_MSG;
+ decodeUint32 (ppInBuffer); // Must decode the rest of the dummy message;
+ break;
+ case FLASH_SET_REQ_DL_MSG:
+ decodeResult = DECODE_RESULT_FLASH_SET_REQ_DL_MSG;
+ pOutBuffer->flashSetReqDlMsg.onNotOff = decodeBool (ppInBuffer);
+ break;
+ case FLASH_GET_REQ_DL_MSG:
+ decodeResult = DECODE_RESULT_FLASH_GET_REQ_DL_MSG;
+ decodeUint32 (ppInBuffer); // Must decode the rest of the dummy message;
+ break;
+ default:
+ // The decodeResult will be left as Unknown message
+ break;
+ }
+ }
+ }
+
+ return decodeResult;
+}
+
+MessageCodec::DecodeResult_t MessageCodec::decodeUlMsg (const char ** ppInBuffer,
+ uint32_t sizeInBuffer,
+ UlMsgUnion_t * pOutBuffer)
+{
+ MsgIdUl_t msgId;
+ DecodeResult_t decodeResult = DECODE_RESULT_FAILURE;
+
+ if (sizeInBuffer < MAX_MESSAGE_SIZE)
+ {
+ decodeResult = DECODE_RESULT_INPUT_TOO_SHORT;
+ }
+ else
+ {
+ decodeResult = DECODE_RESULT_UNKNOWN_MSG_ID;
+ // First byte should be a valid UL message ID
+ msgId = (MsgIdUl_t) **ppInBuffer;
+ (*ppInBuffer)++;
+ if (msgId < MAX_NUM_UL_MSGS)
+ {
+ switch (msgId)
+ {
+ case INIT_IND_UL_MSG:
+ decodeResult = DECODE_RESULT_INIT_IND_UL_MSG;
+ pOutBuffer->initIndUlMsg.wakeUpCode = (WakeUpCode_t) decodeUint32 (ppInBuffer);
+ break;
+ case SERIAL_NUMBER_IND_UL_MSG:
+ decodeResult = DECODE_RESULT_SERIAL_NUMBER_IND_UL_MSG;
+ pOutBuffer->serialNumberIndUlMsg.serialNumber = decodeUint32 (ppInBuffer);
+ break;
+ case VOLUME_IND_UL_MSG:
+ decodeResult = DECODE_RESULT_VOLUME_IND_UL_MSG;
+ pOutBuffer->volumeIndUlMsg.volumeLitres = decodeUint32 (ppInBuffer);
+ break;
+ case RSSI_IND_UL_MSG:
+ decodeResult = DECODE_RESULT_RSSI_IND_UL_MSG;
+ pOutBuffer->rssiIndUlMsg.rssi = decodeUint32 (ppInBuffer);
+ break;
+ case SERIAL_NUMBER_GET_CNF_UL_MSG:
+ decodeResult = DECODE_RESULT_SERIAL_NUMBER_GET_CNF_UL_MSG;
+ pOutBuffer->serialNumberCnfUlMsg.serialNumber = decodeUint32 (ppInBuffer);
+ break;
+ case READING_INTERVAL_SET_CNF_UL_MSG:
+ decodeResult = DECODE_RESULT_READING_INTERVAL_SET_CNF_UL_MSG;
+ pOutBuffer->readingIntervalSetCnfUlMsg.readingIntervalSeconds = decodeUint32 (ppInBuffer);
+ break;
+ case READING_INTERVAL_GET_CNF_UL_MSG:
+ decodeResult = DECODE_RESULT_READING_INTERVAL_GET_CNF_UL_MSG;
+ pOutBuffer->readingIntervalGetCnfUlMsg.readingIntervalSeconds = decodeUint32 (ppInBuffer);
+ break;
+ case GPIO_SET_CNF_UL_MSG:
+ decodeResult = DECODE_RESULT_GPIO_SET_CNF_UL_MSG;
+ pOutBuffer->gpioSetCnfUlMsg = decodeUint32 (ppInBuffer); // Decode as an int32 for later unpacking
+ break;
+ case GPIO_GET_CNF_UL_MSG:
+ decodeResult = DECODE_RESULT_GPIO_GET_CNF_UL_MSG;
+ pOutBuffer->gpioGetCnfUlMsg = decodeUint32 (ppInBuffer); // Decode as an int32 for later unpacking
+ break;
+ case LED_SET_CNF_UL_MSG:
+ decodeResult = DECODE_RESULT_LED_SET_CNF_UL_MSG;
+ pOutBuffer->ledSetCnfUlMsg.onNotOff = decodeBool (ppInBuffer);
+ break;
+ case LED_GET_CNF_UL_MSG:
+ decodeResult = DECODE_RESULT_LED_GET_CNF_UL_MSG;
+ pOutBuffer->ledGetCnfUlMsg.onNotOff = decodeBool (ppInBuffer);
+ break;
+ case FLASH_SET_CNF_UL_MSG:
+ decodeResult = DECODE_RESULT_FLASH_SET_CNF_UL_MSG;
+ pOutBuffer->flashSetCnfUlMsg.onNotOff = decodeBool (ppInBuffer);
+ break;
+ case FLASH_GET_CNF_UL_MSG:
+ decodeResult = DECODE_RESULT_FLASH_GET_CNF_UL_MSG;
+ pOutBuffer->flashGetCnfUlMsg.onNotOff = decodeBool (ppInBuffer);
+ break;
+ default:
+ // The decodeResult will be left as Unknown message
+ break;
+ }
+ }
+ }
+
+ return decodeResult;
+}
+
+// ----------------------------------------------------------------
+// MISC FUNCTIONS
+// ----------------------------------------------------------------
+
+// Log debug messages
+void MessageCodec::logMsg (const char * pFormat, ...)
+{
+ char buffer[MAX_DEBUG_MESSAGE_LEN];
+
+ va_list args;
+ va_start (args, pFormat);
+ vsnprintf (buffer, sizeof (buffer), pFormat, args);
+ va_end (args);
+#ifdef WIN32
+ if (MessageCodec::mp_guiPrintToConsole)
+ {
+ (*MessageCodec::mp_guiPrintToConsole) (buffer);
+ }
+#else
+ // Must be on ARM
+ printf (buffer);
+#endif
+}
+
+void MessageCodec::initDll (void (*guiPrintToConsole) (const char *))
+{
+#ifdef WIN32
+ mp_guiPrintToConsole = guiPrintToConsole;
+ // This is the signal to the GUI that we're done with initialisation
+ logMsg ("MessageCodec::ready.\n");
+#endif
+}
+
+// End Of File
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/IotMeterMsgs.hpp Fri May 22 11:41:38 2015 +0000
@@ -0,0 +1,281 @@
+/* C027N/water-meter message definitions for Water Meter Demo
+ *
+ * Copyright (C) u-blox Melbourn Ltd
+ * u-blox Melbourn Ltd, Melbourn, UK
+ *
+ * All rights reserved.
+ *
+ * This source file is the sole property of u-blox Melbourn Ltd.
+ * Reproduction or utilization of this source in whole or part is
+ * forbidden without the written consent of u-blox Melbourn Ltd.
+ */
+
+#ifndef IOT_METER_MSGS_HPP
+#define IOT_METER_MSGS_HPP
+
+/**
+ * @file iot_meter_msgs.h
+ * This file defines the messages sent between the
+ * C027N/water-meter device and a PC app for the MWC demo
+ * 2015.
+ *
+ * The message format is as follows:
+ *
+ * uint8_t id
+ * uint32_t value
+ *
+ * The IDs are defined in an enumerated type and there are
+ * separately defined ID sets for the downlink and uplink
+ * directions (i.e. they may overlap). When transmitted the
+ * messages are packed such that the 32-bit content byte
+ * immediately follows the 8-bit ID with no packing, resulting
+ * in a fixed message length of 5 bytes. Multiple fixed
+ * length messages may be packed into a datagram, hence it can
+ * be assumed that a datagram of length < 10 bytes contains
+ * one message, a datagram of length < 15 bytes contains two
+ * messages, etc.
+ *
+ * Boolean values are expressed as uint32_t zero (false) or
+ * uint32_t one (true). For multibyte values the highest
+ * value bytes is stored first, so a message with ID 0xa5 and
+ * value 0x12345678 would be stored in the datagram as:
+ *
+ * Location: 0 1 2 3 4
+ * Contents: a512345678
+ *
+ * There are some messages (Gpio setters for instance) which
+ * encode more than a single value into the value field. See
+ * the individual encode/decode functions for how these values
+ * are packed.
+ */
+
+// ----------------------------------------------------------------
+// GENERAL COMPILE-TIME CONSTANTS
+// ----------------------------------------------------------------
+
+/// The maximum length of a single messages in bytes
+#define MAX_MESSAGE_SIZE 5
+
+/// The default meter reading interval.
+#define DEFAULT_READING_INTERVAL_SECONDS 10
+
+
+// ----------------------------------------------------------------
+// TYPES
+// ----------------------------------------------------------------
+
+/// The wake up code sent from the device
+typedef enum WakeUpCodeTag_t
+{
+ WAKE_UP_CODE_OK, //!< A good wake-up, no problems.
+ WAKE_UP_CODE_WATER_METER_PROBLEM, //!< Wake-up after assert due to
+ //! problems reading the water meter.
+ WAKE_UP_CODE_AT_COMMAND_PROBLEM, //!< Wake-up after assert due to
+ //! problems with AT commands.
+ WAKE_UP_CODE_NETWORK_SEND_PROBLEM, //!< Wake-up after assert due to
+ //! problems sending to the network.
+ WAKE_UP_CODE_MEMORY_ALLOC_PROBLEM, //!< Wake-up after assert due to
+ //! memory allocation issues.
+ WAKE_UP_CODE_PROTOCOL_PROBLEM, //!< Wake-up after assert due to
+ //! a protocol problem.
+ WAKE_UP_CODE_GENERIC_FAILURE, //!< Wake-up after a generic failure.
+ WAKE_UP_CODE_REBOOT, //!< Waking up after a commanded reboot.
+ MAX_NUM_WAKE_UP_CODES //!< The maximum number of
+ //! decode results.
+} WakeUpCode_t;
+
+// ----------------------------------------------------------------
+// MESSAGE BODIES
+// ----------------------------------------------------------------
+
+/// InitIndUlMsg_t. Sent at power-on of the device. Indicates that the
+// device has been initialised.
+// After transmission of this message meter readings will be returned
+// at the requested rate (or DEFAULT_READING_INTERVAL_SECONDS if no
+// InitReqDlMsg_t has been received by the device).
+typedef struct InitIndUlMsgTag_t
+{
+ WakeUpCode_t wakeUpCode; //!< A wake-up code from the device.
+} InitIndUlMsg_t;
+
+/// RebootReqDlMsg_t. Sent to reboot the device and set the development
+// mode on or off. By default development mode is OFF.
+typedef struct RebootReqDlMsgTag_t
+{
+ bool devModeOnNotOff; //!< If true development mode is on, else it is off.
+} RebootReqDlMsg_t;
+
+/// SerialNumberGetCnfUlMsg_t. Sent in response to a SerialNumberGetReqDlMsg_t (which
+// is empty and so not represented here).
+typedef struct SerialNumberGetCnfUlMsgTag_t
+{
+ uint32_t serialNumber; //!< The serial number of the meter.
+} SerialNumberGetCnfUlMsg_t;
+
+/// SerialNumberIndUlMsg_t. Sent at power-on of the device and in response to
+// an InitReqDlMsg_t. Indicates the serial number of the device.
+typedef struct SerialNumberIndUlMsgTag_t
+{
+ uint32_t serialNumber; //!< The serial number of the meter.
+} SerialNumberIndUlMsg_t;
+
+/// VolumeIndUlMsg_t. The current meter reading.
+typedef struct VolumeIndUlMsgTag_t
+{
+ uint32_t volumeLitres;
+} VolumeIndUlMsg_t;
+
+/// RssiIndUlMsg_t. The current RSSI reading.
+typedef struct RssiIndUlMsgTag_t
+{
+ uint32_t rssi; //!< The RSSI reading in arbitrary units, range 0 to 255.
+} RssiIndUlMsg_t;
+
+/// ReadingIntervalSetReqDlMsg_t. Set the meter reading interval.
+typedef struct ReadingIntervalSetReqDlMsgTag_t
+{
+ uint32_t readingIntervalSeconds; //!< The interval at which the device
+ //! should send readings.
+} ReadingIntervalSetReqDlMsg_t;
+
+/// ReadingIntervalSetCnfUlMsg_t. Sent in response to a
+// ReadingIntervalSetReqDlMsg_t.
+// After transmission of this message meter readings will be returned
+// at the requested rate (or DEFAULT_READING_INTERVAL_SECONDS if no
+// command setting it otherwise has been received by the device).
+typedef struct ReadingIntervalSetCnfUlMsgTag_t
+{
+ uint32_t readingIntervalSeconds; //!< The interval at which readings are sent.
+} ReadingIntervalSetCnfUlMsg_t;
+
+/// ReadingIntervalGetCnfUlMsg_t. Sent in response to a
+// ReadingIntervalGetReqDlMsg_t (which is empty and so not represented
+// here).
+// After transmission of this message meter readings will be returned
+// at the requested rate (or DEFAULT_READING_INTERVAL_SECONDS if no
+// command setting it otherwise has been received by the device).
+typedef struct ReadingIntervalGetCnfUlMsgTag_t
+{
+ uint32_t readingIntervalSeconds; //!< The interval at which readings are sent.
+} ReadingIntervalGetCnfUlMsg_t;
+
+/// GpioState_t. Data concerning how a GPIO is set up.
+typedef struct GpioStateTag_t
+{
+ uint8_t gpio; //!< The GPIO in question: 0 for D0, 1 for D1, etc.
+ bool inputNotOutput; //!< true if this is an input, else it is an output.
+ bool onNotOff; //!< If the GPIO is an output then this gives its state.
+ //! If the GPIO is an input this is not set.
+} GpioState_t;
+
+/// GpioSetReqDlMsg_t. Set the state of a GPIO on the C027N board.
+typedef struct GpioSetReqDlMsgTag_t
+{
+ GpioState_t gpioState; //!< The state of the GPIO.
+} GpioSetReqDlMsg_t;
+
+/// GpioSetCnfUlMsg_t. Response to GpioSetReqDlMsg_t.
+typedef struct GpioSetCnfUlMsgTag_t
+{
+ GpioState_t gpioState; //!< The state of the GPIO.
+} GpioSetCnfUlMsg_t;
+
+/// GpioGetReqDlMsg_t. Gets the state of a GPIO on the C027N board.
+typedef struct GpioGetReqDlMsgTag_t
+{
+ uint8_t gpio; //!< The GPIO to get.
+} GpioGetReqDlMsg_t;
+
+/// GpioGetCnfUlMsg_t. Sent in response to a GpioGetReqDlMsg.
+typedef struct GpioGetCnfUlMsgTag_t
+{
+ GpioState_t gpioState; //!< The state of the GPIO.
+} GpioGetCnfUlMsg_t;
+
+/// LedSetReqDlMsg_t. Set the steady state of the red LED on
+// the C027N board.
+typedef struct LedSetReqDlMsgTag_t
+{
+ bool onNotOff; //!< Make the steady state ON if true, otherwise OFF.
+ //! OFF is the default state.
+} LedSetReqDlMsg_t;
+
+/// LedSetCnfUlMsg_t. Response to LedSetReqDlMsg_t.
+typedef struct LedSetCnfUlMsgTag_t
+{
+ bool onNotOff; //!< The LED is steady-state ON if true, otherwise
+ //! OFF.
+} LedSetCnfUlMsg_t;
+
+/// LedGetCnfUlMsg_t. Sent in response to an LedGetReqDlMsg
+// (which is an empty ID and so not represented here).
+typedef struct LedGetCnfUlMsgTag_t
+{
+ bool onNotOff; //!< The steady state is ON if true, otherwise OFF.
+} LedGetCnfUlMsg_t;
+
+/// FlashSetReqDlMsg_t. Set the red LED to flash when a reading is
+// being sent (or not). If LedSetReqDlMsg_t has been set to ON the
+// flash will be 'inverted', i.e. the red LED will blink off when a
+// reading is being transmitted instead.
+typedef struct FlashSetReqDlMsgTag_t
+{
+ bool onNotOff; //!< If true then the red LED will flash when a
+ //! reading is being sent, else it will remain in
+ //! steady state. The default is to flash when a
+ //! reading is being sent.
+} FlashSetReqDlMsg_t;
+
+/**
+ * FlashSetCnfUlMsg_t. Response to FlashSetReqDlMsg_t.
+ */
+typedef struct FlashSetCnfUlMsgTag_t
+{
+ bool onNotOff; //!< If true then the red LED flashes when a
+ //! reading is being sent, else it will remain in
+ //! steady state.
+} FlashSetCnfUlMsg_t;
+
+/// FlashGetCnfUlMsg_t. Sent in response to a FlashGetReqDlMsg
+// (which is an empty ID and so not represented here).
+typedef struct FlashGetCnfUlMsgTag_t
+{
+ bool onNotOff; //!< The steady state is ON if true, otherwise OFF.
+} FlashGetCnfUlMsg_t;
+
+// ----------------------------------------------------------------
+// MESSAGE UNIONS
+// ----------------------------------------------------------------
+
+/// Union of all downlink messages.
+typedef union DlMsgUnionTag_t
+{
+ RebootReqDlMsg_t rebootReqDlMsg;
+ ReadingIntervalSetReqDlMsg_t readingIntervalSetReqDlMsg;
+ GpioSetReqDlMsg_t gpioSetReqDlMsg;
+ GpioGetReqDlMsg_t gpioGetReqDlMsg;
+ LedSetReqDlMsg_t ledSetReqDlMsg;
+ FlashSetReqDlMsg_t flashSetReqDlMsg;
+} DlMsgUnion_t;
+
+/// Union of all uplink messages.
+typedef union UlMsgUnionTag_t
+{
+ InitIndUlMsg_t initIndUlMsg;
+ VolumeIndUlMsg_t volumeIndUlMsg;
+ RssiIndUlMsg_t rssiIndUlMsg;
+ SerialNumberIndUlMsg_t serialNumberIndUlMsg;
+ SerialNumberGetCnfUlMsg_t serialNumberCnfUlMsg;
+ ReadingIntervalSetCnfUlMsg_t readingIntervalSetCnfUlMsg;
+ ReadingIntervalGetCnfUlMsg_t readingIntervalGetCnfUlMsg;
+ uint32_t gpioSetCnfUlMsg; // These are left packed inside a uint32_t so that
+ uint32_t gpioGetCnfUlMsg; // they can be passed to C# without a struct.
+ LedSetCnfUlMsg_t ledSetCnfUlMsg;
+ LedGetCnfUlMsg_t ledGetCnfUlMsg;
+ FlashSetCnfUlMsg_t flashSetCnfUlMsg;
+ FlashGetCnfUlMsg_t flashGetCnfUlMsg;
+} UlMsgUnion_t;
+
+#endif
+
+// End Of File