/**************************************************************************
RDS analysis functions

Copyright (C) 1997-2019 AudioScience, Inc. All rights reserved.

This software is provided 'as-is', without any express or implied warranty.
In no event will AudioScience Inc. be held liable for any damages arising
from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
   claim that you wrote the original software. If you use this software
   in a product, an acknowledgment in the product documentation would be
   appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
   misrepresented as being the original software.
3. This copyright notice and list of conditions may not be altered or removed
   from any source distribution.

AudioScience, Inc. <support@audioscience.com>

( This license is GPL compatible see http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses )

***************************************************************************/

#include <stdlib.h>
#include <string.h>

#include "hpirds.h"

#ifdef HPI_OS_DSP_C6000
void AxHPIAssert(char *message, int value);
#endif

/**

\param fieldPI PI - Program identification. PI is a two byte number which identifies the country,
coverage area and service. It can be used by the control microprocessor but is not normally
intended for display. A change in PI code causes the initialisation of all RDS data as it
indicates that the radio has been retuned. This application also facilitates the display
of the current PI code.

\param fieldPTY PTY - Program type. PTY is a 5-bit number which indicates the current program
type. At present 16 of these types are defined. Examples include "no programme type", "Current affairs" and 'Pop music",


*/
struct HPI_RDS_DATA_PRESERVE {
	enum eHPI_RDS_type eType;	///< Type of the bitstream to process.
	int rt_ab_flag;

	char lastGroup[8];	///< Last block returned from hardware.
	char lastBLER[4];	///< Last block error rate returned from hardware. A value >= 6 means uncorrected errors.
};

struct HPI_RDS_DATA {

	unsigned int fieldGroup;	///< Number of the last group to be analyzed.
	char fieldGroupVersion;	///< Version (either 'A' or 'B) of the last group to be analyzed.
	// RDS specific fields follow.
	unsigned short fieldPI;	///< PI - Program identification.
	unsigned char fieldPTY;	///< PTY - Program type

	unsigned int ps_ready;	///< Indicates PS text is complete.
	unsigned int ps_changed;	///< Indicates PS text has changed.
	unsigned int ps_updated;	///< Indicates PS text segment was received.
	unsigned int ps_rx_seg_bitmap;	///< Bitmap of received PS segments.
	char ps_text[9];	///< PS - Program service name. The name of the station. Extra char for null termination.
	unsigned int rt_ready;	///< Indicates RT text is complete.
	unsigned int rt_changed;	///< Indicates RT text has changed.
	unsigned int rt_updated;	///< Indicates RT text segment was received.
	unsigned int rt_ab_flag;	///< RT text A/B flag. 0=A, 1=B.
	unsigned int rt_rx_seg_bitmap;	///< Bitmap of expected RT segments.
	unsigned int rt_exp_seg_bitmap;	///< Bitmap of received RT segments.
	char rt_text[65];	///< RT - Radio text - up to 65 characters. Extra char for null termination.

	///< CT - clock time and date
	///< AF - alternative frequencies
	unsigned int flagTA;	///< TA - Traffic annoucement flag. Is set during traffic announcemnet.
	unsigned int flagTP;	///< TP - Traffic program flag. 1 indicates this transmitter carries traffic announcements.
	unsigned int flagMS;	///< MS - Music/speech switch. Single bit indicationg speech or music.
	unsigned int fieldDI;	///< DI - decoder identification. 4 bits indicating mono,stereo, binaural).
	unsigned int fieldPIN[2];	///< PIN - program item number.
	///< EON - enhanced other networks
	///< TDC - transparent data channel
	///< INH - In-house data

	struct HPI_RDS_DATA_PRESERVE d;
};

#define PS_EXPECTED_SEG_BITMAP (0x0F)

#ifndef DISABLE_PRAGMA_PACK1
#pragma pack(push, 1)
#endif

struct group_0A {
	unsigned short pi_code;
	unsigned short flags;
	unsigned char alt_freq[2];
	char ps_segment[2];
};

struct group_2A {
	unsigned short pi_code;
	unsigned short flags;
	char rt_segment[4];
};

#ifndef DISABLE_PRAGMA_PACK1
#pragma pack(pop)
#endif

