/*
    XDemo29: Reads information from text files(advance)
    Compiler: BC++ 3.1
    Compile mode: large
    Project: user.c
             v7000.c
             vModbus.c           [after vcom3002.lib]
             ..\Lib\7186EL.Lib
             ..\Lib\tcp_dm32.lib
             ..\Lib\VcomNNNN.Lib, with NNNN being the lib file's version.

    19 [KeyName] [Type]
    KeyName: the item that programs want to read out 
             its setting form a text file(config.dat)
             You must position the KeyName after one * character.
             Type:i --> for reading long integer(Dec) 
        s --> for reading string (20 bytes max.)
        f --> for reading float value
        h --> for reading unsigned long ingeger(Hex)
                     
    19 baudrate i        --> reads baudrate from config29.ini
    19 ID s              --> reads ID from config29.ini
    19 pi f              --> read pi (3.141592654) from config29.ini
    19 Hex_Value h       --> read Hex_Value (12AF) from config29.ini
    19 (any string) t    --> read test string from config29.ini
    
    In many applications, users need one text file to record some information.
    And the program can read it.
    You can use GetProFileInt, GetProFileStr to get specific information 
    in text files.
    
    The format of the text file (config.ini) must follow the rules:
    1. The item information you want to read must be positioned after '*'.
    2. The comment cann't contain any '*'.
    3. If the setting of KeyName is string type, you must add
       least one space character to the end of file(EOF).
    
    For example:
    =====================================
    config file sample for Xdemo29
    =====================================
    * baudreate=115200 ;integer type 
    * Debug=on         ;string type
    * slot0=I8024      ;string type ID name
    =====================================
    comment...........
    
    Hareware: uPAC-7186EX
    
    Note: to run this demo, you must load one extra text file
    (I wrote config29.ini for this demo) into 7188E.
    
    Refer 7188e\TCP\Doc\[Big5|Eng|Gb2312]\Vxcomm.htm 
          7188e\TCP\Xserver\Xserver.htm
          7188e\TCP\Xserver\Function.htm   
    to get more information.
    
    [Dec 18, 2008] by Liam
*/

#include<string.h>
#include<stdio.h>
#include "..\lib\7186e.h"
#include "..\lib\tcpip32.h"
#include "..\lib\vxcomm.h"

static FILE_DATA far *config;

unsigned long FSeek(FILE_DATA far *file_pointer,char cMark,unsigned long lStart,int iTh);
    /* 
    search the cMark from lStart until reach the iTh(th) cMark,
    and return the position next to the cMark.
    */

long GetProFileInt(FILE_DATA far *file_pointer,char* sKeyName,long lDefault);
    /*
    Gets integer of sKeyName, the sKeyName in text file must be after one '*'.
    If cannot find the sKeyName, return the lDefault.
    If cannot find the value of the sKeyName, return the lDefault. 
    */

int GetProFileStr(FILE_DATA far *file_pointer,char* sKeyName,char* sResult,char* sDefault);
    /*
    Gets string of sKeyName, the sKeyName in text file must be after one '*'.
    If cannot find the sKeyName, sResult=sDefault.
    If cannot find the string of the sKeyName, sResult=sDefault. 
    Return value: length of sResult

    I use GetProFileStr to replace GetProFileVal.
    float GetProFileVal(FILE_DATA far *file_pointer,char* sKeyName,float fDefault);
    Gets float value of sKeyName, the sKeyName in text file must be after one '*'.
    If cannot find the sKeyName, return the fDefault.
    If cannot find the value of the sKeyName, return the fDefault.
    */
  
void UserCount(void)
{
    /*
    User's timer trigger function.
    Please refer to XDemo04 for detail description.
    Please refer to XDemo09 for example code.
    */
}

void UserInit(void)
{
    /*
    Initialize user's program.
    Please refer to XDemo04 for detail description.
    Please refer to XDemo09 for example code.
    */
    SetBaudrate(1, 115200L);

    config=GetFileInfoByName("config29.ini"); //Opens one file by name.
    
    printCom1("File size=%lu bytes\n\r",config->size);
    printCom1("      day=%02d\n\r",config->day); 
    printCom1("    month=%02d\n\r",config->month); 
    printCom1("     year=%02d\n\r",config->year+1980); 
    printCom1("     hour=%02d\n\r",config->hour); 
    printCom1("   minute=%02d\n\r",config->minute); 
    printCom1("   second=%02d\n\r",config->sec*2);            
}

void UserLoopFun(void)
{
    /*
    VxComm.exe will call this function every scan time
    Please refer to XDemo11 for Real-time I/O control
    */    
}

