//
// sift.c - Serial Interface For Topfield
//

#include <string.h>
#include <stdlib.h>
#include "TAP.H"

#define SIFT_VER "SIFT (command) V0.20"
#define ID_SIFT_TAP 0x84349878         // hopefully uniq at tap world 

TAP_ID( ID_SIFT_TAP );
TAP_PROGRAM_NAME( SIFT_VER );
TAP_AUTHOR_NAME("By Tapani Rintala 2006");
TAP_DESCRIPTION("Serial Interface For Topfield");
TAP_ETCINFO(__DATE__);

#define MC 100 // max command line length
#define TV 0   // always TV, radio support will done maybe later

// #define TRUE 1
// #define FALSE 0
// #define EXIT -1

static int cmd_mode;      // if active sift command line mode = TRUE
static char LFS[5];       // linefeed string


//dirty convert numeric asc to int (atoi seems to be broken at c library)
int asc2int(char *s)
{
  int i=0,j=1;
  char *p;
  
  p=(char *)s;
  while (*p != 0) p++;
  do {
    p = p-1;
    if (*p < '0' || *p > '9') return 0;
    i = i + (j * (*p - '0'));
    j = j * 10;
  } while (p != s);
  return i;
}


//pause for a while , i dont know does TAP_delay call systeproc ?
//  pause will be called before produce output to make sure that
//  client program is ready to receive data
int pause()
{
  dword tm=0;

  tm = TAP_GetTick() + 50; 
  while (TAP_GetTick() < tm) 
    TAP_SystemProc(); 
  
  return 0;
}


//print something before data listing to make easier to parse sift output
int start()
{
  TAP_PrintSys("START%s", LFS);
  return 0;
}

//print something after data listing to make easier to parse sift output
int done()
{
  TAP_PrintSys("READY%s", LFS);
  return 0;
}


//produce epg list from selected channel
int epg_list( int svcNum )
{
  int i, eventNum;
  TYPE_TapEvent *evtInfo = 0, *ei;
  TYPE_TapChInfo chi;
  word  year;
  byte  month, day, weekDay;

  pause();  
  start();
  svcNum--;
  TAP_Channel_GetInfo(TV, svcNum, &chi);
  evtInfo = TAP_GetEvent( TV, svcNum, &eventNum );
  
  TAP_PrintSys("EPGLIST for channel:%i:%s%s", svcNum+1, chi.chName, LFS);
  for( i=0; i < eventNum; i++ ) {
    ei = &evtInfo[i];
    TAP_ExtractMjd( ei->startTime>>16, &year, &month, &day, &weekDay) ;
    TAP_PrintSys("%04d%02d%02d%02d%02d|%04d|%s|%s%s", 
		 year, month, day,
		 (ei->startTime&0xff00)>>8, (ei->startTime&0xff),
		 (((ei->duration&0xff00)>>8) * 60 + (ei->duration&0xff)),
		 ei->eventName,       
		 ei->description,     
		 LFS);
  }  
  if( evtInfo ) TAP_MemFree( evtInfo );
  done();
  return 0;
}


//delete timer 
int delete_timer( int timernum )
{
  int tt;
  
  pause();
  start();

  tt = TAP_Timer_GetTotalNum();
  if (timernum >= 1 && timernum <= tt) {
    if (TAP_Timer_Delete( timernum - 1 ) == TRUE)
      TAP_PrintSys("deletetimer:%i:done%s", timernum, LFS);
    else
      TAP_PrintSys("deletetimer:%i:notdone%s", timernum, LFS);
  }
  else
    TAP_PrintSys("deletetimer:%i:indexerror%s", timernum, LFS);
  done();
  return 0;
}


