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
diff -r 000000000000 -r 5c46cb3be899 IotMeterApi.hpp --- /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
diff -r 000000000000 -r 5c46cb3be899 IotMeterDllWrapper.cpp.txt --- /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
diff -r 000000000000 -r 5c46cb3be899 IotMeterDllWrapper.cs.txt --- /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
diff -r 000000000000 -r 5c46cb3be899 IotMeterDllWrapper.hpp.txt --- /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
diff -r 000000000000 -r 5c46cb3be899 IotMeterMsgCodec.cpp --- /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
diff -r 000000000000 -r 5c46cb3be899 IotMeterMsgs.hpp --- /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