int UserCmd(unsigned char *Cmd,unsigned char *Response)
{
    /*  
    Xserver executes this function when received a package 
    form TCP port 10000 and the first two bytes are "19".
    
    Funtion of Xserver, Please refer to XDemo04 for detail description.
    */  
        
    char sItem[20]; 
    char cType;     //i,I: long integer;
                    //s,S: string; 
                    //f,F: float value;
                    //h,H: hex value;
                    //t,T: to get test string;
    float fValue;
    long lValue;
    char sString[40];
    int iRet;
    
    if (Cmd[0]) /* Not Null command */
    {
        sscanf(Cmd,"%s %c",&sItem,&cType);
                
        switch(cType) 
        {   
            //Gets integer value            
            case 'i':   
            case 'I':   
                lValue=GetProFileInt(config,sItem,1);   // Default value=1
                sprintf(Response,"%s=%ld",sItem,lValue);    
                break;
                
            //Gets string 
            case 's':
            case 'S':
                iRet=GetProFileStr(config,sItem,sString,"Error");   // Default string=Error
                sprintf(Response,"%s=%s",sItem,sString);    
                break;

            //Gets float value
            case 'f':
            case 'F':
                iRet=GetProFileStr(config,sItem,sString,"1.23");    // Default string=1.23
                sscanf(sString,"%f",&fValue);
                sprintf(Response,"%s=%f",sItem,fValue);    
                break;
                                
            //Gets hexadecimal integer value
            case 'h':
            case 'H':
                iRet=GetProFileStr(config,sItem,sString,"FFFF");    // Default string=FFFF
                sscanf(sString,"%lx",&lValue);
                sprintf(Response,"%s=%lx(Hex)",sItem,lValue);    
                break;              
            
            //Gets test string 
            case 't':
            case 'T':
                iRet=GetProFileStr(config,"test",sString,"Default");// Default string=Default
                sprintf(Response,"test=%s",sString);    
                break;
            
            default:
                strcpy(Response,"Type error!");
                break;      
        }
        return 1;   /* return OK */
    }
    strcpy(Response,"Failed");
    return 1;   /* return OK */
}

int VcomUserBinaryCmd(TCPREADDATA *p)
{
    /* 
    VXCOMM.EXE 2.6.12(04,Sep,2001) or later will support this function.

    Xserver executes this function when received a package 
    form TCP port 10000 and the first two bytes are "23".
    
    Please refer to XDemo04 for detail description.
    Please refer to XDemo23 for example code.
    */
    return 1;   /* any value will be accept */
}

int VcomCmdUser(TCPREADDATA *p)  
{ 
    /*
    VCOM3005 (Feb,22,2002) or later will call this function for PortUser.
    When packets received by TCP PORT PortUser(user defined) 
    of 7188E/8000E, Xserver will call this function.

    Please refer to XDemo04 for detail description.
    */
    VcomSendSocket(p->Socket,p->ReadUartChar,p->Length);
    return 1;   /* any value will be accept */  
}

void PortUserStart(int skt)
{
    /* 
    XS8_3200.Lib Version 3.2.00 (20,Apr,2004) 
    or later version supports this function.
    
    When a TCP/IP client connects to the 7188E/8000E via the user's 
    defined port(PortUser), the Xserver calls the function once.

    Please refer to XDemo04 for detail description.
    */
    
    skt=skt; //do nothing
}
  
void Port9999Start(int skt)
{
    /* 
    XS8_3200.Lib Version 3.2.00 (20,Apr,2004) 
    or later version supports this function.
    
    When a TCP/IP client connects to the 7188E/8000E TCP port 9999, 
    the Xserver calls the function once.
 
    Please refer to XDemo04 for detail description.
    */
    
    skt=skt; //do nothing
}
 
void Port502Start(int skt)
{
    /* 
    XS8_3200.Lib Version 3.2.00 (20,Apr,2004) 
    or later version supports this function.
    
    When a TCP/IP client connects to the 7188E/8000E TCP port 502, 
    the Xserver calls the function once.
    
    Please refer to XDemo04 for detail description.
    */
    
    skt=skt; //do nothing
}

