This is a class which contains function to interface with the MLX75320

Dependents:   MLX75320_API

MLX_BaseSPI.c

Committer:
TNU
Date:
2016-02-25
Revision:
0:dfe498e03679

File content as of revision 0:dfe498e03679:

// *****    ***********************************************************************
/*!
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;
}