#include #include #include #include "spi_rtc.h" #include "serial_lib.h" #include "ks0108\lcd_ks0108.h" #include #define TERM '~' // Tilda used due to high ASCII value // Used to synchronize the PC and RTC void setClock(unsigned char h, unsigned char m) { char buffer[16]; unsigned char s = 30; string2LCD(buffer,0,0); string2LCDf("Synching...",2,0); spi_write_reg(0x01,(((s/10)<<4) | (s%10))); spi_write_reg(0x02,(((m/10)<<4) | (m%10))); spi_write_reg(0x03,(((h/10)<<4) | (h%10))); string2LCDf("Synch done", 2, 0); spi_init(); } // Possible serial states enum {SYNCH, INIT, BIN, DOSE, MEDHEAD, MED, STRING, DONE} serial_state; // Writes a string to serial and terminates with the TERM character void put_str(char flash *str) { while (*str != 0) { putchar(*str); str++; } putchar(TERM); } // Confirms a message void send_confirm(void) { put_str("OK"); } // Denies a message void send_deny(void) { put_str("NO"); } // Copies RAM to EEPROM void memcpy_r2e(char eeprom *dest, char *src, int size) { int i = 0; for (i = 0; i < size; i++) { *dest = *src; dest++; src++; } } // Copies EEPROM to RAM void memcpy_e2r(char *dest, char eeprom *src, int size) { int i = 0; for (i = 0; i < size; i++) { *dest = *src; dest++; src++; } } // Waits for a schedule to be uploaded void get_schedule(eeprom_Schedule eeprom *sched_p) { char c; unsigned char buffer[64]; int index, bin_num, dose_num, med_num, name_index, i; unsigned char ready = 0; unsigned char done = 0; // Uses a RAM temporary schedule in case of failure Schedule sched; Bin *curr_bin; Dose *curr_dose; Medication *curr_med; index = 0; bin_num = 0; med_num = 0; name_index = 0; serial_state = SYNCH; while (!done) { // Buffer an Incoming String while ((c = getchar()) != TERM) { buffer[index++] = c; } // Reset Command: XX if (index == 2 && buffer[0] == 'X' && buffer[1] == 'X') { serial_state = SYNCH; bin_num = 0; index = 0; ready = 0; continue; } // Verification Command: VER if (index == 3 && buffer[0] == 'V' && buffer[1] == 'E' && buffer[2] == 'R') { memcpy_e2r(&sched, sched_p, sizeof(Schedule)); string2LCDf("Verifying...",2,0); put_schedule(sched); return; } // Regular Operation Switch switch (serial_state) { // Synchronizes the clock and changes the state to INIT case SYNCH: // Check for the SYN string and allow to continue if (index == 3 && buffer[0] == 'S' && buffer[1] == 'Y' && buffer[2] == 'N') { send_confirm(); ready = 1; // Use the buffer values to set the clock } else if (ready && index == 2) { setClock(buffer[0], buffer[1]); send_confirm(); ready = 0; serial_state = INIT; // Send deny and abort if anything goes wrong } else { send_deny(); return; } break; // Initializes the upload process case INIT: // Check for the US string to begin upload, state goes to BIN if (index == 2 && buffer[0] == 'U' && buffer[1] == 'S') { send_confirm(); serial_state = BIN; } else { send_deny(); return; } break; // Bin state for reading a single bin case BIN: // Starts with the B string if (index == 1 && buffer[0] == 'B') { send_confirm(); ready = 1; // the hour minute and number of doses are loaded from the buffer } else if (ready && index == 3) { curr_bin = &(sched.bins[bin_num++]); curr_bin->hour = buffer[0]; curr_bin->min = buffer[1]; curr_bin->num_doses = buffer[2]; dose_num = 0; send_confirm(); ready = 0; // if the number of doses is zero and the are more bins call bin again if (curr_bin->num_doses == 0 && bin_num < 4) { serial_state = BIN; // if there are not doses and no more bins begin medication } else if (curr_bin->num_doses == 0) { serial_state = MEDHEAD; // Otherwise read in doses for this bin } else { serial_state = DOSE; } // Abort if necessary } else { send_deny(); return; } break; // Reads a single dose descriptor case DOSE: // Start with the D string if (index == 1 && buffer[0] == 'D') { send_confirm(); ready = 1; // Read in the medication number and dose amount from buffer } else if (ready && index == 2) { curr_dose = &(curr_bin->doses[dose_num++]); curr_dose->amount = buffer[0]; curr_dose->med_num = buffer[1]; send_confirm(); ready = 0; // If the number of doses has been reached and there are more bins // begin the next bin transmission if (dose_num == curr_bin->num_doses && bin_num < 4) { serial_state = BIN; // If the number of doses has been reached and no more bins // begin the medication transmission } else if (dose_num == curr_bin->num_doses) { serial_state = MEDHEAD; } // otherwise wait for the next dose // Abort if necessary } else { send_deny(); return; } break; // Header for the medication section case MEDHEAD: // starts with MH String if (index == 2 && buffer[0] == 'M' && buffer[1] == 'H') { send_confirm(); ready = 1; // read the number of meds from the buffer } else if (ready && index == 1) { sched.num_meds = buffer[0]; med_num = 0; send_confirm(); ready = 0; // if no medications process is done if (sched.num_meds == 0) { done = 1; } else { serial_state = MED; } // Abort as necessary } else { send_deny(); return; } break; // Medication descriptors case MED: // start with M string if (index == 1 && buffer[0] == 'M') { send_confirm(); ready = 1; // Use the buffer to fill the name pointer, shape, color, and specials } else if (ready && index == 5) { curr_med = &(sched.meds[med_num++]); curr_med->name_num = buffer[0]; curr_med->shape = buffer[1]; curr_med->color = buffer[2]; curr_med->special1 = buffer[3]; curr_med->special2 = buffer[4]; send_confirm(); ready = 0; // if the number of meds has been transmitted begin names if (med_num == sched.num_meds) { serial_state = STRING; } } break; // Name transmission case STRING: // Name blasting begins with S if (index == 1 && buffer[0] == 'S') { send_confirm(); ready = 1; // Read in each name terminated by zero } else if (ready) { for (i = 0; buffer[i] != 0; i++) { sched.names[name_index++] = buffer[i]; } sched.names[name_index++] = 0; send_confirm(); // If next buffer element is a 4, transmission is done if (buffer[i+1] == 4) { done = 1; } // Abort as necessary } else { send_deny(); return; } break; } //end switch index = 0; } // end while // Verify the results string2LCDf("Verifying...",2,0); put_schedule(sched); // Copy the schedule to EEPROM memcpy_r2e(sched_p, &sched, sizeof(Schedule)); string2LCDf("Complete.", 2,0); } // Transmits entire schedule as a large block to be parsed by PC void put_schedule(Schedule sched) { int bin_num, dose_num, med_num, name_num, index; Bin *curr_bin; Dose *curr_dose; Medication *curr_med; // Verification transmit put_str("VER"); // Transmit individual bins for (bin_num = 0; bin_num < 4; bin_num++) { curr_bin = &(sched.bins[bin_num]); put_str("B"); putchar(curr_bin->hour); putchar(curr_bin->min); putchar(curr_bin->num_doses); put_str(""); for (dose_num = 0; dose_num < curr_bin->num_doses; dose_num++) { curr_dose = &(curr_bin->doses[dose_num]); put_str("D"); putchar(curr_dose->amount); putchar(curr_dose->med_num); put_str(""); } } // Transmit med info for (med_num = 0; med_num < sched.num_meds; med_num++) { curr_med = &(sched.meds[med_num]); put_str("M"); putchar(curr_med->name_num); putchar(curr_med->shape); putchar(curr_med->color); putchar(curr_med->special1); putchar(curr_med->special2); put_str(""); } // Transmit names index = 0; for (name_num = 0; name_num < sched.num_meds; name_num++) { for (; sched.names[index] != 0; index++) { putchar(sched.names[index]); } index++; put_str(""); } put_str("FIN"); } // Initialize serial with 9600 baud void serial_init(void) { UCSRB = 0x18; UBRRL = 103 ; //using a 16 MHz crystal (9600 baud) UCSRB.7 = 1; put_str("Initializing..."); serial_state = INIT; }