Untethered Team

From BenningtonWiki

Jump to: navigation, search

| LINK TO MY SETUP FOR THE AIR PROJECT

Contents

"No strings attached."

camera code which needs to be assimilated

<source lang="c">

  1. include <NewSoftSerial.h>
  2. include <sd_raw_config.h>
  3. undef SD_RAW_WRITE_BUFFERING
  4. include <sd_raw.h>
  5. include <string.h>
  6. include <stdio.h>
  7. include <stdarg.h>
  1. define SD_RAW_WRITE_BUFFERING 0

//Analog inputs

  1. define TEMPERATURE_1 0
  2. define TEMPERATURE_2 1
  3. define TEMPERATURE_3 2
  4. define PRESSURE_1 3
  5. define PRESSURE_2 4
  6. define PRESSURE_3 5

//Digital Inputs

  1. define NUM_MAX395_CHIPS 3
  2. define NUM_MAX395_SWITCHES (NUM_MAX395_CHIPS*8)
  3. define SCLK_PIN 7 // max395 control line: synchronous clock. goes to max395 pin 1.
  4. define DIN_PIN 8 // max395 control line: data in. goes to max395 pin 3.
  5. define CS_PIN 9 // max395 control line: chip select. goes to max395 pin 24.
  6. define LIGHT_PIN 13

//Cameras on Max Chip

  1. define CAMERA_1 21
  2. define CAMERA_2 22

// For max395 power connect pins 2 and 23 to V+, pins 4 and 21 to GND.

static unsigned char max395_switches[NUM_MAX395_CHIPS]; //***************************************************** void max395Setup(void); void max395Write(int sw, int value);

void handle_gps(void); void handle_gps_sentence(char *s);

void rsprintf(const char *format, ...);

NewSoftSerial gps = NewSoftSerial(2, 3);

//***************************************************** //OUR VARIABLES FOR THE PROGRAM; Everything else is black box related. int hello = 0x9876; int log_count; int joe = 0;

//junk data for testing cell phone texting char hour, min, sec, year, mon, day, valid, iteration; char latitude[15], longitude[15]; char sequence[58]; boolean finished = false;


//Phone mapping to the max395 chip //in order, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, G, H, I, POUND, STAR const char phone[] = {12, 8, 15, 16, 9, 14, 17, 10, 13, 18, 0, 6, 7, 1, 2, 5, 4, 3, 20, 19, 11};


void setup() { const char msgStart[] = {12, 18, 18, 18, 18, 10, 18, 10, 17, 17, 17, 18}; for(int i = 0; i < 12; i++){ sequence[i] = msgStart[i]; rsprintf("%d\n", sequence[i]); } const char msgEnd[] = {18, 18, 17, 18, 5, 0, 3, 3, 1, 9, 2, 9, 3, 1, 18, 13}; for(int i = 42; i < 58; i++){ sequence[i] = msgEnd[i-42]; rsprintf("%d\n", sequence[i]); } // const char phoneNumber[] = {5, 0, 3, 3, 1, 9, 2, 9, 3, 1}; // for(int i = 48; i < 58; i++){ // sequence[i] = phoneNumber[i-48]; // rsprintf("%d\n", sequence[i]); // } //sd init sd_raw_init(); sd_check_format(); //max init max395Setup();

//gps setup

 pinMode(4, OUTPUT);
 pinMode(5, OUTPUT);
 pinMode(6, OUTPUT);

 digitalWrite(4, 0);  // POWER ON
 digitalWrite(5, 1);  // READY LED ON
 digitalWrite(6, 0);  // FIX LED OFF
 gps.begin(4800);

//end gps setup

rsprintf("HELO\n"); rsprintf("%d Logs are on the card\n", log_count); pinMode(LIGHT_PIN, OUTPUT); //Uncomment to run printout // sd_print_log(); // for(int i = 0; i < sizeof(sequence)/sizeof(sequence[0]); i++){ // rsprintf("%d\n", sequence[i]); // } // while(1) ; }

void loop() { digitalWrite(LIGHT_PIN, joe); unsigned long timer = millis(); //gps looping handle_gps(); digitalWrite(6, valid); //end gps looping take_picture_cam_1(timer); take_picture_cam_2(timer); save_data(timer); set_text(timer); button_mash(timer); }

void take_picture_cam_1(unsigned long t){

 static unsigned long check;
 static int phase;
 if(t < check){
   return;
 }
 else {switch (phase){
 case 0:  

phase = 1; check = 4000+t; max395Write(CAMERA_1, 1); rsprintf("CAMERA 1 ON\n"); break;

 case 1:  

phase = 2; check = 4000+t; max395Write(CAMERA_1, 0); rsprintf("CAMERA 1 INIT\n"); break;

 case 2:
   phase = 3;

check = 1000+t; max395Write(CAMERA_1, 1); rsprintf("CAMERA 1 PICTURE\n"); break;

 case 3:

phase = 0; check = 12000+t; max395Write(CAMERA_1, 0); rsprintf("CAMERA 1 OFF\n"); break;

   }
 }

}

void take_picture_cam_2(unsigned long t){

 static unsigned long check;
 static int phase;
 if(t < check){
   return;
 }
 else {switch (phase){
 case 0:  

phase = 1; check = 4000+t; max395Write(CAMERA_2, 1); rsprintf("CAMERA 2 ON\n"); break;

 case 1:  

phase = 2; check = 4000+t; max395Write(CAMERA_2, 1); rsprintf("CAMERA 2 INIT\n"); break;

 case 2:

phase = 3; check = 1000+t; max395Write(CAMERA_2, 1); rsprintf("CAMERA 2 PICTURE\n"); break;

 case 3:

phase = 0; check = 12000+t; max395Write(CAMERA_2, 0); rsprintf("CAMERA 2 OFF\n"); break;

   }
 }

}

void save_data(unsigned long t){ static unsigned long check; if(t >= check){ //*******NO PRESSURE IMPLEMENTED YET>>>>******** // int read1 = analogRead(PRESSURE_1); // int read2 = analogRead(PRESSURE_2);

int temp1 = analogRead(TEMPERATURE_1); int temp2 = analogRead(TEMPERATURE_2); int temp3 = analogRead(TEMPERATURE_3);

rsprintf("Temperature: %d,%d,%d\nLog Count: %ld\n\n\n", temp1, temp2, temp3, millis()/1000); sd_log(temp1, temp2, temp3, hour, min, sec, year, mon, day, valid, latitude, longitude, millis()/1000); joe = !joe; check = t+1000; } }

void set_text(unsigned long t){ static unsigned long check; char latitudeNow[15]; char longitudeNow[15]; for(int i = 0; i < sizeof(latitude)/sizeof(latitude[0]); i++){ char digit = latitude[i]-48; if(digit < 0){ latitudeNow[i] = 0; } else if (digit > 9){ latitudeNow[i] = 0; } else latitudeNow[i] = latitude[i]-48; } for(int i = 0; i < sizeof(longitude)/sizeof(longitude[0]); i++){ char digit = longitude[i]-48; if(digit < 0){ longitudeNow[i] = 0; } else if (digit > 9){ longitudeNow[i] = 0; } else longitudeNow[i] = longitude[i]-48; } if(t >= check){ iteration = 0; for(int i = 12; i < 27; i++){ sequence[i] = latitudeNow[i-12]; } for(int i = 27; i < 42; i++){ sequence[i] = longitudeNow[i-27]; } check = t + 120000; finished = false; } }


void button_mash(unsigned long t){ if(!finished){ if(iteration < sizeof(sequence)/sizeof(sequence[0])){ unsigned long timer = millis(); static unsigned long check; static int phase; if(timer >= check){ if(phase == 0){ phase = 1; check = 500+timer; max395Write(phone[sequence[iteration]], 1); rsprintf("%d\n", sequence[iteration]); } else if(phase == 1){ phase = 0; check = 1000+timer; max395Write(phone[sequence[iteration]], 0); iteration++; } } } else if(iteration >= sizeof(sequence)/sizeof(sequence[0])){ finished = true; } } }

struct memory{ char hour, min, sec, year, mon, day, valid; char latitude[15], longitude[15]; int tempRead1, tempRead2, tempRead3; long log_count; };

void sd_log(int tempRead1, int tempRead2, int tempRead3, char hour, char min, char sec, char year, char mon, char day, char valid, char latitude[15], char longitude[15], long timeStamp){

 struct memory mem;

//pressure

 // mem.pressureRead1 = pinRead1;mem.pressureRead2 = pinRead2;
 //temperature

mem.tempRead1 = tempRead1;mem.tempRead2 = tempRead2;mem.tempRead3 = tempRead3; //date mem.hour = hour;mem.min = min;mem.sec = sec;mem.year = year;mem.mon = mon; mem.day = day;mem.valid = valid; //lat+long mem.latitude[15] = latitude[15];mem.longitude[15] = longitude[15]; //log_count

 mem.log_count = timeStamp;
 sd_read(4, &log_count, sizeof(log_count));
 sd_write(((log_count * sizeof(mem)) + 8 ), &mem, sizeof(mem));
 ++log_count;
 sd_write(4, &log_count, sizeof(log_count));

}

void sd_print_log() { struct memory mem; sd_read(4, &log_count, sizeof(log_count)); for (long i=0; i < log_count; ++i) { sd_read(i*sizeof(mem)+8, &mem, sizeof(mem)); rsprintf("%ld: %d,%d,%d,%d,%ld\n", i, mem.tempRead1, mem.tempRead2, mem.tempRead3, mem.log_count); rsprintf(", location: %s, %s\n", mem.latitude, mem.longitude); } }

//********************************************************************************************** // // EVERYTHING BELOW THIS IS BLACK BOX; ABOVE IS PROJECT SPECIFIC. // //**********************************************************************************************


void rsprintf(const char *format, ...) {

   static unsigned char inited = 0;
   char msg[100];
   va_list ap;
   if (!inited) {
       Serial.begin(9600);
       inited = 1;
   }
   va_start(ap, format);
   vsnprintf(msg, sizeof(msg)-1, format, ap);
   Serial.print(msg);
   va_end(ap);

}


//********************************************************************************************** // // SD CARD support //

void sd_format(){

 int id;
 rsprintf("in sd_format\n");
 sd_write(0, &hello, sizeof(hello)); 
 sd_read(0, &id, sizeof(id)); 
 rsprintf("id    %08x\n", id);
 log_count = 0;
 sd_write(4, &log_count, sizeof(log_count)); 

}

void sd_check_format(){

 int id;
 sd_read(0, &id, sizeof(id)); 
 rsprintf("id    %08x\n", id);
 rsprintf("Hello %08x\n", hello);
 if (id != hello){ 
   sd_format();
 }
 sd_read(4, &log_count, sizeof(log_count)); 

}

void sd_write(uint32_t offset, void *buffer, uint16_t length) {

 sd_raw_write(offset, (uint8_t *) buffer, length);
 sd_raw_sync();

}

void sd_read(uint32_t offset, void *buffer, uint16_t length) {

 sd_raw_read(offset, (uint8_t *) buffer, length);

}


//********************************************************************************************** // // Max395 support //

// The Max395 is connected to three digital output pins on the Arduino



void output_max395_switches(void);

// sets all of the max395_switches to off
// sets the arduino's pins to the necessary output mode
// clears the max395 chip select
void max395Setup(void) {
    int i;
    for (i = 0; i < NUM_MAX395_CHIPS; ++i)
        max395_switches[i] = 0;
    pinMode(SCLK_PIN, OUTPUT);
    pinMode(DIN_PIN, OUTPUT);
    pinMode(CS_PIN, OUTPUT);
    digitalWrite(CS_PIN, HIGH);
    digitalWrite(SCLK_PIN, LOW);
    digitalWrite(DIN_PIN, LOW);
    output_max395_switches();
}


// for value: 1 means on, 0 means off, -1 means opposite

void max395Write(int sw, int value) {

   int m, s, b, v;
   if (sw < 0 || sw >= NUM_MAX395_SWITCHES)
       return;
   m = sw / 8;
   s = sw % 8;
   b = 1 << s;
   v = max395_switches[m];
   if (value >= 1)
       v |= b;
   else if (value == 0)
       v &= (b ^ 0xFF);
   else if (value <= -1)
       v ^= b;
   max395_switches[m] = v;
   output_max395_switches();

}

  1. if 0

// for value: 1 means on, 0 means off int get_max395_switch(int sw) {

   int m, s, b, v;
   if (sw < 0 || sw >= NUM_MAX395_SWITCHES)
       return 0;
   m = sw / 8;
   s = sw % 8;
   b = 1 << s;
   v = max395_switches[m];
   return (v & b) != 0;

}

  1. endif

// call this whenever you want the max395 switches to change // outputs the contents of the max395_switches array to the max395s void output_max395_switches(void) {

   int i, j;
   digitalWrite(SCLK_PIN, LOW);
   digitalWrite(CS_PIN, LOW);
   for (i = NUM_MAX395_CHIPS - 1; i >= 0; --i) {
       int val = max395_switches[i];
       int mask = 0x80;
       for (j = 7; j >= 0; --j) {
           digitalWrite(DIN_PIN, (val & mask) != 0);
           digitalWrite(SCLK_PIN, HIGH);
           digitalWrite(SCLK_PIN, LOW);
           mask >>= 1;
       }
   }
   digitalWrite(CS_PIN, HIGH);

}