//list current timers
int list_timer(void)
{
  int i;
  int tt;
  word  year;
  byte  month, day, weekDay;
  TYPE_TimerInfo ti;
  
  pause();
  start();

  tt = TAP_Timer_GetTotalNum();
  TAP_PrintSys("TotalOfTimers=%d%s", tt, LFS);
  for( i=0; i < tt; i++ ) {
    TAP_PrintSys("----------------------------------------%s", LFS);
    TAP_Timer_GetInfo( i, &ti );
    TAP_PrintSys("RecordNumber=%d%s", i+1, LFS);
    TAP_PrintSys("RecordingState=%s%s", 
		 (char *)(ti.isRec==0?"TIMER":"ACTIVE"), LFS);
    TAP_PrintSys("RecordingTuner=%d%s", (int)(ti.tuner + 1), LFS);
    TAP_PrintSys("ChannelType=%s%s", 
		 (char *)(ti.svcType==0?"TV":"RADIO"), LFS);
    TAP_PrintSys("ChannelNumber=%d%s", (int)(ti.svcNum+1), LFS);
    TAP_PrintSys("ReservationType=");
    switch (ti.reservationType) {
    case RESERVE_TYPE_Onetime: TAP_PrintSys("OneTime"); break;
    case RESERVE_TYPE_Everyday: TAP_PrintSys("EveryDay"); break;
    case RESERVE_TYPE_EveryWeekend: TAP_PrintSys("EveryWeekEnd"); break;
    case RESERVE_TYPE_Weekly:TAP_PrintSys("Weekly"); break;
    case RESERVE_TYPE_WeekDay:TAP_PrintSys("Weekday"); break;
    case N_ReserveType:TAP_PrintSys("NoReserveType"); break;
    }
    TAP_PrintSys("%s", LFS);
    TAP_PrintSys("FileName=%s%s", ti.fileName, LFS);
    TAP_PrintSys("NameWithIndex=%s%s", 
		 (char *)(ti.nameFix==0?"NO":"YES"), LFS);
    TAP_ExtractMjd( ti.startTime>>16, &year, &month, &day, &weekDay) ;
    TAP_PrintSys("StartTime=%04d%02d%02d%02d%02d%s",
		 year, month, day,
		 (ti.startTime&0xff00)>>8, (ti.startTime&0xff), LFS);
    TAP_PrintSys("Duration=%d%s", ti.duration, LFS);
  }
  done();
  return 0;
}

// add a new timer
// tuner|channel|freq|length|yyyy|mm|dd|hh|mm|name
int add_timer( char *ts )
{
  int f, mjd = 0;
  word  yyyy = 0;
  byte  mm = 0, dd = 0, hh = 0, mi = 0, endf=0;
  char *p, *pp;
  TYPE_TimerInfo ti;
  
  p = (char *)ts;
  pp = (char *)p;
  f = 1;
  ti.isRec = 1;
  ti.svcType = TV;
  ti.nameFix = 1;
  do {
    p++;
    if (*p == '|' || *p == 0) {
      if (*p == 0) endf = 1;
      *p = 0;
      switch(f++) {
      case 1: //tuner
	ti.tuner = asc2int( pp )-1; break;
      case 2: //channel
	ti.svcNum = asc2int( pp )-1; break;
      case 3: //freq = revervationType
	ti.reservationType = asc2int( pp )-1; break;
	//      case 4: //fixedname or index
	//ti.nameFix = asc2int( pp ); break;
      case 4: //duration
	ti.duration = asc2int( pp ); break;
      case 5: //yyyy
	yyyy = asc2int( pp ); break;
      case 6: //mm
	mm = asc2int( pp ); break;
      case 7: //dd
	dd = asc2int( pp ); break;
      case 8: //hh
	hh = asc2int( pp ); break;
      case 9: //mi
	mi = asc2int( pp ); break;
      case 10: //name
	strcpy(ti.fileName, pp); break;
      }
      p++;
      pp = (char *)p;
    }
  } while(!endf && f < 11);
  
  mjd = TAP_MakeMjd(yyyy, mm, dd);
  ti.startTime = (mjd << 16) | (hh << 8) | mi;

  pause();
  start();
  if (f == 11) {
    if (TAP_Timer_Add( &ti ) == 0)
      TAP_PrintSys("addtimer:done%s", LFS);
    else
      TAP_PrintSys("addtimer:error%s", LFS);
  }
  else
    TAP_PrintSys("addtimer:fieldcounterror%s", LFS);

  done();
  return 0;
}