static char *szERROR = "HANDLE ERROR";

#define MAX_PTY 32
static char *szRDS_PTY_RDS[2][MAX_PTY] = {
{ /* RDS codes (EU) */
"No program type or undefined",	//0
"News",
"Current affairs",
"Information",
"Sport",
"Education",		// 5
"Drama",
"Culture",
"Science",
"Varied",
"Pop Music",		//10
"Rock Music",
"M.O.R. Music",
"Light classical",
"Serious classical",
"Other Music",		//15
"Weather",
"Finance",
"Children's programmes",
"Social Affairs",
"Religion",		//20
"Phone In",
"Travel",
"Leisure",
"Jazz Music",
"Country Music",	//25
"National Music",
"Oldies Music",
"Folk Music",
"Documentary",
"Alarm Test",		//30
"Alarm"},
{ /* RBDS (USA) and HD Radio PSD (see DSPappA_Command_and_Data07192007.pdf) */
"No program type or undefined",	//0
"News",
"Information",
"Sports",
"Talk",
"Rock",			//5
"Classic Rock",
"Adult Hits",
"Soft Rock",
"Top 40",
"Country",		//10
"Oldies",
"Soft",
"Nostalgia",
"Jazz",
"Classical",		// 15
"Rhythm and Blues",
"Soft Rhythm and Blues",
"Foreign Language",
"Religious Music",
"Religious Talk",	//20
"Personality",
"Public",
"College",
"Unassigned",
"Unassigned",		//25
"Unassigned",
"Unassigned",
"Unassigned",
"Weather",
"Emergency Test",	//30
"Emergency"
}
};

static char szRBDS_Unassigned[]="Unassigned";
static char szRBDS_40[]=	"Weather B";
static char szRBDS_41[]=	"Traffic A";
static char szRBDS_42[]=	"Traffic B";
static char szRBDS_43[]=	"Traffic C";
static char szRBDS_49[]=	"Government";
static char szRBDS_4A[]=	"Emergency B";
static char szRBDS_4B[]=	"Emergency C";
static char szRBDS_4C[]=	"Special Reading Services";
static char szRBDS_53[]=	"Private Services A";
static char szRBDS_54[]=	"Private Services B";
static char szRBDS_55[]=	"Private Services C";

static char szRDS_PTY_ERROR[] = "Calling error";

static void resetRDS(struct HPI_RDS_DATA *pD);
static void processBlock1(struct HPI_RDS_DATA *pD);
static void processBlock2(struct HPI_RDS_DATA *pD);
static void processGroup0A(struct HPI_RDS_DATA *pD);
static void processGroup0B(struct HPI_RDS_DATA *pD);
static void processGroup2A(struct HPI_RDS_DATA *pD);

/*--------------------------------------------------------------------------------------*/
HPI_RDS_HANDLE HPI_RDS_Create(enum eHPI_RDS_type eType)
{
	struct HPI_RDS_DATA *h = malloc(sizeof(struct HPI_RDS_DATA));

	resetRDS(h);
	h->d.eType = eType;

	return (HPI_RDS_HANDLE) h;
}

/*--------------------------------------------------------------------------------------*/
void HPI_RDS_Delete(HPI_RDS_HANDLE h)
{
	free(h);
}

/*--------------------------------------------------------------------------------------*/
void HPI_RDS_Clear(HPI_RDS_HANDLE h)
{
	struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;
	const enum eHPI_RDS_type eType = pD->d.eType;
	resetRDS(h);
	pD->d.eType = eType;
}

/*--------------------------------------------------------------------------------------*/
enum eHPI_RDS_type HPI_RDS_Get_RdsType(HPI_RDS_HANDLE h)
{
	const struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;
	return pD->d.eType;
}

/*--------------------------------------------------------------------------------------*/
enum eHPI_RDS_type HPI_RDS_Set_RdsType(HPI_RDS_HANDLE h, enum eHPI_RDS_type eType)
{
	struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;
	const enum eHPI_RDS_type prev_eType = pD->d.eType;
	resetRDS(h);
	pD->d.eType = eType;
	return prev_eType;
}