unsigned long FSeek(FILE_DATA far *file_pointer,char cMark,unsigned long lStart,int iTh)
{
    /*
    This function seeks the mark letter from the start position 
    to the EOF(end of file).
    
    cMark: find the position next to the cMark.
    lStart: the start position to seek the cMark. 
            (0: start position of the file)
    iTh: seek the iTh(th) cMark.
    
    Return value:
        0: cannot find the cMark
       >0: the offset position next to the cMark
     
    */
    
    /*
    typedef struct  {
    unsigned mark;
    unsigned char fname[12];
    unsigned char year;
    unsigned char month;
    unsigned char day;
    unsigned char hour;
    unsigned char minute;
    unsigned char sec;
    unsigned long size;
    char far *addr;
    unsigned CRC;
    unsigned CRC32;
    } FILE_DATA;
    */
    
    char c;
    unsigned long i;
    int iOrder;
    
    i=lStart;
    iOrder=1;
    while(i<(file_pointer->size-1))
    {
        c=file_pointer->addr[i];
        if(c==cMark)
            if(iOrder==iTh)
                return ++i; // return the position next to the cMark.
            else
                iOrder++;
        i++;
    }
    return 0;
}


long GetProFileInt(FILE_DATA far *file_pointer,char* sKeyName,long lDefault)
{        
    /*
    If cannot find the sKeyName, return the lDefault.
    If cannot find the value of the sKeyName, return the lDefault.  
    */
    
    unsigned long lPointer=0;
    char sTemp[20];
    long lValue;
    int i;
    strlwr(sKeyName);
    //Find  out the Item
    while(lPointer<file_pointer->size)
    {
        lPointer=FSeek(file_pointer,'*',lPointer,1);    // To find the 1st '*' from lPointer
        if(lPointer==0) // cannot find '*'
            return lDefault;
        sscanf(file_pointer->addr+lPointer,"%s",&sTemp);
        strlwr(sTemp);
        for(i=0;i<strlen(sTemp)-1;i++)
            if(sTemp[i]=='=')
            {
                sTemp[i]=0;
                break;
            }
        //Read the Value of the Item
        if(!strcmp(sKeyName,sTemp))
        {
            lPointer=FSeek(file_pointer,'=',lPointer,1);    // To find the 1st '=' from lPointer
            if(lPointer==0) // cannot find '=' 
                return lDefault;
            sscanf(file_pointer->addr+lPointer,"%ld",&lValue);
            return lValue;
        }
    }
    // EOF
    return lDefault;
}

int GetProFileStr(FILE_DATA far *file_pointer,char* sKeyName,char* sResult,char* sDefault)
{
    /*
    If cannot find the sKeyName, sResult=sDefault.
    If cannot find the string of the sKeyName, sResult=sDefault.    
    Return value: length of sResult     
    */

    unsigned long lPointer=0;
    char sTemp[20];
    int i,iLen;

    strlwr(sKeyName);
    //Find  out the Item
    while(lPointer<file_pointer->size)
    {
        lPointer=FSeek(file_pointer,'*',lPointer,1);    // To find the 1st '*' from lPointer
        if(lPointer==0) // cannot find '*'
        {
            strcpy(sResult,sDefault);
            return strlen(sDefault);
        }
        sscanf(file_pointer->addr+lPointer,"%s",&sTemp);
        strlwr(sTemp);
        for(i=0;i<strlen(sTemp)-1;i++)
            if(sTemp[i]=='=')
            {
                sTemp[i]=0;
                break;
            }       
        //Read the String of the Item
        if(!strcmp(sKeyName,sTemp))
        {
            lPointer=FSeek(file_pointer,'=',lPointer,1);    // To find the 1st '*' from lPointer
            if(lPointer==0) // cannot find '='
            {
                strcpy(sResult,sDefault);
                return strlen(sResult);
            }
            sscanf(file_pointer->addr+lPointer,"%s",&sTemp);
            if(strlen(sTemp)==0)    // cannot find string
                strcpy(sResult,sDefault);
            else
                strcpy(sResult,sTemp);
            return strlen(sResult);
        }
    }
    // EOF
    strcpy(sResult,sDefault);
    return strlen(sResult);
}

/*
    I use GetProFileStr to replace GetProFileVal.

float GetProFileVal(FILE_DATA far *file_pointer,char* sKeyName,float fDefault)
{        
    unsigned long lPointer=0;
    char sTemp[20];
    float fValue;
    
    strlwr(sKeyName);
    //Find  out the Item
    while(lPointer<file_pointer->size)
    {
        lPointer=FSeek(file_pointer,'*',lPointer,1);    // To find the 1st '*' from lPointer
        if(lPointer==0) // cannot find '*' 
            return fDefault;
        sscanf(file_pointer->addr+lPointer,"%s",&sTemp);
        strlwr(sTemp);
        //Read the Value of the Item
        if(!strcmp(sKeyName,sTemp))
        {
            lPointer=FSeek(file_pointer,'=',lPointer,1);    // To find the 1st '=' from lPointer
            if(lPointer==0) // cannot find '=' 
                return fDefault;
            sscanf(file_pointer->addr+lPointer,"%f",&fValue);
            return fValue;
        }
    }
    // EOF
    return fDefault;
}
*/