./ MultiCS.r82 / twin.c
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
int twin_init()
{
	// Set up Serial Port
	if (serial_init(cfg.twin.serial.device,B115200 | CS8 | CLOCAL | CSTOPB | CREAD,&cfg.twin.serial.handle)==-1) {
		debugf(0, " Error initializing serial device '%s'\n", cfg.twin.serial.device);
		return -1;
	} else serial_purge(cfg.twin.serial.handle);
	debugf(0, " serial device '%s' opened.\n",cfg.twin.serial.device);
	return 0;
}

int twin_done()
{	
  serial_done(cfg.twin.serial.handle);
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

int twin_send(int chn, uint8_t* cw)
{
	uint8_t wbuf[32]; // write
	uint8_t rbuf[32]; // read
	int rlen;

	memset( cw, 0, 16);

	wbuf[0] = 7;
	wbuf[1] = 6;
	wbuf[2] = cfg.twin.chninfo.data[chn].deg>>8;
	wbuf[3] = cfg.twin.chninfo.data[chn].deg&0xff;
	wbuf[4] = cfg.twin.chninfo.data[chn].freq>>8;
	wbuf[5] = cfg.twin.chninfo.data[chn].freq&0xfc;
	wbuf[6] = cfg.twin.chninfo.data[chn].sid>>8;
	wbuf[7] = cfg.twin.chninfo.data[chn].sid&0xff;
	wbuf[8] = wbuf[0]^wbuf[1]^wbuf[2]^wbuf[3]^wbuf[4]^wbuf[5]^wbuf[6]^wbuf[7];

	serial_purge(cfg.twin.serial.handle);
	usleep(20000);

	serial_write(cfg.twin.serial.handle, wbuf, 9);
	usleep(20000);

	memset(rbuf,0,19);
	rlen = serial_readt(cfg.twin.serial.handle, 300, 1000, 19, rbuf);
	if ( (rlen!=19)||(rbuf[0]!=0xF7)||(rbuf[1]!=0x00)||(rbuf[2]!=0x16) )
	{
		char str[512];
		array2hex( rbuf, str, rlen);
		debugf(0, " ch %04x:%06x:%04x, Invalid packet from dongle (%s)\n", cfg.twin.chninfo.data[chn].caid, cfg.twin.chninfo.data[chn].prov, cfg.twin.chninfo.data[chn].sid, str );
		return 0;
	}
	rbuf[6] = rbuf[3]+rbuf[4]+rbuf[5];
	rbuf[10] = rbuf[7]+rbuf[8]+rbuf[9];
	rbuf[14] = rbuf[11]+rbuf[12]+rbuf[13];
	rbuf[18] = rbuf[15]+rbuf[16]+rbuf[17];
	memcpy(cw, rbuf+3, 16);
	return 16;
}
/*
struct channel_info_data *twin_getchannel(uint16_t caid, uint32_t prov, uint16_t sid)
{
	int i;
	for(i=0; i<cfg.twin.chninfo.count; i++)
		if ( (cfg.twin.chninfo.data[i].caid==caid)&&(cfg.twin.chninfo.data[i].prov==prov)&&(cfg.twin.chninfo.data[i].sid==sid) ) return &(cfg.twin.chninfo.data[i]);
	}
	return NULL;
}
*/
void *thread_twin()
{
	int chn;
	uint8_t cw[16];
	uint8_t nullcw[16] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";

	if ( twin_init()==-1 ) return NULL;

	while (1) {
		for(chn=0; chn<cfg.twin.chninfo.count; chn++) {
			uint32_t ticks = GetTickCount();
			if ( !cfg.twin.chninfo.data[chn].ecm.rtime ) continue;
			if ( (cfg.twin.chninfo.data[chn].ecm.rtime+2500) > ticks ) continue;
			if ( (cfg.twin.chninfo.data[chn].ecm.rtime+8000) < ticks ) continue;

			if ( !twin_send(chn,cw) ) {
 				if ( !twin_send(chn,cw) ) continue;
			}

			if ( !acceptcw(cw) ) {
				//cfg.twin.chninfo.data[chn].ecm.error++;
				//debugf(0, " ? chn %04x:%06x:%04x:%s invalid channel '%s'\n", cfg.twin.chninfo.data[chn].caid, cfg.twin.chninfo.data[chn].prov, cfg.twin.chninfo.data[chn].sid, cfg.twin.chninfo.data[chn].name);
				continue;
			}

			char str[512];
			array2hex( cw, str, 16);
			//debugf(0, "  chn %04x:%06x:%04x:%s\n", cfg.twin.chninfo.data[chn].caid, cfg.twin.chninfo.data[chn].prov, cfg.twin.chninfo.data[chn].sid, str);

//			pthread_mutex_lock(&cfg.lockchn);

			if (cfg.twin.chninfo.data[chn].ecm.rtime) { // maybe changed !!!
				if (cfg.twin.chninfo.data[chn].ecm.cwcycle==0x80) {
					if ( memcmp( cfg.twin.chninfo.data[chn].ecm.prevcw, cw, 8) && !memcmp( cfg.twin.chninfo.data[chn].ecm.prevcw+8, cw+8, 8) ) {
						debugf(0, " -> CW0 Cycle chn '%s' %04x:%06x:%04x:%s\n", cfg.twin.chninfo.data[chn].name, cfg.twin.chninfo.data[chn].caid, cfg.twin.chninfo.data[chn].prov, cfg.twin.chninfo.data[chn].sid, str);
						cfg.twin.chninfo.data[chn].ecm.rtime = 0;
						//cacheex_push( &cfg.twin.chninfo.data[chn], cw);
						memcpy( cfg.twin.chninfo.data[chn].ecm.cw, cw, 16);
					}
				}
				else if (cfg.twin.chninfo.data[chn].ecm.cwcycle==0x81) {
					if ( !memcmp( cfg.twin.chninfo.data[chn].ecm.prevcw, cw, 8) && memcmp( cfg.twin.chninfo.data[chn].ecm.prevcw+8, cw+8, 8) ) {
						debugf(0, " -> CW1 Cycle chn '%s' %04x:%06x:%04x:%s\n", cfg.twin.chninfo.data[chn].name, cfg.twin.chninfo.data[chn].caid, cfg.twin.chninfo.data[chn].prov, cfg.twin.chninfo.data[chn].sid, str);
						cfg.twin.chninfo.data[chn].ecm.rtime = 0;
						//cacheex_push( &cfg.twin.chninfo.data[chn], cw);
						memcpy( cfg.twin.chninfo.data[chn].ecm.cw, cw, 16);
					}
				}
			}

//			pthread_mutex_unlock(&cfg.lockchn);
		}
	}

	twin_done();

	return NULL;
}