/*--------------------------------------------------------------------------------------*/
enum eHPI_RDS_errors HPI_RDS_AnalyzeGroup(HPI_RDS_HANDLE h,
						  const char *pData,
						  const unsigned int nSize)
{
	enum eHPI_RDS_errors err = HPI_RDS_ERROR_NOERROR;
	struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;

	if (h == NULL)
		return HPI_RDS_ERROR_HANDLE;
	if (nSize != 12)
		return HPI_RDS_ERROR_INVALID_DATASIZE;

	// copy the blcok into the reference section
	memcpy(pD->d.lastGroup, pData, 8);
	memcpy(pD->d.lastBLER, &pData[8], 4);

	if (pD->d.lastBLER[0] >= 6) {
		err = HPI_RDS_ERROR_BLOCK_DATA;
	} else {
		processBlock1(pD);
	}

	if (pD->d.lastBLER[1] >= 6) {
		/* if block 2 is unreliable we cannot extract the group type so exit here */
		return HPI_RDS_ERROR_BLOCK_DATA;
	} else {
		processBlock2(pD);
	}

	if ((pD->d.lastBLER[2] >= 6) || (pD->d.lastBLER[3] >= 6)) {
		err = HPI_RDS_ERROR_BLOCK_DATA;
	} else if ((pD->fieldGroup == 0) && pD->fieldGroupVersion == 'A') {	// group 0A
		processGroup0A(pD);
	} else if ((pD->fieldGroup == 0) && pD->fieldGroupVersion == 'B') {	// group 0B
		processGroup0B(pD);
	} else if ((pD->fieldGroup == 2) && pD->fieldGroupVersion == 'A')	{	// group 2A
		processGroup2A(pD);
	} else {
		//printf("%d%c\n", pD->fieldGroup, pD->fieldGroupVersion);
		/* do not override an error if already present */
		if (!err) {
			err = HPI_RDS_ERROR_UNKNOWN_GROUP;
		}
	}

	return err;
}

/*--------------------------------------------------------------------------------------*/
enum eHPI_RDS_errors HPI_RDS_Get_BlockErrorCounts(HPI_RDS_HANDLE h, unsigned int
							  *uBlock0, unsigned int
							  *uBlock1, unsigned int
							  *uBlock2, unsigned int
							  *uBlock3)
{
	const struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;

	if (h == NULL)
		return HPI_RDS_ERROR_HANDLE;
	if (uBlock0)
		*uBlock0 = (unsigned char)pD->d.lastBLER[0];
	if (uBlock1)
		*uBlock1 = (unsigned char)pD->d.lastBLER[1];
	if (uBlock2)
		*uBlock2 = (unsigned char)pD->d.lastBLER[2];
	if (uBlock3)
		*uBlock3 = (unsigned char)pD->d.lastBLER[3];

	return HPI_RDS_ERROR_NOERROR;
}

/*--------------------------------------------------------------------------------------*/
unsigned int HPI_RDS_Get_GroupType(HPI_RDS_HANDLE h)
{
	const struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;
	if (h == NULL)
		return HPI_ERROR_INVALID_OBJ;
	return pD->fieldGroup;
}

/*--------------------------------------------------------------------------------------*/
char HPI_RDS_Get_GroupVersion(HPI_RDS_HANDLE h)
{
	const struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;
	if (h == NULL)
		return HPI_ERROR_INVALID_OBJ;
	return pD->fieldGroupVersion;
}

/*--------------------------------------------------------------------------------------*/
unsigned int HPI_RDS_Get_PS_Ready(HPI_RDS_HANDLE h	///< A previously allocated HPIRDS handle.
    )
{
	const struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;
	if (h == NULL)
		return HPI_ERROR_INVALID_OBJ;
	return pD->ps_ready;
}

/*--------------------------------------------------------------------------------------*/
HPI_RDS_STRING HPI_RDS_Get_PS(HPI_RDS_HANDLE h)
{
	struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;
	if (h == NULL)
		return szERROR;
	pD->ps_ready = 0;
	pD->ps_changed = 0;
	pD->ps_updated = 0;
	return pD->ps_text;
}

