Sunday, December 9, 2012

Caller ID Project - part three


Today I did some cleanup of the code, migrated it to the Raspberry Pi and did some unit testing.

Below is the C program that reads the USB modem output and parses the results.  I used printf's to to output to the console just to verify that it's working.  I also wrote the output to an index.html file that I'm serving with Apache on the RPi.

It took some time to get this working on the Raspberry Pi.  For some reason the /dev/ttyACM0 port (that the USB Modem was hooked up to) had a problem with command echo and the status messages being "on" - so I turned them off.

It appeared that the status messages were causing some kind of "loopback" problem.  Odd, that.

I turned on the web server on the Raspberry Pi.  Now whenever anyone calls, the web page is updated and looks something like this - still have some formatting to do...


Date: 12-09
Time: 20:46
Number: 4195551212
Name: Amos Mark

Next steps:
- Figure out how to display to an LCD display hooked up to the RPi
- Get an LCD display hooked up and tested
- Wire everything together and do integration testing

Here's the code so far:

//
//  main.c
//  USB Reader
//
//  Created by Mark Amos on 12/7/12.
//  Copyright (c) 2012 Mark Amos. All rights reserved.
//

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

int get_fld(char *, int);
int hex_to_ascii(int, int);
int hex_to_int(int);
int write_web_page(char *, char *, char *);

int main(int argc, const char * argv[])
{

    int  msg_len;
    int  msg_end;
    long fld_type;
    long fld_len;
    char fld_val [64] = "";
    int  str_ptr;
    char str_date_time [20] = "  /     :  ";
    char str_nbr [20] = "   -   -    ";
    char str_nam [64] = "";
    char str_input [256] = "\0";
    
    // Send configuration strings to modem
    // On Raspberry Pi, leaving echo on and status messages on causes problems with some kind of "loop back" on the
    // /dev/ttyACM0 port.  So, we have to turn them off.
    FILE *out_file;
    out_file = fopen("/dev/tty.usbmodem0000001", "w");
    if (out_file == NULL) {
        fprintf(stderr, "Can't open output file\n");
    }
    fprintf(out_file,"ATE0\n");                                    // Turn off echo
    fprintf(out_file,"ATQ1\n");                                   // Turn off status messages
    fprintf(out_file,"AT#CID=2\n");                            // Turn on unformatted Caller ID
    fclose(out_file);
    
    // Open modem for input
    FILE *in_file;
    in_file = fopen("/dev/tty.usbmodem0000001", "r");
    if (in_file == NULL) {
        fprintf(stderr, "Can't open input file\n");
    }    
    
    // loop getting input from modem
    while (fgets(str_input, 250, in_file) != NULL ){            // Check to see if there's input available
        if(strstr(str_input,"MESG=80")){                          // Check to see if we received a CID message
            
            // Get Message Length
            str_ptr = 7;                                                // position pointer to point at the message length field
            msg_len = get_fld(str_input, str_ptr);
            msg_end = (msg_len * 2) + 8;                       // Adjust for two bytes per hexx digit, plus "header" + length
            str_ptr+=2;                                                // position pointer to point to the start of first field
            
            while (str_ptr < msg_end){                           // Parse message while there's still input to be had               
                fld_type = get_fld(str_input, str_ptr);          // Get Field Type
                str_ptr+=2;
                
                fld_len = get_fld(str_input, str_ptr);            // Get Field Length
                str_ptr+=2;
                fld_len = fld_len * 2;
                
                int j = 0;                                              // Get Field Value
                for (int i=str_ptr; i< fld_len + str_ptr - 1; i+=2){
                    fld_val[j++] = hex_to_ascii(str_input[i], str_input[i+1]);
                    fld_val[j] = '\0';
                }
                
                str_ptr += fld_len;                                 // decode field values using field type
                switch (fld_type) {
                    case 1: {
                        strcpy(str_date_time, fld_val);
                    } break;
                    case 2: {
                        strcpy(str_nbr, fld_val);
                    } break;
                    case 4: {
                        strcpy(str_nbr, "No Number");
                    } break;
                    case 7: {
                        strcpy(str_nam, fld_val);
                    } break;
                    case 8: {
                        strcpy(str_nam, "No Name");
                    } break;
                }
            }                                                         // end while parse message
            printf("Date: %s\n",str_date_time);
            printf("Number: %s\n",str_nbr);
            printf("Name: %s\n",str_nam);
            write_web_page(str_date_time, str_nbr, str_nam);
        }
        else {                                                      // else extraneous input (i.e. not MESG=...)
            printf("%s\n",str_input);                          // shouldn't be any - we turned off echo and status messages
        }
    }                                                               // end while fgets
}                                                                   // end main()

// Write out the web page that shows date, time, number, name
int write_web_page(char *str_date_time, char *str_nbr, char *str_nam){
    FILE *web_file;
    web_file = fopen("/users/markamos/Sites/index.html", "w");  // for Raspberry Pi use /var/www/index.html
    if (web_file == NULL) {
        fprintf(stderr, "Can't open output file\n");
    }
    // format the date and time and output a record to the web server.
    fprintf(web_file,"<html><body>\n");
    fprintf(web_file,"<p>Date: %c%c-%c%c</p>\n",str_date_time[0], str_date_time[1], str_date_time[2], str_date_time[3]);
    fprintf(web_file,"<p>Time: %c%c:%c%c</p>\n",str_date_time[4], str_date_time[5], str_date_time[6], str_date_time[7]);
    fprintf(web_file,"<p>Number: %s</p>\n", str_nbr);
    fprintf(web_file,"<p>Name: %s</p>\n", str_nam);
    fprintf(web_file,"</body></html>\n");
    fclose(web_file);
    
    return 0;
}

// Convert input hex characters to integer
int hex_to_int(int c){
    int first = c / 16 - 3;
    int second = c % 16;
    int result = first * 10 + second;
    if(result > 9) result--;
    return result;
}

int hex_to_ascii(int c, int d){
    int high = hex_to_int(c) * 16;
    int low = hex_to_int(d);
    return high+low;
}

int get_fld(char *fldBuf, int bufPtr){
    char fldStr[3] = "00";
    char *p;
    fldStr[0] = fldBuf[bufPtr++];
    fldStr[1] = fldBuf[bufPtr++];
    return (int) strtoul(fldStr, &p, 16);
}

No comments:

Post a Comment