/*
 * Video On Demand Samples
 *
 * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * You may also obtain this software under a propriety license from Microchip.
 * Please contact Microchip for further information.
 *
 */

/*----------------------------------------------------------*/
/*! \file
 *  \brief  This file contains the CMostMsg class.
 */
/*----------------------------------------------------------*/
#ifndef MOSTMSG_H
#define MOSTMSG_H

#include <stdint.h>
#include <stdbool.h>
#include <string.h>


/*----------------------------------------------------------*/
/*!
 * \brief  class holding a MOST message, it support serializing and deserializing
 * \note Serialize-Protocol is: </br>
 *      p[0] = 0x49 (Start) </br>
 *      p[1] = 0x72 (Start) </br>
 *      p[2] = 0x16 (Start) </br>
 *      p[3] = 0x25 (Start) </br>
 *      p[4] = FBlock Identifier </br>
 *      p[5] = Instance Identifier </br>
 *      p[6] = Function Identifier << 8 </br>
 *      p[7] = Function Identifier << 0 </br>
 *      p[8] = OP Type </br>
 *      p[9] = 0x0 (Reserved) </br>
 *      p[10] = 0x0 (Reserved) </br>
 *      p[11] = 0x0 (Reserved) </br>
 *      p[12] = Payload Length << 24 </br>
 *      p[13] = Payload Length << 16 </br>
 *      p[14] = Payload Length << 8 </br>
 *      p[15] = Payload Length << 0 </br>
 *      p[16] = Header CRC32(p[0] - p[15]) << 24 </br>
 *      p[17] = Header CRC32(p[0] - p[15]) << 16 </br>
 *      p[18] = Header CRC32(p[0] - p[15]) << 8 </br>
 *      p[19] = Header CRC32(p[0] - p[15]) << 0 </br>
 *      p[20] - p[n] = Payload </br>
 *      p[n+1] = Payload CRC32(p[20] - p[n]) << 24 </br>
 *      p[n+2] = Payload CRC32(p[20] - p[n]) << 16 </br>
 *      p[n+3] = Payload CRC32(p[20] - p[n]) << 8 </br>
 *      p[n+4] = Payload CRC32(p[20] - p[n]) << 0 </br>
 */

/*----------------------------------------------------------*/
class CMostMsg
{
private:
    bool m_nIsValid;
    int32_t m_nRefCount;
    uint32_t m_nFBlock;
    uint32_t m_nFunc;
    uint32_t m_nInst;
    uint8_t m_nOpType;
    uint32_t m_nPayloadLen;
    uint8_t *m_Payload;
    uint32_t m_nParsePos;
    uint32_t m_nHeaderCrc;
    uint32_t m_nPayloadCrc;
    uint8_t m_zHeader[16];

protected:
    /*----------------------------------------------------------*/
    /*! \brief Default Destructor
     */
    /*----------------------------------------------------------*/
    virtual ~CMostMsg();

public:

    static const uint8_t OP_SET = 0x0;
    static const uint8_t OP_GET = 0x1;
    static const uint8_t OP_SETGET = 0x2;
    static const uint8_t OP_INC = 0x3;
    static const uint8_t OP_DEC = 0x4;
    static const uint8_t OP_GETINTERFACE = 0x5;
    static const uint8_t OP_STATUS = 0xC;
    static const uint8_t OP_INTERFACE = 0xE;
    static const uint8_t OP_ERROR = 0xF;
    static const uint8_t OP_START = 0x0;
    static const uint8_t OP_ABORT = 0x1;
    static const uint8_t OP_STARTRESULT = 0x2;
    static const uint8_t OP_STARTRESULTACK = 0x6;
    static const uint8_t OP_ABORTACK = 0x7;
    static const uint8_t OP_STARTACK = 0x8;
    static const uint8_t OP_ERRORACK = 0x9;
    static const uint8_t OP_PROCESSINGACK = 0xA;
    static const uint8_t OP_PROCESSING = 0xB;
    static const uint8_t OP_RESULT = 0xC;
    static const uint8_t OP_RESULTACK = 0xD;
    static const uint8_t OP_REPORTS = 0x9;


    /*----------------------------------------------------------*/
    /*! \brief constructs a new message, which is initial not valid. 
     *  \note It has to fed by the Parse method until IsValid method reports true.
     */
    /*----------------------------------------------------------*/
    CMostMsg();


    /*----------------------------------------------------------*/
    /*! \brief constructs a new message which is fully set up and valid
     *  \param nFBlock - The MOST Function Block Identifier
     *  \param nInst - The MOST Function Block Instance Identifier
     *  \param nFunc - The MOST Function Block Function Identifier
     *  \param nPayloadLen - The amount of bytes stored in Payload
     *  \param Payload - The pointer to the payload byte array.
     */
    /*----------------------------------------------------------*/
    CMostMsg( uint32_t nFBlock, uint32_t nInst, uint32_t nFunc, uint8_t nOpType, uint32_t nPayloadLen,
        const uint8_t *Payload );

    /*----------------------------------------------------------*/
    /*! \brief Increments the reference counter
     */
    /*----------------------------------------------------------*/
    void AddReference();

    /*----------------------------------------------------------*/
    /*! \brief Decrements the reference counter, if the value reaches 0, this object destroys it self.
     */
    /*----------------------------------------------------------*/
    void RemoveReference();

    /*----------------------------------------------------------*/
    /*! \brief Fills out an empty CMostMsg (created with default constructor)
     *  \return true, if parsing was valid. false, parser error, no way to continue.
     *  \note Check with IsValid method if parsing is finished.
     */
    /*----------------------------------------------------------*/
    bool Parse( uint8_t receivedByte );



    /*----------------------------------------------------------*/
    /*! \brief serializes a message to an byte array
     *  \note The byte array will be created inside this method and has to be freed after usage!
     *  \return The bytes used inside the given buffer.
     */
    /*----------------------------------------------------------*/
    uint32_t ToByteArray( uint8_t **ppBuffer );


    bool IsValid();

    uint32_t GetFBlock();

    uint32_t GetFunc();

    uint32_t GetInst();

    uint8_t GetOpType();

    uint8_t *GetPayload();

    uint32_t GetPayloadLen();
};


#endif //MOSTMSG_H