//********************************************************************************************** // // GPS support //

void handle_gps(void) {

   static char sentence[100];
   static unsigned char sentence_idx = 0;
   char ch;

   while (gps.available()) {
       ch = gps.read();
       if (ch == '\n') {
           if (sentence_idx < sizeof(sentence)) {
               sentence[sentence_idx] = '\0';
               handle_gps_sentence(sentence);
           } else {
               rsprintf("Sentence too long; ignored.\n");
           }
           sentence_idx = 0;
       } else {
           if (sentence_idx < sizeof(sentence)-1)
               sentence[sentence_idx++] = ch;
       }
   }

}

void handle_gps_sentence(char *s) {

   char ch;
   char *st;
   int len;
   int field;
   int type;

// rsprintf(">> %s\n", s);

   type = 0;
   field = 0;
   st = s;
   while (1) {
       ch = *s++;
       if (ch == '\0' || ch == ',') {
           len = s - st - 1;
           if (field == 0) {
               if (memcmp("$GPRMC", st, len) == 0)
                   type = 1;
           } else {
               switch (type) {
               case 1:
                   handle_rmc(field, st, len);
                   break;
               }
           }
           if (ch == '\0')
               break;
           ++field;
           st = s;
       }
   }

   if (type == 1) {
       rsprintf("time: %02d/%02d/%02d %02d:%02d:%02d UTC", mon, day, year, hour, min, sec);
       if (valid)
           rsprintf(", location: %s, %s\n", latitude, longitude);
       else
           rsprintf("\n");
   }

}

// $GPRMC,193617.000,A,4255.2006,N,07314.3301,W,0.18,116.24,190309,,*13

void handle_rmc(int field, char *st, int len) {

   int l;

   switch (field) {
   case 1:
       if (len == 10) {
           hour = atoilen(st+0, 2);
           min  = atoilen(st+2, 2);
           sec  = atoilen(st+4, 2);
       }
       break;

   case 2:
       valid = (*st == 'A');
       break;

   case 3:
       if (len < sizeof(latitude)-1) {
           memcpy(latitude, st, len);
           latitude[len] = '\0';
       }
       break;

   case 4:
       l = strlen(latitude);
       latitude[l++] = *st;
       latitude[l] = '\0';
       break;

   case 5:
       if (len < sizeof(longitude)-1) {
           memcpy(longitude, st, len);
           longitude[len] = '\0';
       }
       break;

   case 6:
       l = strlen(longitude);
       longitude[l++] = *st;
       longitude[l] = '\0';
       break;

   case 9:
       if (len == 6) {
           day  = atoilen(st+0, 2);
           mon  = atoilen(st+2, 2);
           year = atoilen(st+4, 2);
       }
       break;
   }

}

int atoilen(char *s, int len) {

   int x = 0;
   while (len-- > 0)
       x = (x*10) + (*s++ - '0');
   return x;

} </source> <source lang="c">

void camera(unsigned long t){

 static unsigned long check;
 static int phase;
 if(t < check){
   return;
 }
 else {switch (phase){
 case 0:  
   phase = 1;
     check = 1000+t;
     max395Write(21, 1);
 case 1;
     phase = 0;
     check = 10000+t;
     max395Write(21, 0);
   }
 }

} </source>

Week two

(*Almost) Final code for project

The following is code that works, with the path set out, for our phones. everything is ready software wise for the project; although it is functional, i do want it to use less memory (just for the sake of being badass). right now i have it sending a text every minute, but that will change, obviously. Also, this hasn't been actually tested with a phone, just with the breadboard that i have. all the ascii characters in a gps log (like N, W, and .) are converted to 0. we can track back when we get the text message and convert it manually, as I have done this few times and it works fine when you put it in google maps. Code is as follows:

<source lang="c">

  1. include <NewSoftSerial.h>
  2. include <sd_raw_config.h>
  3. undef SD_RAW_WRITE_BUFFERING
  4. include <sd_raw.h>
  5. include <string.h>
  6. include <stdio.h>
  7. include <stdarg.h>
  1. define SD_RAW_WRITE_BUFFERING 0

//Analog inputs

  1. define PRESSURE_1 0
  2. define PRESSURE_2 1
  3. define PRESSURE_3 2
  4. define TEMPERATURE_1 3
  5. define TEMPERATURE_2 4
  6. define TEMPERATURE_3 5

//Digital Inputs

  1. define NUM_MAX395_CHIPS 3
  2. define NUM_MAX395_SWITCHES (NUM_MAX395_CHIPS*8)
  3. define SCLK_PIN 7 // max395 control line: synchronous clock. goes to max395 pin 1.
  4. define DIN_PIN 8 // max395 control line: data in. goes to max395 pin 3.
  5. define CS_PIN 9 // max395 control line: chip select. goes to max395 pin 24.
  6. define LIGHT_PIN 13

