/*
 * data.c
 *
 *  Created on: Feb 19, 2020
 *      Author: akos
 */

#include <stdint.h>

#include "ieladLib.h"

extern uint16_t crc16(const uint8_t* const pByte, const int len);

void initParserState(ieladParserState* state)
{
    state->state = SYNC;
    state->payloadCounter = 0;
    state->subState = 0;
}

parserResult parser(unsigned char data, ieladMsg* displayMsg, ieladParserState* state)
{
    static int counter;
    counter++;

    switch (state->state)
    {
        case SYNC:
        {
            if (data == DISPLAY_MSG_SYNC_BYTE)
            {
                displayMsg->header.syncByte = data;
                state->subState = 0;
                state->state = MESSAGEID;
            }
            break;
        }
        case MESSAGEID:
        {
            if (state->subState == 0)
            {
                displayMsg->header.msgID = data;
                state->subState++;
            }
            else
            {
                displayMsg->header.msgID |= (data << 8);
                state->subState = 0;
                state->state = MESSAGELENGTH;
            }
            break;
        }
        case MESSAGELENGTH:
        {
            if (state->subState == 0)
            {
                displayMsg->header.length = data;
                state->subState++;
            }
            else
            {
                displayMsg->header.length |= (data << 8);
                state->subState = 0;
                state->state = FRAMECOUNTER;
            }
            break;
        }
        case FRAMECOUNTER:
        {
            displayMsg->header.frameCounter = data;
            state->state = RESERVEDBYTES;
            break;
        }
        case RESERVEDBYTES:
        {
            switch (state->subState)
            {
                case 0:
                {
                    displayMsg->header.reserved = data;
                    state->subState++;
                    break;
                }
                case 1:
                {
                    displayMsg->header.reserved |= (data << 8);
                    state->subState++;
                    break;
                }
                case 2:
                {
                    displayMsg->header.reserved |= (data << 16);
                    state->subState++;
                    break;
                }
                case 3:
                {
                    displayMsg->header.reserved |= (data << 24);
                    state->subState++;
                    break;
                }
                case 4:
                {
                    displayMsg->header.reserved2 = data;
                    state->subState++;
                    break;
                }
                case 5:
                {
                    displayMsg->header.reserved2 |= (data << 8);
                    state->subState++;
                    break;
                }
                case 6:
                {
                    displayMsg->header.reserved2 |= (data << 16);
                    state->subState++;
                    break;
                }
                case 7:
                {
                    displayMsg->header.reserved2 |= (data << 24);
                    state->state = PAYLOAD;
                    state->subState = 0;
                    break;
                }
            }
            break;
        }
        case PAYLOAD:
        {
            if (state->payloadCounter < sizeof(displayMsg->payload))
            {
                displayMsg->payload[state->payloadCounter++] = data;

                if (state->payloadCounter >= (displayMsg->header.length - sizeof(displayMsg->header)))
                {
                    const unsigned short crcCalculated = crc16((uint8_t*)displayMsg, displayMsg->header.length - 2);
                    const unsigned short crcFromMessage = (displayMsg->payload[displayMsg->header.length - sizeof(displayMsg->header) - 2]) |
                                                          (displayMsg->payload[displayMsg->header.length - sizeof(displayMsg->header) - 1] << 8);

                    if (crcCalculated == crcFromMessage)
                    {
                        return PARSE_COMPLETED;
                    }
                    else
                    {
                        return PARSE_CRC_ERROR;
                    }
                }
            }
            else
            {
                return PARSE_ERROR;
            }
            break;
        }
    }

    return PARSE_NOT_COMPLETE;
}
