This is a class which contains function to interface with the MLX75320
Diff: MLX_BaseSPI.c
- Revision:
- 0:dfe498e03679
diff -r 000000000000 -r dfe498e03679 MLX_BaseSPI.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MLX_BaseSPI.c Thu Feb 25 08:02:11 2016 +0000 @@ -0,0 +1,1529 @@ +// ***** *********************************************************************** +/*! +Module: Melexis Base SPI + +Platform: Win32 - Win64 - embedded + +\file MLX_BaseSPI.h + +\brief Base control module the ASIC SPI, Melexis protocol. + +\author Jean-F. Bernier + +\since 2015-04-23 +*/ +// *************************************************************************** + +//***************************************************************************** +//*************** Header includes ********************************************* +//***************************************************************************** +//#include "Tools.h" +#include <string.h> +#include "MLX_BaseSPI.h" + + +// Bit field widths in a packet +#define WID_TYPE 4 /// Packet type +#define WID_SIZE 8 /// Size +#define WID_SEQ 4 /// Sequence number +#define WID_DATA 16 /// Additional data +#define WID_ADDR 16 /// Address +#define WID_RES_DATA 32 /// Response data +#define WID_ISERR 1 /// Is error or not +#define WID_ERROR 15 /// Error qualifier + +// Bit position offsets in a short packet +#ifdef RIGHT_TO_LEFT + #define OFF_TYPE (MLX_SHORT_SZ - WID_TYPE) + #define OFF_SIZE (OFF_TYPE - WID_SIZE) + #define OFF_SEQ (OFF_SIZE - WID_SEQ) + #define OFF_ADDR (OFF_SEQ - WID_ADDR) + #define OFF_DATA (OFF_ADDR - WID_DATA) + #define OFF_RES_DATA (OFF_SEQ - WID_RES_DATA) + #define OFF_ISERR (MLX_SHORT_SZ - 16 - WID_ISERR) + #define OFF_ERROR (OFF_ISERR - WID_ERROR) + + #define BIT_ORDER 0 +#else + #define OFF_TYPE (WID_TYPE - 1) + #define OFF_SIZE (OFF_TYPE + WID_SIZE) + #define OFF_SEQ (OFF_SIZE + WID_SEQ) + #define OFF_ADDR (OFF_SEQ + WID_ADDR) + #define OFF_DATA (OFF_ADDR + WID_DATA) + #define OFF_RES_DATA (OFF_SEQ + WID_RES_DATA) + #define OFF_ISERR 16 + #define OFF_ERROR (OFF_ISERR+ WID_ERROR) + + #define BIT_ORDER 1 +#endif + +//***************************************************************************** +//*************** Private Function Declarations ******************************* +//***************************************************************************** +static uint16 CRC16_Compute ( const uint8 *data, uint16 n); +static BOOL CRC16_IsValid ( const uint8 *data, uint n, uint nbCrc); +static void FillCRC_short ( PACK_SHORT *pack); +static void FillCRC_long1 ( PACK_LONG1 *pack); +static void FillCRC_long2 ( PACK_LONG2 *pack); + + +static BOOL ValidCRC_short( const PACK_SHORT *pack); +static BOOL ValidCRC_long1 ( const PACK_LONG1 *pack); +static BOOL ValidCRC_long2 ( const PACK_LONG2 *pack); + + +static int EncodeS ( PACK_SHORT *pack, const MLX_PackNfo *nfo); +static int DecodeS ( const PACK_SHORT *pack, MLX_PackNfo *nfo); + +static int EncodeL1(PACK_LONG1 *pack, const MLX_PackNfo *nfo); +static int DecodeL1(const PACK_LONG1 *pack, MLX_PackNfo *nfo); + +static int EncodeL2(PACK_LONG2 *pack, const MLX_PackNfo *nfo); +static int DecodeL2(const PACK_LONG2 *pack, MLX_PackNfo *nfo); + +//***************************************************************************** +//*************** Function Definitions **************************************** +//***************************************************************************** + +// ******************************** +// ***** MASTER SIDE FUNCTIONS **** +// ******************************** + +/// **************************************************************************** +/// \fn MLX_ReqReadReg +/// +/// \brief Creates a read register request. +/// +/// \param[out] *pack: Packet to encode as a read register +/// \param[in] reg: Register address to read +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-01 +/// **************************************************************************** +int MLX_ReqReadReg( PACK_SHORT *pack, uint16 reg) +{ + int res; + MLX_PackNfo nfo; + + // Reset packet! + memset( pack, 0, sizeof(*pack)); + + nfo.pktype = PACK_RREG; + nfo.size = 1; + nfo.seq = 0; + nfo.addr = reg; + + res = EncodeS( pack, &nfo); + if (res < 0) + return -1; + + return 0; +} + + +/// **************************************************************************** +/// \fn MLX_ReqWriteReg +/// +/// \brief Creates a write register request. +/// +/// \param[out] *pack: Packet to encode as a write register +/// \param[in] reg: Register address to write +/// \param[in] val: Value to write +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-07 +/// **************************************************************************** +int MLX_ReqWriteReg( PACK_SHORT *pack, uint16 reg, uint16 val) +{ + int res; + MLX_PackNfo nfo; + + // Reset packet! + memset( pack, 0, sizeof(*pack)); + + nfo.pktype = PACK_WREG; + nfo.size = 1; + nfo.seq = 0; + nfo.addr = reg; + nfo.data = val; + + res = EncodeS( pack, &nfo); + if (res < 0) + return -1; + + return 0; +} + + +/// **************************************************************************** +/// \fn MLX_ReqReadTrc +/// +/// \brief Creates a read raw data request. +/// +/// \param[out] *pack: Packet to encode +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-05-07 +/// **************************************************************************** +int MLX_ReqReadTrc( PACK_SHORT *pack) +{ + int res; + MLX_PackNfo nfo; + + nfo.pktype = PACK_RFIRM; + nfo.size = 0; + nfo.seq = 0; + nfo.fwtype = FW_RAW; + + res = EncodeS( pack, &nfo); + if (res < 0) + return -1; + + return 0; +} + + +/// **************************************************************************** +/// \fn MLX_ReqReadEch +/// +/// \brief Creates a read echoes request. +/// +/// \param[out] *pack: Packet to encode +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-05-28 +/// **************************************************************************** +int MLX_ReqReadEch( PACK_SHORT *pack) +{ + int res; + MLX_PackNfo nfo; + + nfo.pktype = PACK_RFIRM; + nfo.size = 0; + nfo.seq = 0; + nfo.fwtype = FW_PROCESSED; + + res = EncodeS( pack, &nfo); + if (res < 0) + return -1; + + return 0; +} + + +/// **************************************************************************** +/// \fn MLX_ReqWriteFW +/// +/// \brief Creates a write firmware request. +/// +/// \param[out] *pack: Packet to encode +/// \param[in] type: Firmware type to write +/// \param[in] size: Words (2 bytes) to write. 0 means 256. If more than 1, the +/// data will be located in following long packets. The size field +/// of these long packets will be the size for this long pack only. +/// \param[in] data: Data to be written, used only if size == 1 +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-05-07 +/// **************************************************************************** +int MLX_ReqWriteFW( PACK_SHORT *pack, uint size, uint16 data) +{ + int res; + MLX_PackNfo nfo; + + nfo.pktype = PACK_WFIRM; + nfo.fwtype = FW_PATCH; + nfo.size = size; + nfo.seq = 0; + nfo.data = data; + + res = EncodeS( pack, &nfo); + if (res < 0) + return -1; + + return 0; +} + + +/// **************************************************************************** +/// \fn MLX_WriteDataL +/// +/// \brief Creates a long write packet. +/// +/// \param[out] *pack: Packet to encode +/// \param[in] size: Words (2 bytes) to take from data. Max = MLX_LONG_DATA_SZ +/// \param[in] seq: Serial sequence number stamping the packets +/// \param[in] data: Data to be written +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-05-07 +/// **************************************************************************** +int MLX_WriteDataL2( PACK_LONG2 *pack, uint size, uint seq, const uint8 *data) +{ + int res; + MLX_PackNfo nfo; + + if (size > MLX_LONG2_DATA_SZ) + return -1; + + nfo.pktype = PACK_WDATA_L; + nfo.size = size; + nfo.seq = seq; + nfo.dataP = data; + + res = EncodeL2( pack, &nfo); + if (res < 0) + return -1; + + return 0; +} + + +/// **************************************************************************** +/// \fn MLX_DecodeResS / L +/// +/// \brief Decodes a read or write response from slave. +/// +/// \param[in] *pack: Packet to decode +/// \param[out] *val: Data value extracted from response +/// +/// \return 0 on success, negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-24 +/// **************************************************************************** +int MLX_DecodeResS( const PACK_SHORT *pack, uint32 *val) +{ + int res; + MLX_PackNfo nfo; + + if (!ValidCRC_short(pack)){ + return -5; + } + + //SWAP( rx+off, 1); + + res = DecodeS( pack, &nfo); + if (res < 0 || nfo.pktype != PACK_RDATA_RESP_S) + if (nfo.pktype == PACK_STATUS_S) return -6; + else return -20; + + *val = nfo.data; + return 0; +} + +int MLX_DecodeResL1(const PACK_LONG1 *pack) +{ + int res; + MLX_PackNfo nfo; + + if (!ValidCRC_long1(pack)){ + return -9; + } + + res = DecodeL1(pack, &nfo); + if (res < 0 || nfo.pktype != PACK_RDATA_RESP_L) + return -10; + + return 0; +} + +int MLX_DecodeResL2(const PACK_LONG2 *pack) +{ + int res; + MLX_PackNfo nfo; + + if (!ValidCRC_long2(pack)){ + return -9; + } + + res = DecodeL2(pack, &nfo); + if (res < 0 || ((nfo.pktype != PACK_RDATA_RESP_L) && (nfo.pktype != PACK_STATUS_L))) + return -10; + + return 0; +} + + +// ******************************** +// ***** SLAVE SIDE FUNCTIONS ***** +// ******************************** + +/// **************************************************************************** +/// \fn MLX_ResReadReg +/// +/// \brief Creates a read register response. +/// +/// \param[out] *pack: Packet to encode as a response +/// \param[in] val: Register value +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-01 +/// **************************************************************************** +int MLX_ResReadReg( PACK_SHORT *pack, uint16 val) +{ + int res; + MLX_PackNfo nfo; + + // Reset packet! + memset( pack, 0, sizeof(*pack)); + + nfo.pktype = PACK_RDATA_RESP_S; + nfo.size = 1; + nfo.seq = 0; + nfo.data = val; + + res = EncodeS( pack, &nfo); + if (res < 0) + return -1; + + return 0; +} + +/// **************************************************************************** +/// \fn MLX_DecodeReqS +/// +/// \brief Decodes a request from master. +/// +/// \param[in] *pack: Packet to decode +/// \param[out] *nfo: Filled info struct +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-28 +/// **************************************************************************** +int MLX_DecodeReqS( const PACK_SHORT *pack, MLX_PackNfo *nfo) +{ + int res; + + if (!ValidCRC_short(pack)){ + return -1; + } + + res = DecodeS( pack, nfo); + if (res < 0) + return -1; + + return 0; +} + + +/// **************************************************************************** +/// \fn MLX_ResReadData +/// +/// \brief Encodes a long read response. +/// +/// \param[in] *pack: Packet to decode +/// \param[out] *nfo: Filled info struct +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-05-07 +/// **************************************************************************** +int MLX_ResReadData( PACK_LONG1 *pack, uint size, uint seq, const uint8 *data) +{ + int res; + MLX_PackNfo nfo; + + if (size > MLX_LONG1_DATA_SZ) + return -1; + + nfo.pktype = PACK_RDATA_RESP_L; + nfo.size = size; + nfo.seq = seq; + nfo.dataP = data; + + res = EncodeL1( pack, &nfo); + if (res < 0) + return -1; + + return 0; +} + +/// **************************************************************************** +/// \fn MLX_ResReadDataE +/// +/// \brief Encodes an echo read response. +/// +/// \param[in] *pack: Packet to decode +/// \param[out] *nfo: Filled info struct +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-05-07 +/// **************************************************************************** +int MLX_ResReadDataL2(PACK_LONG2 *pack, uint size, uint seq, const uint8 *data) +{ + int res; + MLX_PackNfo nfo; + + if (size > MLX_LONG2_DATA_SZ) + return -1; + + nfo.pktype = PACK_RDATA_RESP_L; + nfo.size = size; + nfo.seq = seq; + nfo.dataP = data; + + res = EncodeL2(pack, &nfo); + if (res < 0) + return -1; + + return 0; +} + + +// ******************************** +// ****** COMMON FUNCTIONS ******** +// ******************************** + +/// **************************************************************************** +/// \fn FillCRC_short / long +/// +/// \brief Computes and sets the CRC field in a packet. +/// +/// \param[in/out] *pack: Packet on which to set the CRC +/// +/// \return Nothing. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-24 +/// **************************************************************************** +void FillCRC_short( PACK_SHORT *pack) +{ + pack->crc = CRC16_Compute( (uint8*)pack, sizeof(*pack)-MLX_CRC_SZ); + //SWAP(&pack->crc,2); +} + +void FillCRC_long1(PACK_LONG1 *pack) +{ + pack->crc = CRC16_Compute((uint8*)pack, sizeof(*pack) - MLX_CRC_SZ); + //SWAP(&pack->crc,2); +} + +void FillCRC_long2(PACK_LONG2 *pack) +{ + pack->crc = CRC16_Compute((uint8*)pack, sizeof(*pack) - MLX_CRC_SZ); + //SWAP(&pack->crc,2); +} + +/// **************************************************************************** +/// \fn ValidCRC_short / long +/// +/// \brief Validates the CRC of a packet. +/// +/// \param[in/out] pack: Packet on which to validate the CRC +/// +/// \return Validation status. TRUE if valid, FALSE if invalid. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-24 +/// **************************************************************************** +BOOL ValidCRC_short( const PACK_SHORT *pack) +{ + return CRC16_IsValid( (uint8*)pack, sizeof(*pack), MLX_CRC_SZ); +} + +BOOL ValidCRC_long1( const PACK_LONG1 *pack) +{ + return CRC16_IsValid( (uint8*)pack, sizeof(*pack), MLX_CRC_SZ); +} + +BOOL ValidCRC_long2(const PACK_LONG2 *pack) +{ + return CRC16_IsValid((uint8*)pack, sizeof(*pack), MLX_CRC_SZ); +} + +/// **************************************************************************** +/// \fn CRC16_Compute +/// +/// \brief Computes the CRC16 of a data vector. +/// This is the CCITT CRC 16 polynomial X^16 + X^12 + X^5 + 1. +/// This works out to be 0x1021, but the way the algorithm works +/// lets us use 0x8408 (the reverse of the bit pattern). The high +/// bit is always assumed to be set, thus we only use 16 bits to +/// represent the 17 bit value. +/// +/// Reference: stjarnhimlen.se/snippets/crc-16.c +/// +/// \param[in] *data: Data vector for which to compute the CRC +/// \param[in] n: Number of bytes in data +/// +/// \return The CRC +/// +/// \authors Jean-F. Bernier +/// \since 2015-03-31 +/// **************************************************************************** +/* uint16 CRC16_Compute( const uint8 *data, uint16 n) +{ + uint8 a; + uint tmp; + uint crc = 0x0000; + + const uint POLY = 0x8408; + + if (n == 0) + return (~crc); + + do + { + tmp = (uint)0xFF & *data++; + + for (a = 0 ; a < 8; ++a) + { + tmp >>= 1; + if ((crc & 0x0001) ^ (tmp & 0x0001)) + crc = (crc >> 1) ^ POLY; + else + crc >>= 1; + } + } while (--n); + + crc = ~crc; + tmp = crc; + crc = (crc << 8) | (tmp >> 8 & 0xFF); + + return crc; +} +*/ + +/* +* Copyright 2001-2010 Georges Menie (www.menie.org) +* All rights reserved. +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the University of California, Berkeley nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* CRC16 implementation acording to CCITT standards */ + +static const uint16 crc16tab[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +uint16 CRC16_Compute(const uint8 *buf, uint16 len) +{ + uint16 tmp; + int counter; + uint16 crc = 0; + for (counter = 0; counter < len; counter++) + crc = (crc << 8) ^ crc16tab[((crc >> 8) ^ *(char *)buf++) & 0x00FF]; + + tmp = crc; + crc = (crc << 8) | (tmp >> 8 & 0xFF); + + return crc; +} + + +/// **************************************************************************** +/// \fn CRC16_IsValid +/// +/// \brief Validates the CRC in a byte vector. Computes CRC on all bytes except +/// the X lasts CRC bytes and compares it to the one found in these X lasts. +/// +/// \param[in] *data: Data vector for which to validate the CRC +/// \param[in] n: Total bytes in data +/// \param[in] nbCrc: Nb of bytes at the end of data for the CRC +/// +/// \return TRUE if valid, FALSE otherwise. +/// +/// \authors Jean-F. Bernier +/// \since 2014-10-21 +/// **************************************************************************** +BOOL CRC16_IsValid( const uint8 *data, uint n, uint nbCrc) +{ + if (n <= 1){ + return FALSE; + } + + uint16 test = *(uint16*)(data+n-nbCrc); + //SWAP( &test, 1); + uint16 crc = CRC16_Compute( data, n-nbCrc); + return (crc == test); +} + + + +/// **************************************************************************** +/// \fn SetBitVector +/// +/// \brief Sets a value in a vector of bits at chosen offset and bit width. +/// Input bits all pre-supposed at zero in buffer. +/// +/// \param[in] *buf: Target vector of bits to be modified. The first byte will contain +/// the lowest bits (at lowest offset). +/// \param[in] off: Position offset in bits where to put val, 0-based +/// \param[in] wid: Number of bits to take from val [0 32] +/// \param[in] val: Value to set in buf. Its low bit is always set first at chosen offset. +/// \param[in] inv: Inverse bit ordering inside a byte. Usually, bit#0 is the least significant to the right. +/// With this, bit#0 becomes the most significant to the left. +/// +/// \return Error code: 0 on success, negative otherwise. +/// +/// \authors Jean-F. Bernier +/// \since 2015-04-01 +/// **************************************************************************** +int SetBitVector( uint8 *buf, uint32 off, uchar wid, uint32 val, uchar inv) +{ + if (wid <= 0 || wid > 32 || buf == NULL) + return -1; + + if (inv && wid > off+1) + return -2; + + buf += (off >> 3); // Byte count to move + uint8 rem = off % 8; // Remaining bits to move + + // While there is a remaining bit to set... + while (wid >= 1) + { + // Check the bit value. If zero, nothing to do. + if (val & 1) + { + if (!inv) + BIT_SET( *buf, rem); + else + BIT_SET( *buf, 7-rem); + } + + if (!inv) + { + // Wrap around. Goto next byte when setting bit index > 7 + ++rem; + if (rem >= 8) + { + rem = 0; + ++buf; + } + } + else + { + // Wrap around. Goto previous byte when setting "negative" bit index + --rem; + if (rem >= 8) + { + rem = 7; + --buf; + } + } + + // Activate the next bit + val >>= 1; + --wid; + } + + return 0; +} + + +/// **************************************************************************** +/// \fn GetBitVector +/// +/// \brief Gets a sub-array of bits inside a bigger one. +/// Selects the bits to obtain using offset and bit width. +/// +/// \param[in] *buf: Target vector of bits to be read. The first byte will contain +/// the lowest bits (at lowest offset). +/// \param[in] off: Position offset in bits where to start reading the low bit, 0-based +/// \param[in] wid: Number of bits to read into val [0 32] +/// \param[out] *val: Value obtained from buf. +/// \param[in] inv: Inverse bit ordering inside a byte. Usually, bit#0 is the least significant to the right. +/// With this, bit#0 becomes the most significant to the left. +/// +/// \return Error code: 0 on success, negative otherwise. +/// +/// \authors Jean-F. Bernier +/// \since 2015-04-28 +/// **************************************************************************** +int GetBitVector( const uint8 *buf, uint32 off, uchar wid, uint32 *val, uchar inv) +{ + if (wid <= 0 || wid > 32 || buf == NULL) + return -1; + + if (inv && wid > off+1) + return -2; + + buf += (off >> 3); // Byte count to move + uint8 rem = off % 8; // Remaining bits to move + uchar bit, b = 0; + *val = 0; + + // While there is a remaining bit to set... + while (wid >= 1) + { + if (!inv) + bit = BIT_GET( *buf, rem); + else + bit = BIT_GET( *buf, 7-rem); + + if (bit) + BIT_SET( *val, b); + + if (!inv) + { + // Wrap around. Goto next byte when setting bit index > 7 + ++rem; + if (rem >= 8) + { + rem = 0; + ++buf; + } + } + else + { + // Wrap around. Goto previous byte when setting "negative" bit index + --rem; + if (rem >= 8) + { + rem = 7; + --buf; + } + } + + // Activate the next bit + --wid; + ++b; + } + + return 0; +} + +/// **************************************************************************** +/// \fn ReverseBits +/// +/// \brief Reverses a bit pattern like a mirror. First bits becomes last. +/// Ex.: 011001 <-> 100110 (v = 25, n = 6) +/// +/// \param[in] bits: Value to use as bit pattern +/// \param[in] nb: Number of bits to take from v. Starts at low bits. +/// +/// \return The value with a reversed bit pattern. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-30 +/// **************************************************************************** +/*uint32 ReverseBits( uint32 bits, char nb) +{ + // If n == 0, no bits to use. So result will be zero. + uint32 res = 0; + + while ((signed char)--nb >= 0) + { + res <<= 1; // Shift current result by 1 + res += (bits & 1); // Take the current bit into result + bits >>= 1; // Prepare for next bit + } + + return res; +} +*/ +/// **************************************************************************** +/// \fn EncodeS +/// +/// \brief Generic short packet encoder. +/// +/// \param[out] *pack: Resulting packet encoded with nfo +/// \param[in] *nfo: Info used to encode packet +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-27 +/// **************************************************************************** +int EncodeS( PACK_SHORT *pack, const MLX_PackNfo *nfo) +{ + int res; + + // Reject long packets + if (nfo->pktype == PACK_STATUS_L || nfo->pktype == PACK_RDATA_RESP_L || nfo->pktype == PACK_WDATA_L) + { + return -1; + } + + if (nfo->pktype == PACK_STATUS_S) + { + res = SetBitVector( pack->buf, OFF_TYPE, WID_TYPE, nfo->pktype, BIT_ORDER); + if (res < 0) + return -1; + + // Is error field + res = SetBitVector( pack->buf, OFF_ISERR, WID_ISERR, nfo->iserr, BIT_ORDER); + if (res < 0) + return -1; + + // Error qualifier field + res = SetBitVector( pack->buf, OFF_ERROR, WID_ERROR, nfo->error, BIT_ORDER); + if (res < 0) + return -1; + + goto END; + } + + // Packet type field + res = SetBitVector( pack->buf, OFF_TYPE, WID_TYPE, nfo->pktype, BIT_ORDER); + if (res < 0) + return -1; + + // Size field + res = SetBitVector( pack->buf, OFF_SIZE, WID_SIZE, nfo->size, BIT_ORDER); + if (res < 0) + return -1; + + // Sequence field + res = SetBitVector( pack->buf, OFF_SEQ, WID_SEQ, nfo->seq, BIT_ORDER); + if (res < 0) + return -1; + + // Address field + if (nfo->pktype == PACK_RREG || nfo->pktype == PACK_WREG) + { + res = SetBitVector( pack->buf, OFF_ADDR, WID_ADDR, nfo->addr, BIT_ORDER); + } + else if (nfo->pktype == PACK_RFIRM) + { + res = SetBitVector( pack->buf, OFF_ADDR, WID_ADDR, nfo->fwtype, BIT_ORDER); + } + else if (nfo->pktype == PACK_WFIRM) + { + res = SetBitVector(pack->buf, OFF_ADDR, WID_ADDR, nfo->fwtype, BIT_ORDER); + } + + if (res < 0) + return -1; + + // Data field + if (nfo->pktype == PACK_RDATA_RESP_S) + { + res = SetBitVector( pack->buf, OFF_RES_DATA, WID_RES_DATA, nfo->data, BIT_ORDER); + } + else if (nfo->pktype == PACK_WREG) + { + res = SetBitVector( pack->buf, OFF_DATA, WID_DATA, nfo->data, BIT_ORDER); + } + else if (nfo->pktype == PACK_WFIRM) + { + res = SetBitVector(pack->buf, OFF_DATA, WID_DATA, nfo->data, BIT_ORDER); + } + + if (res < 0) + return -1; + + //SWAP(&pack,sizeof(*pack)); + +END: + FillCRC_short(pack); + //SWAP( &pack->crc, 1); + + return 0; +} + +/// **************************************************************************** +/// \fn DecodeS +/// +/// \brief Generic short packet decoder. +/// +/// \param[in] *pack: Packet to be decoded into info +/// \param[out] *nfo: Filled packet info from pack data +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-27 +/// **************************************************************************** +int DecodeS( const PACK_SHORT *pack, MLX_PackNfo *nfo) +{ + uint32 v; + int res; + + //SWAP(&pack, sizeof(*pack)); + + res = GetBitVector( pack->buf, OFF_TYPE, WID_TYPE, &v, BIT_ORDER); + if (res < 0) + return -1; + nfo->pktype = (PackType)v; + + res = GetBitVector( pack->buf, OFF_SIZE, WID_SIZE, &v, BIT_ORDER); + if (res < 0) + return -1; + nfo->size = v; + + res = GetBitVector( pack->buf, OFF_SEQ, WID_SEQ, &v, BIT_ORDER); + if (res < 0) + return -1; + nfo->seq = v; + + if (nfo->pktype == PACK_STATUS_S) + { + res = GetBitVector( pack->buf, OFF_ISERR, WID_ISERR, &v, BIT_ORDER); + if (res < 0) + return -1; + + nfo->iserr = v; + + res = GetBitVector( pack->buf, OFF_ERROR, WID_ERROR, &v, BIT_ORDER); + if (res < 0) + return -1; + + nfo->error = v; + return 0; + } + + + if (nfo->pktype == PACK_RREG || nfo->pktype == PACK_WREG) + { + res = GetBitVector( pack->buf, OFF_ADDR, WID_ADDR, &v, BIT_ORDER); + if (res < 0) + return -1; + + nfo->addr = v; + } + + + v = 0; + if (nfo->pktype == PACK_RDATA_RESP_S) + { + res = GetBitVector( pack->buf, OFF_RES_DATA, WID_RES_DATA, &v, BIT_ORDER); + } + else if (nfo->pktype == PACK_WREG || nfo->pktype == PACK_WFIRM) + { + res = GetBitVector( pack->buf, OFF_DATA, WID_DATA, &v, BIT_ORDER); + } + + if (res < 0) + return -1; + + nfo->data = v; + + return 0; +} + +/// **************************************************************************** +/// \fn EncodeL +/// +/// \brief Generic long packet encoder. +/// +/// \param[out] *pack: Resulting packet encoded with nfo +/// \param[in] *nfo: Info used to encode packet +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-27 +/// **************************************************************************** +int EncodeL1( PACK_LONG1 *pack, const MLX_PackNfo *nfo) +{ + int res; + + // Reset packet! + memset( pack, 0, sizeof(*pack)); + + // Reject short packets + if (nfo->pktype != PACK_STATUS_L && nfo->pktype != PACK_RDATA_RESP_L && nfo->pktype != PACK_WDATA_L) + { + return -1; + } + + if (nfo->pktype == PACK_STATUS_L) + { + res = SetBitVector( pack->buf, OFF_TYPE, WID_TYPE, nfo->pktype, BIT_ORDER); + if (res < 0) + return -1; + + // Is error field + res = SetBitVector( pack->buf, OFF_ISERR, WID_ISERR, nfo->iserr, BIT_ORDER); + if (res < 0) + return -1; + + // Error qualifier field + res = SetBitVector( pack->buf, OFF_ERROR, WID_ERROR, nfo->error, BIT_ORDER); + if (res < 0) + return -1; + + goto END; + } + + // Packet type field + res = SetBitVector( pack->buf, OFF_TYPE, WID_TYPE, nfo->pktype, BIT_ORDER); + if (res < 0) + return -1; + + // Size field + res = SetBitVector( pack->buf, OFF_SIZE, WID_SIZE, nfo->size, BIT_ORDER); + if (res < 0) + return -1; + + // Sequence field + res = SetBitVector( pack->buf, OFF_SEQ, WID_SEQ, nfo->seq, BIT_ORDER); + if (res < 0) + return -1; + + // Data field + memcpy( pack->data, nfo->dataP, nfo->size); + if (res < 0) + return -1; + + //SWAP(&pack,sizeof(*pack)); + +END: + FillCRC_long1(pack); + //SWAP( &pack->crc, 1); + + return 0; +} + + + +/// **************************************************************************** +/// \fn DecodeL +/// +/// \brief Generic long packet decoder. +/// +/// \param[in] *pack: Packet to be decoded into info +/// \param[out] *nfo: Filled packet info from pack data +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-27 +/// **************************************************************************** +int DecodeL1( const PACK_LONG1 *pack, MLX_PackNfo *nfo) +{ + uint32 v; + int res; + + //SWAP(&pack,sizeof(*pack)); + + res = GetBitVector( pack->buf, OFF_TYPE, WID_TYPE, &v, BIT_ORDER); + if (res < 0) + return -1; + nfo->pktype = (PackType)v; + + res = GetBitVector( pack->buf, OFF_SIZE, WID_SIZE, &v, BIT_ORDER); + if (res < 0) + return -1; + nfo->size = v; + + res = GetBitVector( pack->buf, OFF_SEQ, WID_SEQ, &v, BIT_ORDER); + if (res < 0) + return -1; + nfo->seq = v; + + if (nfo->pktype == PACK_STATUS_L) + { + res = GetBitVector( pack->buf, OFF_ISERR, WID_ISERR, &v, BIT_ORDER); + if (res < 0) + return -1; + + nfo->iserr = v; + + res = GetBitVector( pack->buf, OFF_ERROR, WID_ERROR, &v, BIT_ORDER); + if (res < 0) + return -1; + + nfo->error = v; + return 0; + } + + return 0; +} + +/// **************************************************************************** +/// \fn EncodeL2 +/// +/// \brief Generic long packet encoder. +/// +/// \param[out] *pack: Resulting packet encoded with nfo +/// \param[in] *nfo: Info used to encode packet +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-27 +/// **************************************************************************** +int EncodeL2(PACK_LONG2 *pack, const MLX_PackNfo *nfo) +{ + int res; + + // Reset packet! + memset(pack, 0, sizeof(*pack)); + + // Reject short packets + if (nfo->pktype != PACK_STATUS_L && nfo->pktype != PACK_RDATA_RESP_L && nfo->pktype != PACK_WDATA_L) + { + return -1; + } + + if (nfo->pktype == PACK_STATUS_L) + { + res = SetBitVector(pack->buf, OFF_TYPE, WID_TYPE, nfo->pktype, BIT_ORDER); + if (res < 0) + return -1; + + // Is error field + res = SetBitVector(pack->buf, OFF_ISERR, WID_ISERR, nfo->iserr, BIT_ORDER); + if (res < 0) + return -1; + + // Error qualifier field + res = SetBitVector(pack->buf, OFF_ERROR, WID_ERROR, nfo->error, BIT_ORDER); + if (res < 0) + return -1; + + goto END; + } + + // Packet type field + res = SetBitVector(pack->buf, OFF_TYPE, WID_TYPE, nfo->pktype, BIT_ORDER); + if (res < 0) + return -1; + + // Size field + res = SetBitVector(pack->buf, OFF_SIZE, WID_SIZE, nfo->size, BIT_ORDER); + if (res < 0) + return -1; + + // Sequence field + res = SetBitVector(pack->buf, OFF_SEQ, WID_SEQ, nfo->seq, BIT_ORDER); + if (res < 0) + return -1; + + // Data field + memcpy(pack->data, nfo->dataP, nfo->size*2); + + if (res < 0) + return -1; + + //SWAP(&pack,sizeof(*pack)); + +END: + FillCRC_long2(pack); + //SWAP( &pack->crc, 1); + + return 0; +} + + + +/// **************************************************************************** +/// \fn DecodeE +/// +/// \brief Generic long packet decoder. +/// +/// \param[in] *pack: Packet to be decoded into info +/// \param[out] *nfo: Filled packet info from pack data +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-27 +/// **************************************************************************** +int DecodeL2(const PACK_LONG2 *pack, MLX_PackNfo *nfo) +{ + uint32 v; + int res; + + //SWAP(&pack,sizeof(*pack)); + + res = GetBitVector(pack->buf, OFF_TYPE, WID_TYPE, &v, BIT_ORDER); + if (res < 0) + return -1; + nfo->pktype = (PackType)v; + + res = GetBitVector(pack->buf, OFF_SIZE, WID_SIZE, &v, BIT_ORDER); + if (res < 0) + return -1; + nfo->size = v; + + res = GetBitVector(pack->buf, OFF_SEQ, WID_SEQ, &v, BIT_ORDER); + if (res < 0) + return -1; + nfo->seq = v; + + if (nfo->pktype == PACK_STATUS_L) + { + res = GetBitVector(pack->buf, OFF_ISERR, WID_ISERR, &v, BIT_ORDER); + if (res < 0) + return -1; + + nfo->iserr = v; + + res = GetBitVector(pack->buf, OFF_ERROR, WID_ERROR, &v, BIT_ORDER); + if (res < 0) + return -1; + + nfo->error = v; + return 0; + } + + return 0; +} + + + + +/// **************************************************************************** +/// \fn MLX_EncodeStatusS +/// +/// \brief Creates a short status packet. +/// +/// \param[out] *pack: Resulting encoded packet +/// \param[in] iserr: Flag telling if it is an error or not +/// \param[in] err: Error qualifier data +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-04-28 +/// **************************************************************************** +int MLX_EncodeStatusS( PACK_SHORT *pack, uint8 iserr, uint16 err) +{ + int res; + MLX_PackNfo nfo; + + // Reset packet! + memset( pack, 0, sizeof(*pack)); + + nfo.pktype = PACK_STATUS_S; + nfo.iserr = iserr; + nfo.error = err; + + res = EncodeS( pack, &nfo); + if (res < 0) + return -1; + + return 0; +} + +/// **************************************************************************** +/// \fn MLX_DecodeStatusS +/// +/// \brief Attempts to decode a packet as a status packet. +/// +/// \param[in] *pack: Packet to decode +/// \param[out] *iserr: Flag telling if it is an error or not +/// \param[out] *err: Error qualifier data +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-05-01 +/// **************************************************************************** +int MLX_DecodeStatusS( const PACK_SHORT *pack, uint8 *iserr, uint16 *err) +{ + int res; + MLX_PackNfo nfo; + + if (!ValidCRC_short(pack)){ + return -1; + } + + res = DecodeS( pack, &nfo); + if (res < 0 || nfo.pktype != PACK_STATUS_S) + return -1; + + *iserr = nfo.iserr; + *err = nfo.error; + + return 0; +} + + +/// **************************************************************************** +/// \fn MLX_EncodeStatusL +/// +/// \brief Creates a long status packet. +/// +/// \param[out] *pack: Resulting encoded packet +/// \param[in] iserr: Flag telling if it is an error or not +/// \param[in] err: Error qualifier data +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-05-19 +/// **************************************************************************** +int MLX_EncodeStatusL1( PACK_LONG1 *pack, uint8 iserr, uint16 err) +{ + int res; + MLX_PackNfo nfo; + + // Reset packet! + memset(pack, 0, sizeof(*pack)); + + nfo.pktype = PACK_STATUS_L; + nfo.iserr = iserr; + nfo.error = err; + + res = EncodeL1( pack, &nfo); + if (res < 0) + return -1; + + return 0; +} + +/// **************************************************************************** +/// \fn MLX_DecodeStatusL +/// +/// \brief Attempts to decode a packet as a status packet. +/// +/// \param[in] *pack: Packet to decode +/// \param[out] *iserr: Flag telling if it is an error or not +/// \param[out] *err: Error qualifier data +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-05-19 +/// **************************************************************************** +int MLX_DecodeStatusL1( const PACK_LONG1 *pack, uint8 *iserr, uint16 *err) +{ + int res; + MLX_PackNfo nfo; + + if (!ValidCRC_long1(pack)) + return -1; + + res = DecodeL1( pack, &nfo); + if (res < 0 || nfo.pktype != PACK_STATUS_L) + return -1; + + *iserr = nfo.iserr; + *err = nfo.error; + + return 0; +} + +/// **************************************************************************** +/// \fn MLX_EncodeStatusL2 +/// +/// \brief Creates a echo status packet. +/// +/// \param[out] *pack: Resulting encoded packet +/// \param[in] iserr: Flag telling if it is an error or not +/// \param[in] err: Error qualifier data +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-05-19 +/// **************************************************************************** +int MLX_EncodeStatusL2(PACK_LONG2 *pack, uint8 iserr, uint16 err) +{ + int res; + MLX_PackNfo nfo; + + // Reset packet! + memset(pack, 0, sizeof(*pack)); + + nfo.pktype = PACK_STATUS_L; + nfo.iserr = iserr; + nfo.error = err; + + res = EncodeL2(pack, &nfo); + if (res < 0) + return -1; + + return 0; +} + +/// **************************************************************************** +/// \fn MLX_DecodeStatusL2 +/// +/// \brief Attempts to decode a packet as a status packet. +/// +/// \param[in] *pack: Packet to decode +/// \param[out] *iserr: Flag telling if it is an error or not +/// \param[out] *err: Error qualifier data +/// +/// \return Error code: 0 on success or negative on error. +/// +/// \authors Jean-Fran�ois Bernier +/// \since 2015-05-19 +/// **************************************************************************** +int MLX_DecodeStatusL2(const PACK_LONG2 *pack, uint8 *iserr, uint16 *err) +{ + int res; + MLX_PackNfo nfo; + + if (!ValidCRC_long2(pack)) + return -1; + + res = DecodeL2(pack, &nfo); + if (res < 0 || nfo.pktype != PACK_STATUS_L) + return -1; + + *iserr = nfo.iserr; + *err = nfo.error; + + return 0; +} + +