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.

IotMeterDllWrapper.cs.txt

Committer:
RobMeades
Date:
2015-05-22
Revision:
0:5c46cb3be899

File content as of revision 0:5c46cb3be899:

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;
    }
}