// For max395 power connect pins 2 and 23 to V+, pins 4 and 21 to GND.

static unsigned char max395_switches[NUM_MAX395_CHIPS]; //***************************************************** void max395Setup(void); void max395Write(int sw, int value);

void handle_gps(void); void handle_gps_sentence(char *s);

void rsprintf(const char *format, ...);

NewSoftSerial gps = NewSoftSerial(2, 3);

//***************************************************** //OUR VARIABLES FOR THE PROGRAM; Everything else is black box related. int hello = 0x9876; int log_count; int joe = 0;

//junk data for testing cell phone texting char hour, min, sec, year, mon, day, valid, iteration; char latitude[15], longitude[15]; char sequence[53]; boolean finished = false;

//Phone mapping to the max395 chip //in order, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, G, H, I, POUND, STAR const char phone[] = {12, 8, 15, 16, 9, 14, 17, 10, 13, 18, 0, 7, 6, 1, 2, 5, 4, 3, 20, 19, 11};

void setup() { const char msgStart[] = {20, 11, 20, 20, 20, 20, 19, 20}; for(int i = 0; i < 8; i++){ sequence[i] = msgStart[i]; rsprintf("%d\n", sequence[i]); } const char phoneNumber[] = {5, 0, 3, 3, 1, 9, 2, 9, 3, 1}; for(int i = 8; i < 18; i++){ sequence[i] = phoneNumber[i-sizeof(msgStart)/sizeof(msgStart[0])]; rsprintf("%d\n", sequence[i]); } const char msgEnd[] = {20, 20, 20, 20, 20}; for(int i = 48; i < 53; i++){ sequence[i] = msgEnd[i-48]; rsprintf("%d\n", sequence[i]); } //sd init sd_raw_init(); sd_check_format(); //max init max395Setup();

//gps setup

 pinMode(4, OUTPUT);
 pinMode(5, OUTPUT);
 pinMode(6, OUTPUT);
 
 digitalWrite(4, 0);  // POWER ON
 digitalWrite(5, 1);  // READY LED ON
 digitalWrite(6, 0);  // FIX LED OFF
 gps.begin(4800);

//end gps setup

rsprintf("HELO\n"); rsprintf("%d Logs are on the card\n", log_count); pinMode(LIGHT_PIN, OUTPUT); //Uncomment to run printout // sd_print_log(); // while(1) ; }

void loop() { digitalWrite(LIGHT_PIN, joe); unsigned long timer = millis(); //gps looping handle_gps(); digitalWrite(6, valid); //end gps looping save_data(timer); set_text(timer); button_mash(timer); }

void save_data(unsigned long t){ static unsigned long check; if(t >= check){ int read1 = analogRead(PRESSURE_1); int read2 = analogRead(PRESSURE_2);

int temp1 = analogRead(TEMPERATURE_1); int temp2 = analogRead(TEMPERATURE_2);

// rsprintf("Pressure: %d,%d\nTemperature: %d,%d\nLog Count: %ld\n\n\n", read1, read2, temp1, temp2, millis()/1000); sd_log(read1, read2, temp1, temp2, hour, min, sec, year, mon, day, valid, latitude, longitude, millis()/1000); joe = !joe; check = t+1000; } }

void set_text(unsigned long t){ static unsigned long check; char latitudeNow[15]; char longitudeNow[15]; for(int i = 0; i < sizeof(latitude)/sizeof(latitude[0]); i++){ char digit = latitude[i]-48; if(digit < 0){ latitudeNow[i] = 0; } else if (digit > 9){ latitudeNow[i] = 0; } else latitudeNow[i] = latitude[i]-48; } for(int i = 0; i < sizeof(longitude)/sizeof(longitude[0]); i++){ char digit = longitude[i]-48; if(digit < 0){ longitudeNow[i] = 0; } else if (digit > 9){ longitudeNow[i] = 0; } else longitudeNow[i] = longitude[i]-48; } if(t >= check){ iteration = 0; for(int i = 18; i < 33; i++){ sequence[i] = latitudeNow[i-18]; } for(int i = 33; i < 48; i++){ sequence[i] = longitudeNow[i-33]; } check = t + 60000; finished = false; } }


void button_mash(unsigned long t){ if(!finished){ if(iteration < sizeof(sequence)/sizeof(sequence[0])){ unsigned long timer = millis(); static unsigned long check; static int phase; if(timer >= check){ if(phase == 0){ phase = 1; check = 1000+timer; max395Write(phone[sequence[iteration]], 1); rsprintf("%d\n", sequence[iteration]); } else if(phase == 1){ phase = 0; check = 1000+timer; max395Write(phone[sequence[iteration]], 0); iteration++; } } } else if(iteration >= sizeof(sequence)/sizeof(sequence[0])){ finished = true; } } }

struct memory{ char hour, min, sec, year, mon, day, valid; char latitude[15], longitude[15]; int pressureRead1, pressureRead2, tempRead1, tempRead2; long log_count; };

void sd_log(int pinRead1, int pinRead2, int tempRead1, int tempRead2, char hour, char min, char sec, char year, char mon, char day, char valid, char latitude[15], char longitude[15], long timeStamp){

 struct memory mem;

//pressure

 mem.pressureRead1 = pinRead1;mem.pressureRead2 = pinRead2;
 //temperature

mem.tempRead1 = tempRead1;mem.tempRead2 = tempRead2; //date mem.hour = hour;mem.min = min;mem.sec = sec;mem.year = year;mem.mon = mon; mem.day = day;mem.valid = valid; //lat+long mem.latitude[15] = latitude[15];mem.longitude[15] = longitude[15]; //log_count

 mem.log_count = timeStamp;
 sd_read(4, &log_count, sizeof(log_count));
 sd_write(((log_count * sizeof(mem)) + 8 ), &mem, sizeof(mem));
 ++log_count;
 sd_write(4, &log_count, sizeof(log_count));

}

void sd_print_log() { struct memory mem; sd_read(4, &log_count, sizeof(log_count)); for (long i=0; i < log_count; ++i) { sd_read(i*sizeof(mem)+8, &mem, sizeof(mem)); rsprintf("%ld: %d,%d,%d,%d,%ld\n", i, mem.pressureRead1, mem.pressureRead2, mem.tempRead1, mem.tempRead2, mem.log_count); rsprintf(", location: %s, %s\n", mem.latitude, mem.longitude); } }

//********************************************************************************************** // // EVERYTHING BELOW THIS IS BLACK BOX; ABOVE IS PROJECT SPECIFIC. // //**********************************************************************************************


void rsprintf(const char *format, ...) {

   static unsigned char inited = 0;
   char msg[100];
   va_list ap;
   if (!inited) {
       Serial.begin(9600);
       inited = 1;
   }
   va_start(ap, format);
   vsnprintf(msg, sizeof(msg)-1, format, ap);
   Serial.print(msg);
   va_end(ap);

}


//********************************************************************************************** // // SD CARD support //

void sd_format(){

 int id;
 rsprintf("in sd_format\n");
 sd_write(0, &hello, sizeof(hello)); 
 sd_read(0, &id, sizeof(id)); 
 rsprintf("id    %08x\n", id);
 log_count = 0;
 sd_write(4, &log_count, sizeof(log_count)); 

}

void sd_check_format(){

 int id;
 sd_read(0, &id, sizeof(id)); 
 rsprintf("id    %08x\n", id);
 rsprintf("Hello %08x\n", hello);
 if (id != hello){ 
   sd_format();
 }
 sd_read(4, &log_count, sizeof(log_count)); 

}

void sd_write(uint32_t offset, void *buffer, uint16_t length) {

 sd_raw_write(offset, (uint8_t *) buffer, length);
 sd_raw_sync();

}

void sd_read(uint32_t offset, void *buffer, uint16_t length) {

 sd_raw_read(offset, (uint8_t *) buffer, length);

}


//********************************************************************************************** // // Max395 support //

// The Max395 is connected to three digital output pins on the Arduino



void output_max395_switches(void);

// sets all of the max395_switches to off
// sets the arduino's pins to the necessary output mode
// clears the max395 chip select
void max395Setup(void) {
    int i;
    for (i = 0; i < NUM_MAX395_CHIPS; ++i)
        max395_switches[i] = 0;
    pinMode(SCLK_PIN, OUTPUT);
    pinMode(DIN_PIN, OUTPUT);
    pinMode(CS_PIN, OUTPUT);
    digitalWrite(CS_PIN, HIGH);
    digitalWrite(SCLK_PIN, LOW);
    digitalWrite(DIN_PIN, LOW);
    output_max395_switches();
}


// for value: 1 means on, 0 means off, -1 means opposite

void max395Write(int sw, int value) {

   int m, s, b, v;
   if (sw < 0 || sw >= NUM_MAX395_SWITCHES)
       return;
   m = sw / 8;
   s = sw % 8;
   b = 1 << s;
   v = max395_switches[m];
   if (value >= 1)
       v |= b;
   else if (value == 0)
       v &= (b ^ 0xFF);
   else if (value <= -1)
       v ^= b;
   max395_switches[m] = v;
   output_max395_switches();

}

  1. if 0

// for value: 1 means on, 0 means off int get_max395_switch(int sw) {

   int m, s, b, v;
   if (sw < 0 || sw >= NUM_MAX395_SWITCHES)
       return 0;
   m = sw / 8;
   s = sw % 8;
   b = 1 << s;
   v = max395_switches[m];
   return (v & b) != 0;

}

  1. endif

// call this whenever you want the max395 switches to change // outputs the contents of the max395_switches array to the max395s void output_max395_switches(void) {

   int i, j;
   digitalWrite(SCLK_PIN, LOW);
   digitalWrite(CS_PIN, LOW);
   for (i = NUM_MAX395_CHIPS - 1; i >= 0; --i) {
       int val = max395_switches[i];
       int mask = 0x80;
       for (j = 7; j >= 0; --j) {
           digitalWrite(DIN_PIN, (val & mask) != 0);
           digitalWrite(SCLK_PIN, HIGH);
           digitalWrite(SCLK_PIN, LOW);
           mask >>= 1;
       }
   }
   digitalWrite(CS_PIN, HIGH);

}


//********************************************************************************************** // // GPS support //

void handle_gps(void) {

   static char sentence[100];
   static unsigned char sentence_idx = 0;
   char ch;
   while (gps.available()) {
       ch = gps.read();
       if (ch == '\n') {
           if (sentence_idx < sizeof(sentence)) {
               sentence[sentence_idx] = '\0';
               handle_gps_sentence(sentence);
           } else {
               rsprintf("Sentence too long; ignored.\n");
           }
           sentence_idx = 0;
       } else {
           if (sentence_idx < sizeof(sentence)-1)
               sentence[sentence_idx++] = ch;
       }
   }

}

void handle_gps_sentence(char *s) {

   char ch;
   char *st;
   int len;
   int field;
   int type;

// rsprintf(">> %s\n", s);

   type = 0;
   field = 0;
   st = s;
   while (1) {
       ch = *s++;
       if (ch == '\0' || ch == ',') {
           len = s - st - 1;
           if (field == 0) {
               if (memcmp("$GPRMC", st, len) == 0)
                   type = 1;
           } else {
               switch (type) {
               case 1:
                   handle_rmc(field, st, len);
                   break;
               }
           }
           if (ch == '\0')
               break;
           ++field;
           st = s;
       }
   }
   if (type == 1) {
       rsprintf("time: %02d/%02d/%02d %02d:%02d:%02d UTC", mon, day, year, hour, min, sec);
       if (valid)
           rsprintf(", location: %s, %s\n", latitude, longitude);
       else
           rsprintf("\n");
   }

}

// $GPRMC,193617.000,A,4255.2006,N,07314.3301,W,0.18,116.24,190309,,*13

void handle_rmc(int field, char *st, int len) {

   int l;
   switch (field) {
   case 1:
       if (len == 10) {
           hour = atoilen(st+0, 2);
           min  = atoilen(st+2, 2);
           sec  = atoilen(st+4, 2);
       }
       break;
   case 2:
       valid = (*st == 'A');
       break;
   case 3:
       if (len < sizeof(latitude)-1) {
           memcpy(latitude, st, len);
           latitude[len] = '\0';
       }
       break;
   case 4:
       l = strlen(latitude);
       latitude[l++] = *st;
       latitude[l] = '\0';
       break;
   case 5:
       if (len < sizeof(longitude)-1) {
           memcpy(longitude, st, len);
           longitude[len] = '\0';
       }
       break;
   case 6:
       l = strlen(longitude);
       longitude[l++] = *st;
       longitude[l] = '\0';
       break;
   case 9:
       if (len == 6) {
           day  = atoilen(st+0, 2);
           mon  = atoilen(st+2, 2);
           year = atoilen(st+4, 2);
       }
       break;
   }

}

int atoilen(char *s, int len) {

   int x = 0;
   while (len-- > 0)
       x = (x*10) + (*s++ - '0');
   return x;

} </source> Theoretically, the cell phone should work now; the first thing below is the real code for the entire project as it stands right now. Review if you want to. The code will not work yet, as we are now WAY over the ram limit with an atmega 168; we will have to install the 328 for this to work. That is why i'm also including a program that is just the proof of concept for the max chip sending to a cell phone; since the other parts of the code (SD Writing, GPS Logging) are completely separated (except for texting latitude and longitude, which are instead junk data in the proof of concept), I don't see any reason why there should be any issue with running this.

Things left with the code:

1. Get the trail for sending a text down 2. Debug any issues along the way 3. The things stored in ram should be cut in half; this is profoundly sloppy, resource hog code. My Apologies. Revisions will come.

airProject.c

<source lang="c">

  1. include <NewSoftSerial.h>
  2. include <sd_raw_config.h>
  3. undef SD_RAW_WRITE_BUFFERING
  4. include <sd_raw.h>
  5. include <string.h>
  6. include <stdio.h>
  7. include <stdarg.h>
  1. define SD_RAW_WRITE_BUFFERING 0

//Analog inputs

  1. define PRESSURE_1 0
  2. define PRESSURE_2 1
  3. define PRESSURE_3 2
  4. define TEMPERATURE_1 3
  5. define TEMPERATURE_2 4
  6. define TEMPERATURE_3 5

//Digital Inputs

  1. define NUM_MAX395_CHIPS 3
  2. define NUM_MAX395_SWITCHES (NUM_MAX395_CHIPS*8)
  3. define SCLK_PIN 2 // max395 control line: synchronous clock. goes to max395 pin 1.
  4. define DIN_PIN 3 // max395 control line: data in. goes to max395 pin 3.
  5. define CS_PIN 4 // max395 control line: chip select. goes to max395 pin 24.
  6. define LIGHT_PIN 13

// For max395 power connect pins 2 and 23 to V+, pins 4 and 21 to GND.

static unsigned char max395_switches[NUM_MAX395_CHIPS]; //***************************************************** void max395Setup(void); void max395Write(int sw, int value);

void handle_gps(void); void handle_gps_sentence(char *s);

void rsprintf(const char *format, ...); //*****************************************************

NewSoftSerial gps = NewSoftSerial(2, 3); //***************************************************** //OUR VARIABLES FOR THE PROGRAM; Everything else is black box related. int hello = 0x9876; int log_count; int joe = 0;

char hour, min, sec, year, mon, day, valid, iteration; char latitude[15] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3}; char longitude[15] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3}; char sequence[40]; boolean finished = false; //*****************************************************