/*--------------------------------------------------------------------------------------*/
unsigned int HPI_RDS_Get_RT_Ready(HPI_RDS_HANDLE h	///< A previously allocated HPIRDS handle.
    )
{
	const struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;
	if (h == NULL)
		return HPI_ERROR_INVALID_OBJ;
	return pD->rt_ready;
}

/*--------------------------------------------------------------------------------------*/
void HPI_RDS_Set_RT_Threshold(HPI_RDS_HANDLE h, unsigned int nCount)
{
	/* NOP */
}

/*--------------------------------------------------------------------------------------*/
HPI_RDS_STRING HPI_RDS_Get_RT(HPI_RDS_HANDLE h	///< A previously allocated HPIRDS handle.
    )
{
	struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;
	if (h == NULL)
		return szERROR;
	pD->rt_ready = 0;
	pD->rt_changed = 0;
	pD->rt_updated = 0;
	return pD->rt_text;
}

/*--------------------------------------------------------------------------------------*/
unsigned short HPI_RDS_Get_PI(HPI_RDS_HANDLE h	///< A previously allocated HPIRDS handle.
    )
{
	const struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;
	if (h == NULL)
		return HPI_ERROR_INVALID_OBJ;
	return pD->fieldPI;
}

/*--------------------------------------------------------------------------------------*/
unsigned char HPI_RDS_Get_PTY(HPI_RDS_HANDLE h	///< A previously allocated HPIRDS handle.
    )
{
	const struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;
	if (h == NULL)
		return HPI_ERROR_INVALID_OBJ;
	return pD->fieldPTY;
}

/*--------------------------------------------------------------------------------------*/
HPI_RDS_STRING HPI_RDS_Get_PTY_Text(HPI_RDS_HANDLE h	///< A previously allocated HPIRDS handle.
    )
{
	const struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;
	if (h == NULL)
		return szERROR;

	return HPI_RDS_Get_PTY_Translate(pD->d.eType,pD->fieldPTY);
}
/*--------------------------------------------------------------------------------------*/
HPI_RDS_STRING HPI_RDS_Get_PTY_Translate(enum eHPI_RDS_type eType, ///< Data type.
					    unsigned int uPTY	///< PTY code.
    )
{
	if ((int)eType>=2)	// error check
		return szRDS_PTY_ERROR;
	else {
		if ( (eType==HPI_RDS_DATATYPE_RDS) && (uPTY >= MAX_PTY) )
			return szRDS_PTY_ERROR;
		if(uPTY<32)
			return szRDS_PTY_RDS[eType][uPTY];
		switch(uPTY)
		{
		case 0x40: return szRBDS_40;
		case 0x41: return szRBDS_41;
		case 0x42: return szRBDS_42;
		case 0x43: return szRBDS_43;
		case 0x49: return szRBDS_49;
		case 0x4A: return szRBDS_4A;
		case 0x4B: return szRBDS_4B;
		case 0x4C: return szRBDS_4C;
		case 0x53: return szRBDS_53;
		case 0x54: return szRBDS_54;
		case 0x55: return szRBDS_55;
		default: return szRBDS_Unassigned;
		}
	}
}
/*--------------------------------------------------------------------------------------*/
unsigned int HPI_RDS_Get_TP(HPI_RDS_HANDLE h	///< A previously allocated HPIRDS handle.
    )
{
	const struct HPI_RDS_DATA *pD = (struct HPI_RDS_DATA *)h;
	if (h == NULL)
		return HPI_ERROR_INVALID_OBJ;
	return pD->flagTP;
}

/**************************** PRIVATE *************************************/

/*--------------------------------------------------------------------------------------*/
/** Reset the RDS structure
  */
static void resetRDS(struct HPI_RDS_DATA *pD)
{
	const enum eHPI_RDS_type eType = pD->d.eType;
	memset(pD, 0, sizeof(struct HPI_RDS_DATA));
	memset(&pD->ps_text, 0x20, sizeof(pD->ps_text)-1);
	memset(&pD->rt_text, 0x20, sizeof(pD->rt_text)-1);
	pD->d.eType = eType;
	pD->d.rt_ab_flag = -1;
	pD->rt_exp_seg_bitmap = 0xFFFF;
}

