/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/* 
 * File:   PocsagDecoder.cpp
 * Author: jens
 * 
 * Created on 11. Januar 2019, 17:20
 */

#include "PocsagDecoder.hpp"

static const char numericChar[16] = 
{
	'0', '1', '2', '3', 
	'4', '5', '6', '7', 
	'8', '9', '.', 'U', 
	' ', '-', ']', '[', 
};

PocsagDecoder::PocsagDecoder()
: state(Sync)
, dataCount(0)
, msgPos(0)
, msgWord(0)
, func(0)
, msgActive(0)
{
}

PocsagDecoder::PocsagDecoder(const PocsagDecoder& orig)
{
}

PocsagDecoder::~PocsagDecoder()
{
}

void PocsagDecoder::messageBegin()
{
	msgActive = 1;
}

void PocsagDecoder::messageFinish()
{
	if (msgActive)
	{
		msgActive = 0;
		msgPos = 0;
		msgWord = 0;
		fprintf(stderr, "\n");
	}
}

size_t PocsagDecoder::process(uint8_t const *pData, size_t size)
{
	size_t remain = size;
	size_t numProcessed = 0;
	while(remain >= 4)
	{
		int incr = 4;
		uint32_t word 
				= (uint32_t)pData[0] << 24 & 0xFF000000
				| (uint32_t)pData[1] << 16 & 0x00FF0000
				| (uint32_t)pData[2] <<  8 & 0x0000FF00
				| (uint32_t)pData[3] <<  0 & 0x000000FF;
	
//		fprintf (stderr, "word=%08X\n", word);

		State stateNext = state;
		switch(state)
		{
			case Sync:
				if (word == 0x7CD215D8)
				{
					stateNext = Data;
					dataCount = 0x00;
				}
				else
				{
					incr = 1;
				}
				break;
			case Data:
				// Sync received
				if (word == 0x7CD215D8)
				{
					dataCount = 0x00;
					break;
				}
				
				// Message word
				if (word & 0x80000000)
				{
					if (func == 0x00)
					{
						// Numeric
						for (size_t i=1; i < 21; i++)
						{
							uint32_t bit = 0x80000000 & (word << i);
							msgWord >>= 1;

							msgWord |= (uint8_t)(0x8*(bit != 0));
							msgPos++;
							if (msgPos == 4)
							{
								fprintf(stderr, "%c", numericChar[msgWord]);
								msgPos = 0;
								msgWord = 0;
							}
						}
					}
					if (func == 0x03)
					{
						// Alpha numeric
						for (size_t i=1; i < 21; i++)
						{
							uint32_t bit = 0x80000000 & (word << i);
							msgWord >>= 1;

							msgWord |= (uint8_t)(0x40*(bit != 0));
							msgPos++;
							if (msgPos == 7)
							{
								if (msgWord != 0x04)
								{
									fprintf(stderr, "%c", msgWord);
									msgPos = 0;
									msgWord = 0;
								}
							}
						}
					}
				}
				else
				{
					if (word == 0x7A89C197)
					{
						// Idle
						messageFinish();
					}
					else
					{
						// Address word
						messageFinish();
						uint32_t addr = (word >> 13) & 0x3FFFF; 
						func = (word >> 11) & 0x03; 
						fprintf(stderr, "%02X: [%07u](%02X): ", (uint8_t)(dataCount), (unsigned)(8*addr+dataCount/2), func);
						messageBegin();
					}
				}
				dataCount++;
				if (dataCount == 0x10)
				{
					stateNext = Sync;
					dataCount = 0;
				}
				break;
	
		}
		pData += incr;
		remain -= incr;
		state = stateNext;
		numProcessed += incr;
		
	}
	return numProcessed;
	
}