const char phone[] = {12, 8, 15, 16, 9, 14, 17, 10, 13, 18, 0, 7, 6, 1, 2, 5, 4, 3, 20, 19, 11};

void setup(){ const char phoneNumber[10] = {5, 0, 3, 3, 1, 9, 2, 9, 3, 1}; for(int i = 0; i < 10; i++){ sequence[i] = phoneNumber[i]; rsprintf("%d\n", sequence[i]); } //sd init sd_raw_init(); sd_check_format(); //max init max395Setup(); //gps setup

 pinMode(4, OUTPUT);
 pinMode(5, OUTPUT);
 pinMode(6, OUTPUT);
 digitalWrite(4, 0);  // POWER ON
 digitalWrite(5, 1);  // READY LED ON
 digitalWrite(6, 0);  // FIX LED OFF
 gps.begin(4800);

//end gps setup rsprintf("HELO\n"); rsprintf("%d Logs are on the card\n", log_count); pinMode(LIGHT_PIN, OUTPUT); //Uncomment to run printout // sd_print_log(); // while(1) ; }

void loop(){

 rsprintf("||||||||||||||||||||||||||||||||||||||||||||||||||||\n");

digitalWrite(LIGHT_PIN, joe); rsprintf("The light is %d\n", joe); unsigned long timer = millis(); save_data(timer); set_text(timer); button_mash(timer); }

void save_data(unsigned long t){ static unsigned long check; if(t >= check){ int read1 = analogRead(PRESSURE_1); int read2 = analogRead(PRESSURE_2);

int temp1 = analogRead(TEMPERATURE_1); int temp2 = analogRead(TEMPERATURE_2);

//gps looping handle_gps(); digitalWrite(6, valid); //end gps looping

rsprintf("Pressure: %d,%d\nTemperature: %d,%d\n Log Count: %ld\n\n\n", read1, read2, temp1, temp2, millis()/1000); sd_log(read1, read2, temp1, temp2, hour, min, sec, year, mon, day, valid, latitude, longitude, millis()/1000); joe = !joe; check = t+1000; } }

void set_text(unsigned long t){ static unsigned long check; char latitudeNow[15]; char longitudeNow[15]; for(int i = 0; i < sizeof(latitude)/sizeof(latitude[0]); i++){ latitudeNow[i] = latitude[i]; } for(int i = 0; i < sizeof(longitude)/sizeof(longitude[0]); i++){ longitudeNow[i] = longitude[i]; } if(t >= check){ iteration = 0; for(int i = 10; i < sizeof(latitudeNow)/sizeof(latitudeNow[0])+10; i++){ sequence[i] = latitudeNow[i-10]; } for(int i = sizeof(latitudeNow)/sizeof(latitudeNow[0])+10; i < sizeof(sequence)/sizeof(sequence[0]); i++){ sequence[i] = longitudeNow[i-25]; } check = t + 48000; finished = false; } }


void button_mash(unsigned long t){ if(!finished){ if(iteration < sizeof(sequence)/sizeof(sequence[0])){ unsigned long timer = millis(); static unsigned long check; static int phase; if(timer >= check){ if(phase == 0){ phase = 1; check = 125+timer; max395Write(phone[sequence[iteration]], 1); rsprintf("%d\n", sequence[iteration]); } else if(phase == 1){ phase = 0; check = 250+timer; max395Write(phone[sequence[iteration]], 0); iteration++; } } } else if(iteration >= sizeof(sequence)/sizeof(sequence[0])){ finished = true; } } }

struct memory{ char hour, min, sec, year, mon, day, valid; char latitude[15], longitude[15]; int pressureRead1, pressureRead2, tempRead1, tempRead2; long log_count; };

void sd_log(int pinRead1, int pinRead2, int tempRead1, int tempRead2, char hour, char min, char sec, char year, char mon, char day, char valid, char latitude[15], char longitude[15], long timeStamp){

 struct memory mem;

//pressure

 mem.pressureRead1 = pinRead1;mem.pressureRead2 = pinRead2;
 //temperature

mem.tempRead1 = tempRead1;mem.tempRead2 = tempRead2; //date mem.hour = hour;mem.min = min;mem.sec = sec;mem.year = year;mem.mon = mon; mem.day = day;mem.valid = valid; //lat+long mem.latitude[15] = latitude[15];mem.longitude[15] = longitude[15]; //log_count

 mem.log_count = timeStamp;
 sd_read(4, &log_count, sizeof(log_count));
 sd_write(((log_count * sizeof(mem)) + 8 ), &mem, sizeof(mem));
 ++log_count;
 sd_write(4, &log_count, sizeof(log_count));

}

void sd_print_log() { struct memory mem; sd_read(4, &log_count, sizeof(log_count)); for (long i=0; i < log_count; ++i) { sd_read(i*sizeof(mem)+8, &mem, sizeof(mem)); rsprintf("%ld: %d,%d,%d,%d,%ld\n", i, mem.pressureRead1, mem.pressureRead2, mem.tempRead1, mem.tempRead2, mem.log_count); rsprintf(", location: %s, %s\n", mem.latitude, mem.longitude); } } //********************************************************************************************** // // EVERYTHING BELOW THIS IS BLACK BOX; ABOVE IS PROJECT SPECIFIC. // //**********************************************************************************************


void rsprintf(const char *format, ...) {

   static unsigned char inited = 0;
   char msg[100];
   va_list ap;
   if (!inited) {
       Serial.begin(9600);
       inited = 1;
   }
   va_start(ap, format);
   vsnprintf(msg, sizeof(msg)-1, format, ap);
   Serial.print(msg);
   va_end(ap);

}


//********************************************************************************************** // // SD CARD support //

void sd_format(){

 int id;
 rsprintf("in sd_format\n");
 sd_write(0, &hello, sizeof(hello)); 
 sd_read(0, &id, sizeof(id)); 
 rsprintf("id    %08x\n", id);
 log_count = 0;
 sd_write(4, &log_count, sizeof(log_count)); 

}

void sd_check_format(){

 int id;
 sd_read(0, &id, sizeof(id)); 
 rsprintf("id    %08x\n", id);
 rsprintf("Hello %08x\n", hello);
 if (id != hello){ 
   sd_format();
 }
 sd_read(4, &log_count, sizeof(log_count)); 

}

void sd_write(uint32_t offset, void *buffer, uint16_t length) {

 sd_raw_write(offset, (uint8_t *) buffer, length);
 sd_raw_sync();

}

void sd_read(uint32_t offset, void *buffer, uint16_t length) {

 sd_raw_read(offset, (uint8_t *) buffer, length);

}


//********************************************************************************************** // // Max395 support //

// The Max395 is connected to three digital output pins on the Arduino



void output_max395_switches(void);
// sets all of the max395_switches to off
// sets the arduino's pins to the necessary output mode
// clears the max395 chip select
void max395Setup(void) {
    int i;
    for (i = 0; i < NUM_MAX395_CHIPS; ++i)
        max395_switches[i] = 0;
    pinMode(SCLK_PIN, OUTPUT);
    pinMode(DIN_PIN, OUTPUT);
    pinMode(CS_PIN, OUTPUT);
    digitalWrite(CS_PIN, HIGH);
    digitalWrite(SCLK_PIN, LOW);
    digitalWrite(DIN_PIN, LOW);
    output_max395_switches();
}


// for value: 1 means on, 0 means off, -1 means opposite
void max395Write(int sw, int value) {
    int m, s, b, v;
    if (sw < 0 || sw >= NUM_MAX395_SWITCHES)
        return;
    m = sw / 8;
    s = sw % 8;
    b = 1 << s;
    v = max395_switches[m];
    if (value >= 1)
        v |= b;
    else if (value == 0)
        v &= (b ^ 0xFF);
    else if (value <= -1)
        v ^= b;
    max395_switches[m] = v;
    output_max395_switches();
}
#if 0
// for value: 1 means on, 0 means off
int get_max395_switch(int sw) {
    int m, s, b, v;
    if (sw < 0 || sw >= NUM_MAX395_SWITCHES)
        return 0;
    m = sw / 8;
    s = sw % 8;
    b = 1 << s;
    v = max395_switches[m];
    return (v & b) != 0;
}
#endif
// call this whenever you want the max395 switches to change
// outputs the contents of the max395_switches array to the max395s
void output_max395_switches(void) {
    int i, j;
    digitalWrite(SCLK_PIN, LOW);
    digitalWrite(CS_PIN, LOW);
    for (i = NUM_MAX395_CHIPS - 1; i >= 0; --i) {
        int val = max395_switches[i];
        int mask = 0x80;
        for (j = 7; j >= 0; --j) {
            digitalWrite(DIN_PIN, (val & mask) != 0);
            digitalWrite(SCLK_PIN, HIGH);
            digitalWrite(SCLK_PIN, LOW);
            mask >>= 1;
        }
    }
    digitalWrite(CS_PIN, HIGH);
}


//********************************************************************************************** // // GPS support //

void handle_gps(void) {

   static char sentence[100];
   static unsigned char sentence_idx = 0;
   char ch;
   while (gps.available()) {
       ch = gps.read();
       if (ch == '\n') {
           if (sentence_idx < sizeof(sentence)) {
               sentence[sentence_idx] = '\0';
               handle_gps_sentence(sentence);
           } else {
               rsprintf("Sentence too long; ignored.\n");
           }
           sentence_idx = 0;
       } else {
           if (sentence_idx < sizeof(sentence)-1)
               sentence[sentence_idx++] = ch;
       }
   }

}

void handle_gps_sentence(char *s) {

   char ch;
   char *st;
   int len;
   int field;
   int type;

// rsprintf(">> %s\n", s);

   type = 0;
   field = 0;
   st = s;
   while (1) {
       ch = *s++;
       if (ch == '\0' || ch == ',') {
           len = s - st - 1;
           if (field == 0) {
               if (memcmp("$GPRMC", st, len) == 0)
                   type = 1;
           } else {
               switch (type) {
               case 1:
                   handle_rmc(field, st, len);
                   break;
               }
           }
           if (ch == '\0')
               break;
           ++field;
           st = s;
       }
   }
   if (type == 1) {
       rsprintf("time: %02d/%02d/%02d %02d:%02d:%02d UTC", mon, day, year, hour, min, sec);
       if (valid)
           rsprintf(", location: %s, %s\n", latitude, longitude);
       else
           rsprintf("\n");
   }

}

// $GPRMC,193617.000,A,4255.2006,N,07314.3301,W,0.18,116.24,190309,,*13

void handle_rmc(int field, char *st, int len) {

   int l;
   switch (field) {
   case 1:
       if (len == 10) {
           hour = atoilen(st+0, 2);
           min  = atoilen(st+2, 2);
           sec  = atoilen(st+4, 2);
       }
       break;
   case 2:
       valid = (*st == 'A');
       break;
   case 3:
       if (len < sizeof(latitude)-1) {
           memcpy(latitude, st, len);
           latitude[len] = '\0';
       }
       break;
   case 4:
       l = strlen(latitude);
       latitude[l++] = *st;
       latitude[l] = '\0';
       break;
   case 5:
       if (len < sizeof(longitude)-1) {
           memcpy(longitude, st, len);
           longitude[len] = '\0';
       }
       break;
   case 6:
       l = strlen(longitude);
       longitude[l++] = *st;
       longitude[l] = '\0';
       break;
   case 9:
       if (len == 6) {
           day  = atoilen(st+0, 2);
           mon  = atoilen(st+2, 2);
           year = atoilen(st+4, 2);
       }
       break;
   }

}

int atoilen(char *s, int len) {

   int x = 0;
   while (len-- > 0)
       x = (x*10) + (*s++ - '0');
   return x;

} </source>

PrototypeProg.c

<source lang="c">

  1. include <string.h>
  2. include <stdio.h>
  3. include <stdarg.h>

//Digital Inputs

  1. define NUM_MAX395_CHIPS 3
  2. define NUM_MAX395_SWITCHES (NUM_MAX395_CHIPS*8)
  3. define SCLK_PIN 2 // max395 control line: synchronous clock. goes to max395 pin 1.
  4. define DIN_PIN 3 // max395 control line: data in. goes to max395 pin 3.
  5. define CS_PIN 4 // max395 control line: chip select. goes to max395 pin 24.

// For max395 power connect pins 2 and 23 to V+, pins 4 and 21 to GND.

static unsigned char max395_switches[NUM_MAX395_CHIPS]; //***************************************************** void max395Setup(void); void max395Write(int sw, int value);

void rsprintf(const char *format, ...);

//junk data for testing cell phone texting char latitude[15] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3}; char longitude[15] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3}; char iteration; char sequence[40]; boolean finished = false;

//Phone mapping to the max395 chip //in order, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, G, H, I, POUND, STAR const char phone[] = {12, 8, 15, 16, 9, 14, 17, 10, 13, 18, 0, 7, 6, 1, 2, 5, 4, 3, 20, 19, 11};

void setup() { const char phoneNumber[10] = {5, 0, 3, 3, 1, 9, 2, 9, 3, 1}; for(int i = 0; i < 10; i++){ sequence[i] = phoneNumber[i]; rsprintf("%d\n", sequence[i]); } //max init max395Setup(); }

void loop() { unsigned long timer = millis(); set_text(timer); button_mash(timer); } void set_text(unsigned long t){ static unsigned long check; char latitudeNow[15]; char longitudeNow[15]; for(int i = 0; i < sizeof(latitude)/sizeof(latitude[0]); i++){ latitudeNow[i] = latitude[i]; } for(int i = 0; i < sizeof(longitude)/sizeof(longitude[0]); i++){ longitudeNow[i] = longitude[i]; } if(t >= check){ iteration = 0; for(int i = 10; i < sizeof(latitudeNow)/sizeof(latitudeNow[0])+10; i++){ sequence[i] = latitudeNow[i-10]; } for(int i = sizeof(latitudeNow)/sizeof(latitudeNow[0])+10; i < sizeof(sequence)/sizeof(sequence[0]); i++){ sequence[i] = longitudeNow[i-25]; } check = t + 48000; finished = false; } }


void button_mash(unsigned long t){ if(!finished){ if(iteration < sizeof(sequence)/sizeof(sequence[0])){ unsigned long timer = millis(); static unsigned long check; static int phase; if(timer >= check){ if(phase == 0){ phase = 1; check = 125+timer; max395Write(phone[sequence[iteration]], 1); rsprintf("%d\n", sequence[iteration]); } else if(phase == 1){ phase = 0; check = 250+timer; max395Write(phone[sequence[iteration]], 0); iteration++; } } } else if(iteration >= sizeof(sequence)/sizeof(sequence[0])){ finished = true; } } }

//********************************************************************************************** // // EVERYTHING BELOW THIS IS BLACK BOX; ABOVE IS PROJECT SPECIFIC. // //**********************************************************************************************


void rsprintf(const char *format, ...) {

   static unsigned char inited = 0;
   char msg[100];
   va_list ap;
   if (!inited) {
       Serial.begin(9600);
       inited = 1;
   }
   va_start(ap, format);
   vsnprintf(msg, sizeof(msg)-1, format, ap);
   Serial.print(msg);
   va_end(ap);

}


//********************************************************************************************** // // Max395 support //

// The Max395 is connected to three digital output pins on the Arduino



void output_max395_switches(void);
// sets all of the max395_switches to off
// sets the arduino's pins to the necessary output mode
// clears the max395 chip select
void max395Setup(void) {
    int i;
    for (i = 0; i < NUM_MAX395_CHIPS; ++i)
        max395_switches[i] = 0;
    pinMode(SCLK_PIN, OUTPUT);
    pinMode(DIN_PIN, OUTPUT);
    pinMode(CS_PIN, OUTPUT);
    digitalWrite(CS_PIN, HIGH);
    digitalWrite(SCLK_PIN, LOW);
    digitalWrite(DIN_PIN, LOW);
    output_max395_switches();
}


// for value: 1 means on, 0 means off, -1 means opposite
void max395Write(int sw, int value) {
    int m, s, b, v;
    if (sw < 0 || sw >= NUM_MAX395_SWITCHES)
        return;
    m = sw / 8;
    s = sw % 8;
    b = 1 << s;
    v = max395_switches[m];
    if (value >= 1)
        v |= b;
    else if (value == 0)
        v &= (b ^ 0xFF);
    else if (value <= -1)
        v ^= b;
    max395_switches[m] = v;
    output_max395_switches();
}
#if 0
// for value: 1 means on, 0 means off
int get_max395_switch(int sw) {
    int m, s, b, v;
    if (sw < 0 || sw >= NUM_MAX395_SWITCHES)
        return 0;
    m = sw / 8;
    s = sw % 8;
    b = 1 << s;
    v = max395_switches[m];
    return (v & b) != 0;
}
#endif
// call this whenever you want the max395 switches to change
// outputs the contents of the max395_switches array to the max395s
void output_max395_switches(void) {
    int i, j;
    digitalWrite(SCLK_PIN, LOW);
    digitalWrite(CS_PIN, LOW);
    for (i = NUM_MAX395_CHIPS - 1; i >= 0; --i) {
        int val = max395_switches[i];
        int mask = 0x80;
        for (j = 7; j >= 0; --j) {
            digitalWrite(DIN_PIN, (val & mask) != 0);
            digitalWrite(SCLK_PIN, HIGH);
            digitalWrite(SCLK_PIN, LOW);
            mask >>= 1;
        }
    }
    digitalWrite(CS_PIN, HIGH);
}

</source>

Here's the code as of this week, forgetting about all the black box stuff; there have been some fundamental changes to the way the whole thing works:

1. break out of the array iteration style for more control of time sensitive stuff; the old code would not allow for the correct timing of button presses, and we would lose data as the program waited to send out button presses.

2. The program now has some more functions: button_mash(), save_data, and send_text(). Save data runs every second, and saves what the current status of the sensors are. set_text runs once every ten minutes, and updates a bigass array with the status from the gps, as well as the phone number it uses. button mash actually iterates through that bigass array and pushes the button sequence. here it all is:

<source lang="c">

  1. include <NewSoftSerial.h>
  2. include <sd_raw_config.h>
  3. undef SD_RAW_WRITE_BUFFERING
  4. include <sd_raw.h>
  5. include <string.h>
  6. include <stdio.h>
  7. include <stdarg.h>
  1. define SD_RAW_WRITE_BUFFERING 0

//Analog inputs

  1. define PRESSURE_1 0
  2. define PRESSURE_2 1
  3. define PRESSURE_3 2
  4. define TEMPERATURE_1 3
  5. define TEMPERATURE_2 4
  6. define TEMPERATURE_3 5

//Digital Inputs

  1. define NUM_MAX395_CHIPS 3
  2. define NUM_MAX395_SWITCHES (NUM_MAX395_CHIPS*8)
  3. define SCLK_PIN 7 // max395 control line: synchronous clock. goes to max395 pin 1.
  4. define DIN_PIN 8 // max395 control line: data in. goes to max395 pin 3.
  5. define CS_PIN 9 // max395 control line: chip select. goes to max395 pin 24.
  6. define LIGHT_PIN 13

// For max395 power connect pins 2 and 23 to V+, pins 4 and 21 to GND.

static unsigned char max395_switches[NUM_MAX395_CHIPS]; //***************************************************** void max395Setup(void); void max395Write(int sw, int value);

void handle_gps(void); void handle_gps_sentence(char *s);

void rsprintf(const char *format, ...); //*****************************************************

NewSoftSerial gps = NewSoftSerial(2, 3); //***************************************************** //OUR VARIABLES FOR THE PROGRAM; Everything else is black box related. int hello = 0x9876; int log_count; int joe = 0;

char hour, min, sec, year, mon, day, valid, iteration; char latitude[15], longitude[15]; char sequence[40]; //*****************************************************

void setup(){ char phoneNumber[10] = {5,0,3,3,1,9,2,9,3,1}; for(int i = 0; i < 10; i++){ sequence[i] = phoneNumber[i]; } //sd init sd_raw_init(); sd_check_format(); //max init max395Setup(); //gps setup

 pinMode(4, OUTPUT);
 pinMode(5, OUTPUT);
 pinMode(6, OUTPUT);
 digitalWrite(4, 0);  // POWER ON
 digitalWrite(5, 1);  // READY LED ON
 digitalWrite(6, 0);  // FIX LED OFF
 gps.begin(4800);

//end gps setup rsprintf("HELO\n"); rsprintf("%d Logs are on the card\n", log_count); pinMode(LIGHT_PIN, OUTPUT); //Uncomment to run printout // sd_print_log(); // while(1) ; }

void loop(){

 rsprintf("||||||||||||||||||||||||||||||||||||||||||||||||||||\n");

digitalWrite(LIGHT_PIN, joe); rsprintf("The light is %d\n", joe); unsigned long timer = millis(); save_data(timer); set_text(timer); button_mash(timer); }

void save_data(unsigned long t){ static unsigned long check; if(t < check){ return; } int read1 = analogRead(PRESSURE_1); int read2 = analogRead(PRESSURE_2);

int temp1 = analogRead(TEMPERATURE_1); int temp2 = analogRead(TEMPERATURE_2);

//gps looping handle_gps();

 digitalWrite(6, valid);

//end gps looping

rsprintf("Pressure: %d,%d\nTemperature: %d,%d\n Log Count: %ld\n\n\n", read1, read2, temp1, temp2, millis()/1000); sd_log(read1, read2, temp1, temp2, hour, min, sec, year, mon, day, valid, latitude, longitude, millis()/1000); joe = !joe; check = t+1000; }

void set_text(unsigned long t){ static unsigned long check; char latitudeNow[15]; char longitudeNow[15]; for(int i = 0; i < sizeof(latitude)/sizeof(char); i++){ latitudeNow[i] = latitude[i]; } for(int i = 0; i < sizeof(longitude)/sizeof(char); i++){ longitudeNow[i] = longitude[i]; } if(t < check){ return; } iteration = 0; for(int i = 10; i < sizeof(latitudeNow)/sizeof(char)+10; i++){ sequence[i] = latitudeNow[i-10]; } for(int i = sizeof(latitudeNow)/sizeof(char)+10; i < sizeof(sequence)/sizeof(char); i++){ sequence[i] = longitudeNow[i-20]; } check = t + 600000; }


void button_mash(unsigned long t){ if(iteration <= sizeof(sequence)/sizeof(char)){ unsigned long timer = millis(); static unsigned long check; static int phase; if(timer < check){ return; } switch(phase){ case 1: phase = 0; check = 125+timer; max395Write(sequence[iteration], 1); case 0: phase = 1; check = 250+timer; max395Write(sequence[iteration], 0); iteration++; } } }

struct memory{ char hour, min, sec, year, mon, day, valid; char latitude[15], longitude[15]; int pressureRead1, pressureRead2, tempRead1, tempRead2; long log_count; };

void sd_log(int pinRead1, int pinRead2, int tempRead1, int tempRead2, char hour, char min, char sec, char year, char mon, char day, char valid, char latitude[15], char longitude[15], long timeStamp){

 struct memory mem;

//pressure

 mem.pressureRead1 = pinRead1;mem.pressureRead2 = pinRead2;
 //temperature

mem.tempRead1 = tempRead1;mem.tempRead2 = tempRead2; //date mem.hour = hour;mem.min = min;mem.sec = sec;mem.year = year;mem.mon = mon; mem.day = day;mem.valid = valid; //lat+long mem.latitude[15] = latitude[15];mem.longitude[15] = longitude[15]; //log_count

 mem.log_count = timeStamp;
 sd_read(4, &log_count, sizeof(log_count));
 sd_write(((log_count * sizeof(mem)) + 8 ), &mem, sizeof(mem));
 ++log_count;
 sd_write(4, &log_count, sizeof(log_count));

}

void sd_print_log() { struct memory mem; sd_read(4, &log_count, sizeof(log_count)); for (long i=0; i < log_count; ++i) { sd_read(i*sizeof(mem)+8, &mem, sizeof(mem)); rsprintf("%ld: %d,%d,%d,%d,%ld\n", i, mem.pressureRead1, mem.pressureRead2, mem.tempRead1, mem.tempRead2, mem.log_count); rsprintf(", location: %s, %s\n", mem.latitude, mem.longitude); } } </source>

Week one

Software

I just finished up setting up some of the pseudo code; the major patches that are left are largely things related to the actual key bindings specific to the phone. Since we don't know how the sequence works for getting into the text message area, i just have everything up until then. Here's how it works:

1. using a phone number stored in an array, dial each number into the phone, assuming we have navigated into the "send to" box.

2. not implemented: get to the box for the message details

3. implemented: dial in the 15 char's for latitude

4. dial in the 15 char's for longitude

5. not implemented: send the message using the keystrokes that we don't know yet; will be easy.

Everything else is fairly straightforward; the sd logging is just what it has been for a long time, only we're adding the two arrays. I will be sure to test this on an arduino asap; the only problem is all the sd shield are in use, so we can't really perfect the gps part until then. for testing next week, we can just fill it with junk data. The following is the code, broken into smaller chunks for readability.

Header stuff, declarations... <source lang="c">

  1. include <NewSoftSerial.h>
  2. include <sd_raw_config.h>
  3. undef SD_RAW_WRITE_BUFFERING
  4. include <sd_raw.h>
  5. include <string.h>
  6. include <stdio.h>
  7. include <stdarg.h>
  1. define SD_RAW_WRITE_BUFFERING 0

//Analog inputs

  1. define PRESSURE_1 0
  2. define PRESSURE_2 1
  3. define PRESSURE_3 2
  4. define TEMPERATURE_1 3
  5. define TEMPERATURE_2 4
  6. define TEMPERATURE_3 5

//Digital Inputs

  1. define NUM_MAX395_CHIPS 3
  2. define NUM_MAX395_SWITCHES (NUM_MAX395_CHIPS*8)
  3. define SCLK_PIN 7 // max395 control line: synchronous clock. goes to max395 pin 1.
  4. define DIN_PIN 8 // max395 control line: data in. goes to max395 pin 3.
  5. define CS_PIN 9 // max395 control line: chip select. goes to max395 pin 24.
  6. define LIGHT_PIN 13

// For max395 power connect pins 2 and 23 to V+, pins 4 and 21 to GND.

static unsigned char max395_switches[NUM_MAX395_CHIPS]; //***************************************************** void max395Setup(void); void max395Write(int sw, int value);

void handle_gps(void); void handle_gps_sentence(char *s);

void rsprintf(const char *format, ...); //*****************************************************

NewSoftSerial gps = NewSoftSerial(2, 3); //***************************************************** //OUR VARIABLES FOR THE PROGRAM; Everything else is black box related. int hello = 0x9876; int log_count; int joe = 0;

char hour, min, sec, year, mon, day, valid; char latitude[15], longitude[15]; //***************************************************** </source>

SETUP <source lang="c"> void setup(){ //sd init sd_raw_init(); sd_check_format(); //max init max395Setup(); //gps setup

 pinMode(4, OUTPUT);
 pinMode(5, OUTPUT);
 pinMode(6, OUTPUT);
 digitalWrite(4, 0);  // POWER ON
 digitalWrite(5, 1);  // READY LED ON
 digitalWrite(6, 0);  // FIX LED OFF
 gps.begin(4800);

//end gps setup rsprintf("HELO\n"); rsprintf("%d Logs are on the card\n", log_count); pinMode(LIGHT_PIN, OUTPUT); //Uncomment to run printout // sd_print_log(); // while(1) ; } </source>

LOOP <source lang="c"> void loop(){ static int phoneNumber[10] = {5,0,3,3,1,9,2,9,3,1};

 rsprintf("||||||||||||||||||||||||||||||||||||||||||||||||||||\n");

digitalWrite(LIGHT_PIN, joe); rsprintf("The light is %d\n", joe);

unsigned long int sec = millis()/1000; unsigned long int now, next;

int read1 = analogRead(PRESSURE_1); int read2 = analogRead(PRESSURE_2);

int temp1 = analogRead(TEMPERATURE_1); int temp2 = analogRead(TEMPERATURE_2);

//gps looping handle_gps();

 digitalWrite(6, valid);

//end gps looping

rsprintf("Pressure: %d,%d\nTemperature: %d,%d\n Log Count: %ld\n\n\n", read1, read2, temp1, temp2, millis()/1000); sd_log(read1, read2, temp1, temp2, hour, min, sec, year, mon, day, valid, latitude, longitude, millis()/1000); joe = !joe; if(now >= next){ send_text(phoneNumber); next = now+600; } } </source>

Sending Texts <source lang="c"> void send_text(int phoneNumber[10]){ //click the buttons to get to a text

// change i to i+some number to set the write button into motion to click that phone number in //do this for all integers in the phone number for(int i = 0; i < sizeof(phoneNumber)/sizeof(i); i++){ rsprintf("Number on phone: %d", phoneNumber[i]); max395Write(i, 1); delay(125); max395Write(i, 0); delay(250); } //skip to message area for(int i = 0; i < sizeof(latitude)/sizeof(latitude[0]); i++){ rsprintf("Number on phone: %d", latitude[i]); max395Write(i, 1); delay(125); max395Write(i, 0); delay(250); } for(int i = 0; i < sizeof(longitude)/sizeof(longitude[0]); i++){ rsprintf("Number on phone: %d", longitude[i]); max395Write(i, 1); delay(125); max395Write(i, 0); delay(250); } //send text message button sequence } </source>

Memory Struct, Logging to SD, Printing from SD <source lang="c"> struct memory{ char hour, min, sec, year, mon, day, valid; char latitude[15], longitude[15]; int pressureRead1, pressureRead2, tempRead1, tempRead2; long log_count; };

void sd_log(int pinRead1, int pinRead2, int tempRead1, int tempRead2, char hour, char min, char sec, char year, char mon, char day, char valid, char latitude[15], char longitude[15], long timeStamp){

 struct memory mem;

//pressure

 mem.pressureRead1 = pinRead1;mem.pressureRead2 = pinRead2;
 //temperature

mem.tempRead1 = tempRead1;mem.tempRead2 = tempRead2; //date mem.hour = hour;mem.min = min;mem.sec = sec;mem.year = year;mem.mon = mon; mem.day = day;mem.valid = valid; //lat+long mem.latitude[15] = latitude[15];mem.longitude[15] = longitude[15]; //log_count

 mem.log_count = timeStamp;
 sd_read(4, &log_count, sizeof(log_count));
 sd_write(((log_count * sizeof(mem)) + 8 ), &mem, sizeof(mem));
 ++log_count;
 sd_write(4, &log_count, sizeof(log_count));

}

void sd_print_log() { struct memory mem; sd_read(4, &log_count, sizeof(log_count)); for (long i=0; i < log_count; ++i) { sd_read(i*sizeof(mem)+8, &mem, sizeof(mem)); rsprintf("%ld: %d,%d,%d,%d,%ld\n", i, mem.pressureRead1, mem.pressureRead2, mem.tempRead1, mem.tempRead2, mem.log_count); rsprintf(", location: %s, %s\n", mem.latitude, mem.longitude); } } </source>

Black box stuff All the stuff that follows are the general functions that apply to all the different parts of the project; the sd support, the max chip initialization and parsing, the gps reading and writing; these types of nuts and bolts generic functions that really don't apply to anything in the project, but are included just to make life simpler and easier; they don't change, so I'm calling it the black box stuff; unless something goes horribly wrong somehow, there's little chance anything below this line will change. <source lang="c"> //********************************************************************************************** // // EVERYTHING BELOW THIS IS BLACK BOX; ABOVE IS PROJECT SPECIFIC. // //**********************************************************************************************


void rsprintf(const char *format, ...) {

   static unsigned char inited = 0;
   char msg[100];
   va_list ap;
   if (!inited) {
       Serial.begin(9600);
       inited = 1;
   }
   va_start(ap, format);
   vsnprintf(msg, sizeof(msg)-1, format, ap);
   Serial.print(msg);
   va_end(ap);

}


//********************************************************************************************** // // SD CARD support //

void sd_format(){

 int id;
 rsprintf("in sd_format\n");
 sd_write(0, &hello, sizeof(hello)); 
 sd_read(0, &id, sizeof(id)); 
 rsprintf("id    %08x\n", id);
 log_count = 0;
 sd_write(4, &log_count, sizeof(log_count)); 

}

void sd_check_format(){

 int id;
 sd_read(0, &id, sizeof(id)); 
 rsprintf("id    %08x\n", id);
 rsprintf("Hello %08x\n", hello);
 if (id != hello){ 
   sd_format();
 }
 sd_read(4, &log_count, sizeof(log_count)); 

}

void sd_write(uint32_t offset, void *buffer, uint16_t length) {

 sd_raw_write(offset, (uint8_t *) buffer, length);
 sd_raw_sync();

}

void sd_read(uint32_t offset, void *buffer, uint16_t length) {

 sd_raw_read(offset, (uint8_t *) buffer, length);

}


//********************************************************************************************** // // Max395 support //

// The Max395 is connected to three digital output pins on the Arduino



void output_max395_switches(void);
// sets all of the max395_switches to off
// sets the arduino's pins to the necessary output mode
// clears the max395 chip select
void max395Setup(void) {
    int i;
    for (i = 0; i < NUM_MAX395_CHIPS; ++i)
        max395_switches[i] = 0;
    pinMode(SCLK_PIN, OUTPUT);
    pinMode(DIN_PIN, OUTPUT);
    pinMode(CS_PIN, OUTPUT);
    digitalWrite(CS_PIN, HIGH);
    digitalWrite(SCLK_PIN, LOW);
    digitalWrite(DIN_PIN, LOW);
    output_max395_switches();
}


// for value: 1 means on, 0 means off, -1 means opposite
void max395Write(int sw, int value) {
    int m, s, b, v;
    if (sw < 0 || sw >= NUM_MAX395_SWITCHES)
        return;
    m = sw / 8;
    s = sw % 8;
    b = 1 << s;
    v = max395_switches[m];
    if (value >= 1)
        v |= b;
    else if (value == 0)
        v &= (b ^ 0xFF);
    else if (value <= -1)
        v ^= b;
    max395_switches[m] = v;
    output_max395_switches();
}
#if 0
// for value: 1 means on, 0 means off
int get_max395_switch(int sw) {
    int m, s, b, v;
    if (sw < 0 || sw >= NUM_MAX395_SWITCHES)
        return 0;
    m = sw / 8;
    s = sw % 8;
    b = 1 << s;
    v = max395_switches[m];
    return (v & b) != 0;
}
#endif
// call this whenever you want the max395 switches to change
// outputs the contents of the max395_switches array to the max395s
void output_max395_switches(void) {
    int i, j;
    digitalWrite(SCLK_PIN, LOW);
    digitalWrite(CS_PIN, LOW);
    for (i = NUM_MAX395_CHIPS - 1; i >= 0; --i) {
        int val = max395_switches[i];
        int mask = 0x80;
        for (j = 7; j >= 0; --j) {
            digitalWrite(DIN_PIN, (val & mask) != 0);
            digitalWrite(SCLK_PIN, HIGH);
            digitalWrite(SCLK_PIN, LOW);
            mask >>= 1;
        }
    }
    digitalWrite(CS_PIN, HIGH);
}


//********************************************************************************************** // // GPS support //

void handle_gps(void) {

   static char sentence[100];
   static unsigned char sentence_idx = 0;
   char ch;
   while (gps.available()) {
       ch = gps.read();
       if (ch == '\n') {
           if (sentence_idx < sizeof(sentence)) {
               sentence[sentence_idx] = '\0';
               handle_gps_sentence(sentence);
           } else {
               rsprintf("Sentence too long; ignored.\n");
           }
           sentence_idx = 0;
       } else {
           if (sentence_idx < sizeof(sentence)-1)
               sentence[sentence_idx++] = ch;
       }
   }

}

void handle_gps_sentence(char *s) {

   char ch;
   char *st;
   int len;
   int field;
   int type;

// rsprintf(">> %s\n", s);

   type = 0;
   field = 0;
   st = s;
   while (1) {
       ch = *s++;
       if (ch == '\0' || ch == ',') {
           len = s - st - 1;
           if (field == 0) {
               if (memcmp("$GPRMC", st, len) == 0)
                   type = 1;
           } else {
               switch (type) {
               case 1:
                   handle_rmc(field, st, len);
                   break;
               }
           }
           if (ch == '\0')
               break;
           ++field;
           st = s;
       }
   }
   if (type == 1) {
       rsprintf("time: %02d/%02d/%02d %02d:%02d:%02d UTC", mon, day, year, hour, min, sec);
       if (valid)
           rsprintf(", location: %s, %s\n", latitude, longitude);
       else
           rsprintf("\n");
   }

}

// $GPRMC,193617.000,A,4255.2006,N,07314.3301,W,0.18,116.24,190309,,*13

void handle_rmc(int field, char *st, int len) {

   int l;
   switch (field) {
   case 1:
       if (len == 10) {
           hour = atoilen(st+0, 2);
           min  = atoilen(st+2, 2);
           sec  = atoilen(st+4, 2);
       }
       break;
   case 2:
       valid = (*st == 'A');
       break;
   case 3:
       if (len < sizeof(latitude)-1) {
           memcpy(latitude, st, len);
           latitude[len] = '\0';
       }
       break;
   case 4:
       l = strlen(latitude);
       latitude[l++] = *st;
       latitude[l] = '\0';
       break;
   case 5:
       if (len < sizeof(longitude)-1) {
           memcpy(longitude, st, len);
           longitude[len] = '\0';
       }
       break;
   case 6:
       l = strlen(longitude);
       longitude[l++] = *st;
       longitude[l] = '\0';
       break;
   case 9:
       if (len == 6) {
           day  = atoilen(st+0, 2);
           mon  = atoilen(st+2, 2);
           year = atoilen(st+4, 2);
       }
       break;
   }

}

int atoilen(char *s, int len) {

   int x = 0;
   while (len-- > 0)
       x = (x*10) + (*s++ - '0');
   return x;

} </source>

Hardware

Max chip/cellphone progress

Hardware Purchasing

Schematics

Breadboard prototyping

Personal tools