/*--------------------------------------------------------------------------------------*/
/** Process block 1 is common processing that extracts the PI code.
  */
static void processBlock1(struct HPI_RDS_DATA *pD)
{
	const struct group_0A *p_0A = (struct group_0A *)pD->d.lastGroup;
	const unsigned short uPI = p_0A->pi_code;
	struct HPI_RDS_DATA_PRESERVE localCopy;

	// ---------------------  PI --------------------------
	// if PI has changed, we need to reset some things
	if (uPI != pD->fieldPI) {
		// Save some values for later.
		localCopy = pD->d;

		// can't just reset everything because we will lose the data we are processing !
		resetRDS(pD);

		// restore saved values that we need later.
		pD->d = localCopy;
		pD->fieldPI = uPI;
	}
}

/*--------------------------------------------------------------------------------------*/
/** Process block 2 is common processing that extracts common portions of Block 2.
  * The portions extracted are:<br>
  * Group number<br>
  * Group version (sometimes called group type) - 'A' or 'B'<br>
  * PTY code.<br>
  *
  */
static void processBlock2(struct HPI_RDS_DATA *pD)
{
	const struct group_0A *p_0A = (struct group_0A *)pD->d.lastGroup;

	// --------------------- Group number and type --------------------------
	pD->fieldGroup = p_0A->flags >> 12;
	if ((p_0A->flags >> 11) & 1)
		pD->fieldGroupVersion = 'B';
	else
		pD->fieldGroupVersion = 'A';

	pD->fieldPTY = (p_0A->flags >> 5) & 0x1f;

	// --------------------- TP --------------------------
	pD->flagTP = (p_0A->flags >> 10) & 1;

}

/*--------------------------------------------------------------------------------------*/
/** Process group 0A
  */
static void processGroup0A(struct HPI_RDS_DATA *pD)
{
	const struct group_0A *p_0A = (struct group_0A *)pD->d.lastGroup;
	const int seg_index = p_0A->flags & 0x3;
	const int char_index = seg_index * 2;
	const int rx_seg_bitmap = pD->ps_rx_seg_bitmap;
	char text_segment[2];
	int i;

	pD->ps_updated = 1;

	/* TODO: handle code page selectors */
	text_segment[0] = p_0A->ps_segment[1];
	text_segment[1] = p_0A->ps_segment[0];

	for (i=0; i < sizeof(text_segment); i++) {
		const char c = text_segment[i];
		/*
			Skip code page selectors
		*/
		/* Code page 1 selector is the pair 0x0F, 0x0F */
		/* Code page 2 selector is the pair 0x0E, 0x0E */
		/* Code page 3 selector is the pair 0x1B, 0x6E */
		if (c == 0x0E || c == 0x0F || c == 0x1B) {
			/* skip the next character too */
			i++;
			continue;
		}
		if (pD->ps_text[char_index+i] != c) {
			pD->ps_changed = 1;
		}
		pD->ps_text[char_index+i] = c;
		pD->ps_rx_seg_bitmap |= (1 << seg_index);
	}

	if (PS_EXPECTED_SEG_BITMAP == pD->ps_rx_seg_bitmap) {
		if ((rx_seg_bitmap != pD->ps_rx_seg_bitmap) || pD->ps_changed) {
			pD->ps_ready = 1;
		}
	}

/*
	printf("ps_char_index = %d, uPScount = %d, chars (%c%c) (0x%02X,0x%02X)\n",
		ps_char_index,
		pD->uPScount,
		pD->ps_text[ps_char_index],
		pD->ps_text[ps_char_index+1],
		pD->ps_text[ps_char_index],
		pD->ps_text[ps_char_index+1]
		);
*/

}

/** Process group 0B
  */
static void processGroup0B(struct HPI_RDS_DATA *pD)
{
	// Use 0A for the moment.
	processGroup0A(pD);
}

static void extract_2A_text_segment(char *dst, int ofs, struct group_2A *rds_data) {
	/* extract radio text characters from the RT segment in the data group */
	dst[ofs]   = rds_data->rt_segment[1];
	dst[ofs+1] = rds_data->rt_segment[0];
	dst[ofs+2] = rds_data->rt_segment[3];
	dst[ofs+3] = rds_data->rt_segment[2];
}

