C Program: Interface Embedded Linux to Terminal

1 reply [Last post]
Michael Watterson's picture
Michael Watterson
Offline
Joined: 21 Sep 2009
Posts:

This program is to allow a Serial port and GPIO port on a Wrap2C or similar Embedded Linux board to control relays, operate LEDs and use a simple PIC based Terminal with two line display and 3x4 keypad to connect as User Interface.

It also shows how "non-Blocking" serial I/O is done on Linux. Applies to PC also. If there is no data to read, the program continues. Normal behaviour is that the program reading a serial port waits for ever for either a character, or even by default an "enter key" press (EOL) to read the buffer.

It includes a Turbo NiMH charger that signals "end of charge" all via GPIO port pins.


#include 
#include 
#include 
#include 
#include 
#include 
#include 
// these make the serial port work!
#include 
#include 
#include 
// these added for scripts
#include 
// for parsing
#include 


#define LPC_ADDR 0xF410        //GPIOBASE10
#define GPIOBASE14 0xF414 

//select ONLY ONE PAIR of the next four  lines:
#define TARGET        // for production on Wrap PC Engines 1E or 1C
#define DEVICE_NAME "/dev/ttyS0"

//#define DESKTOP        // Running on a regular desktop / laptop Linux
//#define DEVICE_NAME "/dev/ttyUSB0"
const int halfbyte = 4;
            // LED PIN    If not mentioned, DON'T connect!
const int LPC_LINK = 0;        //  GPIO32 3    Link or Status
const int LPC_RXSIG = 1;    //  GPIO33 5    RX level
const int LPC_RXSN = 2;        //  GPIO34 7    RX S/N
const int LPC_PIN9 = 3;        //  GPIO35 9    TX Status
const int LPC_IN_LO = 4;    // GPIO36 20     INPUT: 1=Batt Low, 0=Normal
const int LPC_CHARGE = 5;    // GPIO37 11    Charge
const int GPIO38 = 6;        // Unknown function
const int LPC_IN_HI = 7;    // GPIO39 19    INPUT: 1=Normal, 0=Charged
                            // 18    3.3V Wrap Vs
                            // 2,4,6,8,10,12,17 GND
const int ALL_LEDS_RED = 0;
const int ALL_LEDS_GREEN = 15;
#define KEY1 ( 48 + 1)
#define KEY2 ( 48 + 2)
#define KEY3 ( 48 + 3)
#define KEY4 ( 48 + 4)
#define KEY5 ( 48 + 5)
#define KEY6 ( 48 + 6)
#define KEY7 ( 48 + 7)
#define KEY8 ( 48 + 8)
#define KEY9 ( 48 + 9)
#define KEY0 ( 48 + 0)
#define KEYSTAR  42  
#define KEYHASH  35  
#define KEYUP (48 + 1)
#define KEYDN (48 + 7)

 
//Read mask GPIO  1010 0000 for battery state:
// msb ..lsb
// 0xx0 xxxx = Charged
// 1xx0 xxxx = Normal
// 1xx1 xxxx = Low 

const int LOOP_INTERVAL = 4000;    //4ms = 250 times a second
const int PULSE_CHARGE_DUTYCYCLE = 15;
const int RECHARGE_DELAY = 30000; 
const int PULSE_COLOUR = 5;
const int PULSE_FLASH = 40;
const int PULSE_STICK =5; 

char STICK_CHARS[7];

char frequencies[150][10];
char baseNames[150][17];
int  MAX_BASES = 149;


int pulsesColour = 0;    //to modulate colour of LED.    
int pulsesStick = 0;
int ledSequence[7];
int lpcDataOut = 0;

int waitingForPage = 0;
int pulseFlash = 0;        //to toggle flash on off.
int pulsedCharge = 0;
int flashToggle = 0;    // on/off or bicolour flash
int chargeToggle = 0;    // A/C only enables charging
char spinningStick ;
char escape = 27;
// low sensor: Bat low =1, Bat Ok = 0
// hi sensor: Bat Ok = 1, bat charged = 0
//    lsb .. msb
// so xxxx 1001 = LOW, Pulse Charging
// so xxxx 1xx0 = Normal, Turbo charge
// so xxxx 0xx0 = Full Charge, Trickle charge
const int BATT_LOW = 9;
const int BATT_NORMAL = 8;
const int BATT_FULL = 0;



enum testerStates {TS_DISP_OFF, TS_BATT_LOW, TS_TURBO_CHARGE, TS_TRICKLE_CHARGE, TS_DISP_FREQ, TS_DISP_BASE, TS_ENTER_FREQ, TS_ENTER_BASE, TS_DISP_WAIT};

enum testerStates thisState = TS_TRICKLE_CHARGE;
enum testerStates lastState = TS_DISP_OFF;

int entryCountdown;        //Reset to last base
struct timeval timenow;
struct timeval exectime;