//produce simple status listing
int info_list()
{
  word mjd, yy;
  dword t1, t2, t3;
  byte hh, mm, ss, mmm, ddd, wday, z;
  TYPE_File tf, *tfp;

  pause();
  start();

  TAP_PrintSys("version:%s%s", SIFT_VER, LFS);
  TAP_GetTime(&mjd, &hh, &mm, &ss);
  TAP_ExtractMjd( mjd, &yy, &mmm, &ddd, &wday);  
  TAP_PrintSys("system-time:%d.%d.%d %02d:%02d%s",yy,mmm,ddd,hh,mm, LFS);
  
  t1 = (TAP_GetTick() / (100 * 60 * 60));
  TAP_PrintSys("uptime-hours:%d%s", t1, LFS);
  
  TAP_MemInfo(&t1, &t2, &t3);
  TAP_PrintSys("heapsize     :%d%s", t1,  LFS);
  TAP_PrintSys("freeheapsize :%d%s", t2,  LFS);
  TAP_PrintSys("availheapsize:%d%s", t3,  LFS);
  
  t1 = (TAP_Hdd_TotalSize() / 1000);
  TAP_PrintSys("disksize-G:%d%s", t1,  LFS);
  
  t1 = (TAP_Hdd_FreeSize() / 1000);
  TAP_PrintSys("diskfree-G:%d%s", t1,  LFS);
  
  //create listing from default save directory
  TAP_Hdd_ChangeDir("/DataFiles");
  z = TAP_Hdd_FindFirst(&tf);
  while (z > 0) {
    if (tf.attr == ATTR_TS) {
      tfp = TAP_Hdd_Fopen( tf.name );
      t1 = 0;
      if (tfp) {
	t1 = (TAP_Hdd_Flen( tfp ) / 1000 / 1000);
	if (tfp) TAP_Hdd_Fclose( tfp );
      }
      TAP_ExtractMjd( tf.mjd, &yy, &mmm, &ddd, &wday);  
      TAP_PrintSys("filedata:%04d.%02d.%02d %02d.%02d:%5d:Mb:%s%s",
		   yy, mmm, ddd, tf.hour, tf.min, t1, tf.name, LFS);
    }
    z = TAP_Hdd_FindNext(&tf);
  }
  done();
  return 0;
}


//fast help
int print_help()
{
  TAP_PrintSys("a:tuner|channel|freq|length|yyyy|mm|dd|hh|mi|name%s",
	       LFS);
  TAP_PrintSys("  tuner: 1 or 2%s", LFS);
  TAP_PrintSys("  frequency: 1=OneTime,2=EveryDay,3=EveryWeekEnd%s", LFS);
  TAP_PrintSys("             4=Weekly,5=Weekday,6=NoType%s", LFS);
  TAP_PrintSys("l            List timers%s", LFS);
  TAP_PrintSys("i            Info listing%s", LFS);
  TAP_PrintSys("d<number>    Delete timer%s", LFS);
  TAP_PrintSys("e<channel    Epg data list%s", LFS);
  return 0;
}


//comand parser
void command_loop()
{
  int i, val;
  char c[MC];
  
  i = 0;
  TAP_PrintSys("SIFT>");    
  
  while ( TRUE )  {
    while (TAP_KbHit()) {
      val = TAP_GetCh();
      if (val == 10) val = 0; //suppose enter is 13
      if (val == '#') {
	TAP_PrintSys("%sLeaving Sift command mode. '*' will activate.%s", 
		     LFS, LFS);
	cmd_mode = FALSE;
	return;
      }
      if (val == 13) {
	TAP_PrintSys("%s", LFS);
	c[i] = 0;
	switch (c[0]) {
	case 'l': list_timer(); break;
	case 'e': if (i > 1) epg_list( asc2int(c+1) ); break;
	case 'd': if (i > 1) delete_timer( asc2int(c+1) ); break;
	case 'a': if (i > 2) add_timer( (c+2) ); break;
	case 'i': info_list(); break;
	case 'h': print_help(); break;
	}
	i = 0;
	val = 0;
	TAP_PrintSys("SIFT>");    
      }
      if ((val > 0) && (i < (MC-2))) {
	c[i++] = val; 
	TAP_PutByte((byte)val);
      }
    }
    TAP_SystemProc(); // let it roll 
  }
}


//this get call when event available 
dword TAP_EventHandler( word event, dword param1, dword param2 )
{
  if( event == EVT_UART ) {
    if (param1 == '!') {
      TAP_PrintSys("%sGoodbye.%s", LFS, LFS);    
      TAP_Exit();
    }
    if (param1 == '*') {
      if (cmd_mode != TRUE) {
	cmd_mode = TRUE;
	command_loop();
	return 0;
      }
    }
    if (cmd_mode == TRUE)
      return 0;
  }
  //this event was not for us 
  return param1;
}


// mainprogram
int TAP_Main(void)
{
  TAP_SetBaudRate( 115200 ); 
  LFS[0]=10; LFS[1]=0; // set linefeed string
  
  cmd_mode = FALSE;

  TAP_PrintSys("%s%s[ %s ]%s", LFS, LFS, SIFT_VER, LFS);
  TAP_PrintSys("push '*' to go command mode%s", LFS);
  
  // trs - mode
  return 1;
}