/*--------------------------------------------------------------------------------------*/
/** Process group 2A
  *
  * This routine is complicated by the fact that we want to support transmitters
  * that do not completely follow the RDS specification.
  *
  * There are basically 3 possible paths below that could produce a RT output:
  *
  * 1) The A/B flag has toggled and required counts have been exceed. In this case
  * we are currently processing a different flag than the one with output RT.
  *
  * 2) The A/B has not toggled but the required counts have been exceeded. In this
  * case we are processing the same flag as the one with the output RT.
  *
  * In both cases counting should have been from index 0.
  */
static void processGroup2A(struct HPI_RDS_DATA *pD)
{
	struct group_2A *p_2A = (struct group_2A *)pD->d.lastGroup;
	const int rx_seg_bitmap = pD->rt_rx_seg_bitmap;
	const int seg_index = p_2A->flags & 0xF;
	const int char_index = seg_index * 4;
	// check the RT text flag
	const int ab_flag = (p_2A->flags >> 4) & 0x1;

	pD->rt_updated = 1;

	// We have an A/B toggle
	if (ab_flag != pD->d.rt_ab_flag) {
		/* wipe text on A/B toggle */
		memset(pD->rt_text, 0x20, sizeof(pD->rt_text)-1);
		pD->rt_changed = 1;
		pD->rt_ready = 0;
		pD->rt_exp_seg_bitmap = 0xFFFF;
		pD->rt_rx_seg_bitmap = 0;
	}
	pD->d.rt_ab_flag = ab_flag;

	{
		char text_segment[4];
		int i;
		
		extract_2A_text_segment(text_segment, 0, p_2A);

		/* TODO: handle code page selectors */
		for (i=0; i < sizeof(text_segment); i++) {
			const char c = text_segment[i];
			/*
				Skip code page selectors
			*/
			/* Code page 1 selector is the pair 0x0F, 0x0F */
			/* Code page 2 selector is the pair 0x0E, 0x0E */
			/* Code page 3 selector is the pair 0x1B, 0x6E */
			if (c == 0x0E || c == 0x0F || c == 0x1B) {
				/* skip the next character too */
				i++;
				continue;
			}
			if (pD->rt_text[char_index+i] != c) {
				pD->rt_changed = 1;
			}
			pD->rt_text[char_index+i] = c;
			pD->rt_rx_seg_bitmap |= (1 << seg_index);

			if (c == 0x0D) {
				const size_t rt_len = char_index+i+1;
				const size_t available_len = sizeof(pD->rt_text)-1;
				if (available_len-rt_len > 0) {
					memset(pD->rt_text+rt_len, 0x20, available_len-rt_len);
				}
				/* update expected segment mask to include all segments up to this one */
				pD->rt_exp_seg_bitmap = (1<<(seg_index+1))-1;
				/* wipe bits corresponding to non-expected segments */
				pD->rt_rx_seg_bitmap &= pD->rt_exp_seg_bitmap;
				break;
			}
		}
	}

	if (pD->rt_exp_seg_bitmap == pD->rt_rx_seg_bitmap) {
		if (rx_seg_bitmap != pD->rt_rx_seg_bitmap || pD->rt_changed) {
			pD->rt_ready = 1;
		}
	}

/* *
	printf("[%d] RTIndex = %d, d.uRTcount = %d, chars (%c%c%c%c) (0x%02X,0x%02X,0x%02X,0x%02X)\n",
		ab_flag,
		rt_char_index,
		pD->d.uRTcount[ab_flag],
		pD->rt_text[ab_flag][rt_char_index],
		pD->rt_text[ab_flag][rt_char_index+1],
		pD->rt_text[ab_flag][rt_char_index+2],
		pD->rt_text[ab_flag][rt_char_index+3],
		pD->rt_text[ab_flag][rt_char_index],
		pD->d.fieldRTbuild[ab_flag][rt_char_index+1],
		pD->d.fieldRTbuild[ab_flag][rt_char_index+2],
		pD->d.fieldRTbuild[ab_flag][rt_char_index+3]
		);
* */

}