#define BASE_LIST_FILENAME "baselist.csv"
char baseName[17];
int thisBase = 0;
char thisFreq[10];
int serport;    //the device for I/O


int initport (char *deviceName){
int fd;
    struct termios options;
    serport = open(deviceName, O_RDWR | O_NOCTTY | O_NDELAY);
#ifdef DESKTOP
    if (serport == -1) {
        perror("open_port fail: ");
        perror(DEVICE_NAME);
        return -1;
    }
#endif
    //Next line not liked by  gcc so we get existing one 
    //bzero(&options,sizeof(options));
    fd = serport;
    tcgetattr(fd,&options);
    options.c_cflag = (B2400 |CRTSCTS |CS8| CLOCAL |CREAD);
    // options.c_cflag &= ~PARENB;
    // options.c_cflag &= ~CSTOPB;
    // options.c_cflag &= ~CSIZE ;
    options.c_iflag |= IGNPAR ;
    options.c_oflag = 0;
    //options.c_oflag = options.c_iflag;
    options.c_lflag = 0 ;    //no echo, no buffer till ENTER key
    options.c_cc[VMIN] = 0;  // don't wait for any characters
    options.c_cc[VTIME] = 0; // no intercharacter delay
    tcflush(fd,TCIFLUSH);
    tcsetattr(fd,TCSANOW,&options);
    fcntl(fd,F_SETFL,FNDELAY);    //nonblocking
    cfsetispeed(&options, B2400);
    cfsetospeed(&options, B2400);
    return serport;
}    
// End initport

int readsch(int fd){
    int readError = 0;
    char portbuff[200];
     
    readError = read(fd,portbuff,1);
    readError-- ;    // so we can hsav nulls
    if (readError >= 0) 
        readError = portbuff[0];
    return readError;
}
// End readsch

int writesch(int fd, char chtosend){
    int writeError = 0;
    char portbuff[200]; 
    portbuff[0] = chtosend;
    writeError = write(fd,&portbuff,1);
    return writeError;
}
// End writesch

int writesstr(int fd, char * strtosend){
    int writeError = 0;
    int sendLen = strlen(strtosend); 
    if (strtosend[sendLen-1] =='')
        sendLen--;
    writeError = write(fd,strtosend,sendLen);
    return writeError;
}
// End writesstr

void  lcdClear(int fd) {
char spaces32home[80];
    strcpy(spaces32home, "                                           ");
    spaces32home[0] = 'n';
    spaces32home[33] = 'n';
    spaces32home[34] = '';
    writesstr(fd,spaces32home);    
#ifdef DESKTOP
//    writesch(fd,escape);
//    writesch(fd,'H');
#endif    
}
// End lcdClear

void lcdLamp(int fd, int lit){
const char CTRLP = 16;
char lcdcmd[5];
    strcpy(lcdcmd,"p1");
    lcdcmd[0] = CTRLP;
    if (lit > 0 )
        lcdcmd[1] = '1';
    else
        lcdcmd[1] = '0';
    writesstr(fd, lcdcmd);
#ifdef DESKTOP
//    writesch(fd,escape);
//    writesch(fd,'H');
#endif    
}
// End lcdLamp

void lcdHome(int fd) {
char newline = 13;

    writesch(fd,newline);
#ifdef DESKTOP
//    writesch(fd,escape);
//    writesch(fd,'H');
#endif    
}
// End lcdHome
void lcdBargraph(int fd, int barsize){
int sigcount = 0;
char lcdbuff[17];
    if (barsize > 16)
        barsize = 16;
    if (barsize < 0) 
        strcpy(lcdbuff," * NO SIGNAL! * ");
    else
        strcpy(lcdbuff,"                "); // 16 chars I hope!
    for (sigcount=0; sigcount';
    writesstr(fd,lcdbuff);
}
// End lcdBargraph

void tickTockInit(int loopInterval){
    /* Get current time */
    gettimeofday(&timenow,NULL);

    /* Set future time for action */
    exectime.tv_sec = timenow.tv_sec;
    exectime.tv_usec = timenow.tv_usec + loopInterval;
    if (exectime.tv_usec > 1000000) {
        exectime.tv_usec = exectime.tv_usec - 1000000;
        exectime.tv_sec++;
    }


}
void tickTockWait(int waitInterval) {/* Get current time */
int waiting = 1;
    while (waiting){
    gettimeofday(&timenow,NULL);
    if ((exectime.tv_sec < timenow.tv_sec) 
        ||((exectime.tv_sec == timenow.tv_sec)
            && (exectime.tv_usec <= timenow.tv_usec))) {

        /* Set future time for action */
        exectime.tv_sec = timenow.tv_sec;
        exectime.tv_usec = timenow.tv_usec + waitInterval;
        if (exectime.tv_usec > 1000000) {
            exectime.tv_usec = exectime.tv_usec - 1000000;
            exectime.tv_sec++;
            }
        waiting = 0;
        }
    }
    //update all the timers, the colour sequence index changes every time
    pulsesColour++;
    if (pulsesColour > (PULSE_COLOUR))
        pulsesColour = 0;
    if ((thisState == TS_DISP_FREQ) ||(thisState==TS_DISP_BASE)) {
        lpcDataOut = ledSequence[pulsesColour];
    }     

    pulseFlash++;
    if (pulseFlash > (PULSE_FLASH)){
        pulseFlash = 0;
        // spins at twice the flashing speed
        if (pulsesStick > PULSE_STICK)
                    pulsesStick = 0;
        pulsesStick++;
        if (flashToggle > 0) {
            flashToggle = 0;
        } else{
            flashToggle = 1;
        }
        if (thisState == TS_DISP_WAIT) {
                lcdLamp(serport,0); // LEDS off
                lcdClear(serport);
                writesstr(serport,"WAIT ... ");
                writesch(serport,STICK_CHARS[pulsesStick]);
                writesstr(serport," == ");
                writesch(serport,STICK_CHARS[pulsesStick]);
                lcdHome(serport);
                lpcDataOut = 0;
        }    
    }
    pulsedCharge++;
    if (pulsedCharge > PULSE_CHARGE_DUTYCYCLE)
        pulsedCharge = 0;
    #ifdef TARGET
/* Output LPC_CHARGE..32 values as doubleword/long to GPIOBASE offset 10 */
    
    outl(lpcDataOut,LPC_ADDR);
#endif
            
}
//End tickTockWait
void initLPCbusAsIO(){
#define PMR_ADDR 0x9030
#define GPIOBASE20 0xF420
#define GPIOBASE24 0xF424
#ifdef TARGET
    /* Allow program to use higher I/O ports */
    iopl(3);

    /* Allow program to access required I/O */
    ioperm(PMR_ADDR,4,1);
    ioperm(GPIOBASE20,4,1);
    ioperm(GPIOBASE24,4,1);

    /* Switch the LPC port to GPIO mode */
    outl(inl(PMR_ADDR) & ~(1 << 16 | 1 << 14), PMR_ADDR);

    /* Select GPIO to change (32) */
    outl(32,GPIOBASE20);
    /* Setup this GPIO for output */
    outl(67,GPIOBASE24);

    /* Select GPIO to change (33) */
    outl(33,GPIOBASE20);
    /* Setup this GPIO for output */
    outl(67,GPIOBASE24);

    /* Select GPIO to change (34) */
    outl(34,GPIOBASE20);
    /* Setup this GPIO for output */
    outl(67,GPIOBASE24);

    /* Select GPIO to change (35) */
    outl(35,GPIOBASE20);
    /* Setup this GPIO for output */
    outl(67,GPIOBASE24);

    /* Select GPIO to change (36) */
    outl(36,GPIOBASE20);
    /* Setup this GPIO for input only */
    outl(68,GPIOBASE24);

    /* Select GPIO to change (37) */
    outl(37,GPIOBASE20);
    /* Setup this GPIO for output */
    outl(67,GPIOBASE24);

    /* Select GPIO to change (39) */
    outl(39,GPIOBASE20);
    /* Setup this GPIO for input only */
    outl(68,GPIOBASE24);

    /* Remove I/O permissions */
    ioperm(PMR_ADDR,4,0);
    ioperm(GPIOBASE20,4,0);
    ioperm(GPIOBASE24,4,0);
#endif
}
//End initLPCbusAsIO

void displaySignalFreq(int siglevel, char *freqText ){
    lcdLamp(serport,1);
    lcdClear(serport);
    lcdBargraph(serport,(siglevel)); // assume only 1 to 8 used
    writesstr(serport,"FREQ: ");
    if (strlen(freqText) > 9)
        freqText[9] ='';
    writesstr(serport,freqText);
    lcdHome(serport);
}
//end DisplaySignalFreq
void displaySignalText(int siglevel, char *sigLabel ){
    lcdLamp(serport,1);
    lcdClear(serport);
    lcdBargraph(serport,siglevel); // assume only 1 to 8 used
    if (strlen(sigLabel) > 16)
        sigLabel[16] ='';
    writesstr(serport,sigLabel);
    lcdHome(serport);
}
//end DisplaySignalFreq

void showBase(int baseNum ){
    if (baseNum < 0) 
        baseNum = 0;
    if (baseNum > MAX_BASES)
        baseNum = MAX_BASES;
    lcdLamp(serport,1);
    lcdHome(serport);
    writesstr(serport,"                ");
    lcdHome(serport);
    if (strlen(baseNames[baseNum]) > 16)
        baseNames[baseNum][16] ='';
    writesstr(serport,baseNames[baseNum]);
    lcdHome(serport);
}

void showNewFreq (char * newFreq) {
    lcdHome(serport);
    writesstr(serport," New : ");
    writesstr(serport, newFreq);
}

/***************************************************
Scripts:
get_webpages.sh        Does wget on the webpages 
                    and creates "/rw/siglevels.csv"

put_frequency.sh    Does wget on form post to set
                    frequency and creates "/rw/donefreqpost.txt"





***************************************************/
int fileExists (char *newFile){
FILE *fp;
    fp = fopen(newFile,"r");
    if (fp == NULL){    // not ready yet
        return (-1);
    }else {
    
         return (1);
    }

}
// End File Exists

void  modemAskStatus(){
    if (waitingForPage < 1) {
        system("./test_webpages.sh &");
        waitingForPage = 1;
    }
}
//End modemAskStatus

int modemStatusRead(char *resultsTxt){
FILE *fp;
int readQty =0;
    if (waitingForPage > 0) {
        fp = fopen("/rw/siglevels.csv","r");
        if (fp == NULL){    // not ready yet
            readQty = -1;
        }else { 
             readQty=fread(resultsTxt,1,79,fp);
             fclose(fp);
             if (readQty > 5) {
             system("rm /rw/siglevels.csv");
             waitingForPage = 0;
             }else {
                 readQty = -1;
             }
        } 
    }else{
        modemAskStatus();
    }
    return (readQty);    
}
// End modemStatusRead

void modemSetFreq(char *newFrequency){
char commandstr[80];
    while (waitingForPage > 0)
         modemStatusRead(commandstr);
    strcpy(commandstr, "./test_frequency.sh ");
    strcat(commandstr, newFrequency); 
    strcat(commandstr, " &");
    system(commandstr);
}
// End ModemSetFreq


int modemFreqDone(){
FILE *fp;
int readQty;
char results[80];
    readQty = -1;
    strcpy(results,"                       ");
    fp = fopen("/rw/donefreqpost.txt","r");
    if (fp == NULL){    // not ready yet
        readQty = -1;
    }else {
         readQty=fread(results,1,5,fp);
         fclose(fp);
        if (readQty > 4) {
             system("rm /rw/donefreqpost.txt");
        }else {
            readQty = -1;
        }
    }
    return (readQty);
}
// End modemFreqDone

    // find nth-1 comma, if n zero the start
    // read till nth comma or end of string
    // convert substring to Int.

int parseNthString (char *sourceTxt, int posparm, char *newBuff){
int lineLen = 0;
int startCh = 0;
int endCh = 0;
long resultNum = 0;
int indexCh = 0;
int indexBuff = 0;
    lineLen = strlen(sourceTxt);
    if (posparm < 1) 
        posparm = 1;
    if (posparm == 1){ 
        startCh = 0;
    } else {
        indexCh = 1;
        while (indexCh < lineLen) {
             if (sourceTxt[indexCh] == ','){
                 startCh = indexCh +1;
                 posparm-- ;
                 if (posparm < 2){
                     while ((startCh < lineLen) && (sourceTxt[startCh] == ' ')){
                         startCh++;
                     } //eat leading spaces
                     indexCh = lineLen;    
                 }
             }
             indexCh++ ;
        }
        
    }
    // now find the end
    endCh = lineLen;  //if there is no last comma
    indexCh = startCh +1;
    while (indexCh < lineLen){
         if ((sourceTxt[indexCh] == ',') ||(sourceTxt[indexCh] == 'n')){
             endCh = indexCh;
             indexCh = lineLen;
         } 
         indexCh++ ; 

    }
    // now copy the substring
    indexBuff = 0;
    indexCh = startCh;
    while (indexCh < endCh){
        newBuff[indexBuff] = sourceTxt[indexCh];
        indexBuff++;
        indexCh++;
    }
    newBuff[indexBuff] = '';
    return indexBuff; 
}
// End parseNthInt


int readBaseList (char * fname){
// read file line by line 
FILE *fp;
int readQty =0;
int lineLen = 0;
int buffUsed = 0;
int buffIndex = 0;
int readFreq = 1;
int chrIndex = 0;
const MAX_BUFFER = 7000;
char buffer[7000]; 
    fp = fopen(fname,"r");
#ifdef DESKTOP
    printf("Open file %s n",fname);
#endif
    if (fp ==NULL){    // not there
        readQty = -1;
#ifdef DESKTOP
    printf("Open file %s did fail! n",fname);
#endif
    }else {
#ifdef DESKTOP
        printf("Read the buffer? n");
#endif
         buffUsed=fread(buffer,1, (MAX_BUFFER-1),fp);
         // close the file?
         fclose(fp);
        buffer[buffUsed] = '';
#ifdef DESKTOP
        printf("The buffer is Read! size %dn",buffUsed);
#endif
        readQty =0;     //index to arrays
        for (buffIndex = 0; buffIndex < buffUsed; buffIndex++) {
            if (buffer[buffIndex] == 'n') {
                baseNames[readQty][chrIndex] = '';
                chrIndex = 0;
#ifdef DESKTOP
                printf("item: %d >%s< [%s]n",readQty, frequencies[readQty], baseNames[readQty]);

#endif
                readQty++ ;
                readFreq = 1;
            }else{
                // add code here to eat " or _ if desired
                if (buffer[buffIndex] == ',') {
                    frequencies[readQty][chrIndex] = '';
                    readFreq = 0;
                    chrIndex = -1;
                } else {
                    if ((chrIndex < 0) && (buffer[buffIndex] != ' ')) {
                        chrIndex = 0;
                    }else {
                        if (readFreq > 0) {
                            frequencies[readQty][chrIndex] = buffer[buffIndex];
                            chrIndex++;
                        }else {
                            baseNames[readQty][chrIndex] = buffer[buffIndex];
                            chrIndex++;
                        } //reading an entry
                    } // skip spaces after a comma only
                } //skip comma and swtich to base name
            }// newline and switch to frequency 
        } // Read & process buffer
    }  // open the file    
    return (readQty );    
}
// End readBaseList


int lookupBaseNum( char *freqText){
// assume the list is ordered
long unknownFreq ;
long actualBaseFreq;
int baseNum;
char * pEnd;

    baseNum = 0;
    unknownFreq =  strtol(freqText,&pEnd,10);
    actualBaseFreq =  strtol(frequencies[baseNum],&pEnd,10);
//    printf("unknown: %d, Actual:%d n",unknownFreq,actualBaseFreq);
        while ((baseNum <= MAX_BASES)&& (actualBaseFreq < unknownFreq)) {
            baseNum++;
            actualBaseFreq =  strtol(frequencies[baseNum],&pEnd,10);
//            printf("base: %d, unknown: %d, Actual:%d n",baseNum, unknownFreq,actualBaseFreq);
        }
    if (baseNum == (MAX_BASES -1)) {    //penultimate entry is always reserved for Unknown 
        strcpy(frequencies[baseNum],freqText);
    }
    return (baseNum);
}
//End lookupBaseName
int lookupBaseFreq(int baseNum,char *newFreq){
    if (baseNum < 0) 
        baseNum = 0;
    if (baseNum > MAX_BASES)
        baseNum = MAX_BASES;
    strcpy(newFreq,frequencies[baseNum]);
    
    return(1);
}
//End lookUpBaseFreq

// echo "$rxSig, $rxSN, $txPwr, $freq, $loaded_page" > $resultsfile

int  displayRxLevel(char *resultsTxt, int showName){
//masks for LEDs
const int TX_MASK_HI = 8; //0b00001000;
//const int TX_MASK_LO = 0b11110111;
const int SN_MASK_HI = 4; // 0b00000100;
// const int SN_MASK_LO = 0b11111011;
const int RX_MASK_HI = 2; // 0b00000010;
// const int RX_MASK_LO = 0b11111101;
const int LK_MASK_HI = 1; // 0b00000001;
// const int LK_MASK_LO = 0b11111110;
// for signal levels
const int rxSigRedThresh=-16;
const int rxSigAmbThresh=-7;
const int rxSNRedThresh=21;
const int rxSNAmbThresh=25;
const int txPwrRedThresh=47;
const int txPwrAmbThresh=45;
const int txPwrLowThresh=6;
//
char newBuff[80] ;
int parmSize = 0;
int rxSig = 0;
int rxSN = 0;
int txPwr = 0;
int loadedPage =0;
char rxFreq[11] ;
char * pEnd;
char baseName [20];
int barSize =0 ;
    strcpy(newBuff,"This is junk ********!!!!");
    if (strlen (resultsTxt) > 16){
        parmSize = parseNthString (resultsTxt, 1, newBuff);
        if (parmSize > 0){
            rxSig = strtol(newBuff,&pEnd,10);
        }
        parmSize = parseNthString (resultsTxt, 2, newBuff);
        if (parmSize > 0){
            rxSN = strtol(newBuff,&pEnd,10);
        }
        parmSize = parseNthString (resultsTxt, 3, newBuff);
        if (parmSize > 0){
            txPwr = strtol(newBuff,&pEnd,10);
        }
        strcpy(rxFreq,"100000000");  //minimum?
        parmSize = parseNthString (resultsTxt, 4, rxFreq);
        if (strlen(rxFreq) > 10){
            rxFreq[9] ='';
        }
        parmSize = parseNthString (resultsTxt, 5, newBuff);
        if (parmSize > 0){
            loadedPage = strtol(newBuff,&pEnd,10);
        }
        // adjust RxSig bar size 0 = threshold
        barSize  = ((rxSig - rxSigRedThresh) +1) /2;  // 2dB per dot
        if (loadedPage > 0) {
            loadedPage = lookupBaseNum(rxFreq);
            if (showName < 1) {
                displaySignalFreq(barSize,rxFreq);
                strcpy(thisFreq,rxFreq);
            }else{
                displaySignalText(barSize,(baseNames[loadedPage]));
            }
        } else {
            loadedPage = -1;
            displaySignalText(-1," NO CONNECTION! ");
        }
    //set txSig, rxSN, rxSig, loadedPage between 0 to 7
    
/************************************************************************
 ledSequence[PULSE_COLOUR+2] is array of LED states to colour them
 0th element not used
       0 1 2 3 4 5  
 0  0 0 0 0 0 0 = red
 1  1 0 0 0 0 0 = ambered
 2  1 1 0 0 0 0 = amber
 3  1 1 1 0 0 0 = orange
 4  1 1 1 1 0 0 = sodium
 5  1 1 1 1 1 0 = yellow
 6  1 1 1 1 1 1 = green

Bit positions:
 0b0 0 0 c t n r l
c = Charge
t = Tx
n = RX S/N
r = RX Level
l = Link (not used)
*************************************************************************/
    // set each signal to 1, 4 or 7 
         if (rxSig <  rxSigRedThresh) {
             rxSig = 1;
         }else{
             if (rxSig <  rxSigAmbThresh){
                 rxSig = 4;
             }else{
                 rxSig = 7;
             }
         }
 //rxSNThresh high is good
         if (rxSN <  rxSNRedThresh) {
             rxSN = 1;
         }else{
             if (rxSN <  rxSNAmbThresh){
                 rxSN = 4;
             }else{
                 rxSN = 7;
             }
         }
 // txPwrThresh high is bad
          if ((txPwr >  txPwrRedThresh)||(txPwr < txPwrLowThresh)) {
             txPwr = 1;
         }else{
             if (txPwr >  txPwrAmbThresh){
                 txPwr = 4;
             }else{
                 txPwr = 7;
             }
         }

    int timeIndex = 0;
        for (timeIndex =0; (timeIndex < (PULSE_COLOUR+1)); timeIndex++){
            ledSequence[timeIndex] = 0;
            if (timeIndex < txPwr)
                ledSequence[timeIndex] |= TX_MASK_HI;
            if (timeIndex < rxSN)
                ledSequence[timeIndex] |= SN_MASK_HI;
            if (timeIndex < rxSig)
                ledSequence[timeIndex] |= RX_MASK_HI;
            if (loadedPage > -1)
                ledSequence[timeIndex] |= LK_MASK_HI;
        } 
    } 
    modemAskStatus();
    return loadedPage;
}

//End 
/******
ARGUMENTS: none used 
******/
int main(int argc, char *argv[]) {

const int MAX_INPUT_DELAY = 100000;
int statusFile;
int resultsReady = -1; //no web page
int batterystate = 0;
int lastbatterystate = 0;
int rechargeDelayCount = 0;
int webpage;
int mybuff ='?';
int inputTimeOut = 0;
char newFreq[11];
int  newBase = 0;
char signalLevelsText[80] = "";
int freqCursorPos = 0;

void initTS_ENTER_FREQ() {
    inputTimeOut = MAX_INPUT_DELAY;
    strcpy(newFreq,thisFreq);
    freqCursorPos = 0;
    newFreq[freqCursorPos]= mybuff;
    freqCursorPos++ ;
    lcdClear(serport);
    showNewFreq(newFreq);
    writesstr(serport,"Freq: ");
    writesstr(serport, thisFreq);
    thisState = TS_ENTER_FREQ;
}
void initTS_TRICKLE_CHARGE() {
    lcdLamp(serport,0);
    lcdClear(serport);
    writesstr(serport,"  BATTERY is    ");
    writesstr(serport," fully charged!");
    lcdHome(serport);    
    lpcDataOut =0; 
}
void initTS_TURBO_CHARGE() {
    lcdLamp(serport,1);
    lcdClear(serport);
    writesstr(serport,"  BATTERY IS    ");
    writesstr(serport,"  NORMAL ");
    lcdHome(serport);
}
void initTS_BATT_LOW(){
    lcdLamp(serport,0);
    lcdClear(serport);
    writesstr(serport," BATTERY IS LOW ");
    lcdHome(serport);
    lpcDataOut =0; 
}

void checkForWebPage(){
    if (flashToggle == 1) {
        resultsReady = modemStatusRead( signalLevelsText);
        if (resultsReady > 0) {
        // display new results    
            thisBase =displayRxLevel(signalLevelsText,0);
            if (thisBase > -1){
                lastState = thisState;
                thisState = TS_DISP_FREQ;
            }                         
        }
    }
}
/**********************************************************

            MAIN PROGRAM 
            
            
**********************************************************/
            
    // Select serial port for our LCD and set it up
    serport = initport(DEVICE_NAME);

#ifdef TARGET
    initLPCbusAsIO();    // Setup LPC for our own I/o!
    /* Allow program to use higher I/O ports */
    /* Allow program to access required I/O */
    iopl(3);
    ioperm(LPC_ADDR,4,1);
    ioperm(GPIOBASE14,4,1);
#endif
/*************************************************
if BATT_LOW we care about nothing else
    we only pulse charge. Do nothing else
else If we are in EntryMode then KEEP ENTERING
     If we confirm then set new frequency
        If time out then fetch results.        
else if resultsReady is -1 then no modem, we must be charging
    if battery goes from Normal to Charged we trickle
else if resultsReady is 0 then we wait 
else if resultsReady is 1 then we get them AND see if the user wants do do anything new
    User choice


             
**************************************************/
    /*************************************************/
    /* MAIN LOOP */
    //modemAskStatus();
    strcpy(STICK_CHARS, " +*X*+ ");
    MAX_BASES = (readBaseList (BASE_LIST_FILENAME ))-1;
#ifdef DESKTOP
    printf ("list of Bases read! n");
    batterystate = BATT_NORMAL; 
#endif
    strcpy(signalLevelsText,"No");
    tickTockInit(LOOP_INTERVAL);
    while (1) {
        tickTockWait(LOOP_INTERVAL);

#ifdef TARGET
        //Read battery state  
        // 9 = 1001 is mask
        // 0 = Charged (Trickle), 9 = Low (Pulse), 8 = Normal (Turbo)
        batterystate = (inl(GPIOBASE14) >> halfbyte) & 9;
#endif
        if (batterystate == BATT_LOW){
            if (thisState != TS_BATT_LOW) {
                lastState=thisState;
                thisState= TS_BATT_LOW;
                initTS_BATT_LOW();
            }
        }
            switch  (thisState) {
            case (TS_ENTER_FREQ):
            case (TS_ENTER_BASE):
                 // Continue user entry
                mybuff = readsch(serport);
                if (mybuff < 0){
                    inputTimeOut-- ;
                    if (inputTimeOut < 1) {
                        if (thisState == TS_ENTER_FREQ){
                            thisState =TS_DISP_FREQ;
                            modemAskStatus();
                        }
                        if (thisState ==TS_ENTER_BASE){
                            thisState =TS_DISP_BASE;
                            modemAskStatus();
                        } 
                    }        
                } else {
                //some user entry
                    inputTimeOut = MAX_INPUT_DELAY;
                    if (thisState == TS_ENTER_FREQ){
                        switch (mybuff){
                        case (KEY1):
                        case (KEY2):
                        case (KEY3):
                        case (KEY4):
                        case (KEY5):
                        case (KEY6):
                        case (KEY7):
                        case (KEY8):
                        case (KEY9):
                        case (KEY0):
                            newFreq[freqCursorPos]= mybuff;
                            freqCursorPos++;
                            if (freqCursorPos > 8){
                                newFreq[freqCursorPos] = '';
                                freqCursorPos = 0;
                                }
                            showNewFreq(newFreq);
                        break;        
                        case (KEYSTAR):// switch to base Mode
                            lastState = thisState;
                            thisState = TS_ENTER_BASE;
                        break;
                        case (KEYHASH)://Select entry as freq
                            modemSetFreq(newFreq);
                            lastState = thisState;
                            thisState = TS_DISP_WAIT;
                        break;
                        }
                    } //endIf enterFreq
                    if (thisState ==TS_ENTER_BASE){                
                        switch (mybuff){
                        case (KEYUP):
                            newBase--;
                            if (newBase < 0 )
                                newBase = MAX_BASES;
                            showBase(newBase);
                        break;
                        case (KEYDN):
                            newBase++;
                            if (newBase > MAX_BASES)
                                newBase = 0;
                            showBase(newBase);    
                        break;        
                        case (KEYSTAR):
                            thisBase = newBase;
                            lookupBaseFreq(thisBase,newFreq);
                            modemSetFreq(newFreq);
                            lastState = thisState;
                            thisState = TS_DISP_WAIT;
                        break;
                        case (KEYHASH):// switch to Freq Mode
                            lastState = thisState;
                            thisState = TS_ENTER_FREQ;
                            initTS_ENTER_FREQ();
                        break;
                        }
                    } //endIf enterBase
                //end user entry 
                } //end if mybuff else
            break;
            case (TS_DISP_FREQ):
                modemAskStatus();
                resultsReady = modemStatusRead( signalLevelsText);
                if (resultsReady > 0) {
                // display new results    
                    thisBase =displayRxLevel(signalLevelsText,0);
                    if (thisBase < 0){
                        lastState = thisState;
                        thisState = TS_TRICKLE_CHARGE;
                    }                         
                }
                mybuff = readsch(serport); //see if we want to enter
                switch (mybuff){
                case (KEY1):
                case (KEY2):
                case (KEY3):
                case (KEY4):
                case (KEY5):
                case (KEY6):
                case (KEY7):
                case (KEY8):
                case (KEY9):
                case (KEY0):
                    lastState = thisState;
                    thisState = TS_ENTER_FREQ;
                    initTS_ENTER_FREQ();
                break;        
                case (KEYSTAR):// switch to base Mode
                    lastState = thisState;
                    thisState = TS_DISP_BASE;
                break;
                case (KEYHASH)://Do nothing!
                break;
                } // end key read
            break;
            case (TS_DISP_BASE):
                modemAskStatus();
                resultsReady = modemStatusRead( signalLevelsText);
                if (resultsReady > 0) {
                    // display new results    
                    thisBase =displayRxLevel(signalLevelsText,1);
                    if (thisBase < 0){
                        lastState = thisState;
                        thisState = TS_TRICKLE_CHARGE;
                        initTS_TRICKLE_CHARGE();
                    }                         
                }
                mybuff = readsch(serport); //see if we want to enter
                switch (mybuff){
                case (KEY4):
                case (KEY5):
                case (KEY6):
                case (KEY0):
                break;        
                case (KEY1):
                case (KEY2):
                case (KEY3):
                    inputTimeOut = MAX_INPUT_DELAY;
                    lastState = thisState;
                    thisState  = TS_ENTER_BASE;
                    newBase = thisBase;
                    newBase--;
                    if (newBase < 0)
                        newBase = MAX_BASES;
                    showBase(newBase);
                break;
                case (KEY7):
                case (KEY8):
                case (KEY9):
                    inputTimeOut = MAX_INPUT_DELAY;
                    lastState = thisState;
                    thisState  = TS_ENTER_BASE;
                    newBase = thisBase;
                    newBase++;
                    if (newBase > MAX_BASES)
                        newBase = 0;
                    showBase(newBase);
                break;        
                case (KEYSTAR):// Do nothing!
                break;
                case (KEYHASH):// switch to Frequency Display
                    lastState = thisState;
                    thisState  = TS_DISP_FREQ;
                break;
                } // end key press
            break;
            case (TS_DISP_WAIT): //caused by Modem Reset!
                if (modemFreqDone() > 0 ) {
                    if (lastState ==TS_ENTER_BASE){
                        thisState = TS_DISP_BASE;
                    }else{
                        thisState = TS_DISP_FREQ;
                    }
                }
            break;
            case (TS_BATT_LOW): // No RX LEDs and Red TX LED
                if ((batterystate == BATT_NORMAL) &&(lastState != TS_TURBO_CHARGE)) {
                    lastState = thisState;
                    thisState = TS_TURBO_CHARGE;
                    initTS_TURBO_CHARGE();
                } else{
                    if (batterystate == BATT_FULL) {
                        lastState = thisState;
                        thisState = TS_TRICKLE_CHARGE;
                        initTS_TRICKLE_CHARGE();
                    } else {
                        if (pulsedCharge ==1 )    {
                            if (chargeToggle > 0){
                                lpcDataOut |= 32; // 0b00010000  charge pin high
                            } else {
                                lpcDataOut &= (255-32); // 0b11101111; // charge pin low                
                            }    
                        } else {
                            lpcDataOut = 0;
                        }
                    }
                }

            break;
            case (TS_TURBO_CHARGE): //LEDS ON but alternate
        
                if (batterystate == BATT_FULL) {
                    lastState = thisState;
                    thisState = TS_TRICKLE_CHARGE;
                    initTS_TRICKLE_CHARGE();
                }
                if (flashToggle == 1){
                    lpcDataOut =4; // 0b00000100  RX LEDS Green/Red 
                } else {
                    lpcDataOut = 2; // 0b00000010 RX LEDS Red/Green
                }
                if (chargeToggle > 0){
                    lpcDataOut |= 32;    // 0b00010000  charge pin high
                    chargeToggle = 0;
                } else {
                    lpcDataOut &= (255 - 32); //0b11101111 charge pin low
                    chargeToggle = 1;                
                }
                checkForWebPage();
            break;
            case (TS_TRICKLE_CHARGE):  // No RX LEDs and Red TX LED
                // charging hysterisis  don't switch to turbo if we have been on Turbo
                if ((batterystate == BATT_NORMAL) &&(lastState != TS_TURBO_CHARGE)) {
                    lastState = thisState;
                    thisState = TS_TURBO_CHARGE;
                    initTS_TURBO_CHARGE();
                }
                checkForWebPage();
            break;
    
            }//end state machine switch
    }
    // end main loop 

    // Remove I/O permissions 
#ifdef TARGET
    ioperm(LPC_ADDR,4,0);
    ioperm(GPIOBASE14,4,0);
#endif
    return 1;
}

I'm not a Real C programmer, nor Linux/UNIX guru so don't that this is the best or even a correct solution. However it works on a Geode based Wrap2C board from PCengines.

(c) 2007 Michael Watterson (free for personal use)
gerryk
Offline
Joined: 22 Oct 2009
Posts:

Good stuff. To bo honest, I'm more of an arduino type when it comes to embedde stuff. It was Microchip's awful IDEs that turned me off PICs, well, that, and the fact that I'm too old for low level stuff like timers and locks.
That might have something to do with the fact that I like Python these days too...

User login