www.pudn.com > ÓÃCÓïÑÔ¶ÁдCF¿¨³ÌÐò.zip > hoarder.c
// Hoarder board software http://vadim.www.media.mit.edu/Hoarder/Hoarder.htm // Copyright (C) 2001-2002 MIT Media Laboratory // Concept, design, and programming by Vadim Gerasimov// Code fragments by Paul Covell, Matthew Drake // Ideas contributed by // Paul Covell, Ted Selker, Sandy Pentland, Richard DeVaul, // Brian Silverman, Tim Hirzel, Josh Weaver, Ivan Chardin #include <16F877.H> #list #include "Math32.c" // Configuration bits for initial programming #fuses HS, NOPROTECT, WDT, PUT, BROWNOUT, NOLVP // 20 MHz clock #use delay (clock=20000000) // up to 57.6kBaud (recommended 38.4) to be compatible with BiM2 transceiver // up to 115,2kBaud for cable connection #use rs232 (baud=115200, xmit=PIN_C6, rcv=PIN_C7) // Disable automatic TRIS programming for all ports #use fast_io(a) #use fast_io(b) #use fast_io(c) #use fast_io(d) #use fast_io(e) // for MIThril bus and I2C-enabled add-on boards #use I2C (master, sda=PIN_C4, scl=PIN_C3, address=0xc0, SLOW) // define for initial PIC programming to include the serial programming function #define InitialProgram // define only one: Rochester, ESL, GAME, or Tim //#define Rochester #define ESL // Every Sign of Life collect/broadcast //#define GAME // Ball game broadcast //#define Tim // Tim Hirzel's project data collection // define OldSAK for boards earlier than NOV 2001 //#define OldSAK // define DelayedWrite to use with IBM MicroDrive (TM) //#define DelayedWrite // CompactFlash pins // 3 address lines (all others grounded) #define CF_A0 PIN_B0 #define CF_A1 PIN_B1 #define CF_A2 PIN_B2 // data flow strobe signals #define CF_N_OE PIN_B3 #define CF_N_WE PIN_B4 // card detect signal (high if card is not present) #define CF_CD1 PIN_B7 #define cf_out input(CF_CD1) // CF power switch #ifdef OldSAK #define CF_POWER PIN_C0 #else #define CF_POWER PIN_B6 #endif // LED pins #define CF_LED0 PIN_C1 #define CF_LED1 PIN_C2 // EKG amplifier enable for BIOMETRICS add-on module #define EKG_EN PIN_C5 // Real time clock signals // two lines shared with CF data bus #define RTC_RST PIN_B5 #define RTC_CLK PIN_D0 #define RTC_IO PIN_D1 // BiM transceiver pins TX-, RX-enable and Carrier Detect // TX, RX data pins connected to UART #ifdef OldSAK #define BIM_TX PIN_E0 #define BIM_RX PIN_E1 #define BIM_CD PIN_E2 #else #define BIM_TX PIN_E2 #define BIM_RX PIN_E1 #define BIM_CD PIN_C0 #endif #define RBIF 0x58 #define RCIF 0x65 #define OERR 0xC1 #define CREN 0xC4 // Event button -- Tim Hirzel's project #define BUTTON PIN_A4 #byte SPBRG = 0x99 #byte TXSTA = 0x98 #byte PORTA = 0x05 #byte PORTB = 0x06 #byte PORTC = 0x07 #byte CF_DATA = 0x08 /* Port D */ #byte CF_DATA_TRIS = 0x88 /* Port D TRIS */ // 1-in 0-out #define TRIS_A 0xFF // 11111111 #define TRIS_B 0x80 // 10000000 #ifdef OldSAK #define TRIS_C 0xF8 // 11111000 #define TRIS_C_SLEEP 0x80 // 10000000 #define TRIS_E 0x04 // 0000x100 #else #define TRIS_C 0xD9 // 11011001 #define TRIS_C_SLEEP 0x81 // 10000001 #define TRIS_E 0x01 // 0000x001 #endif #define TRIS_D_IN 0xFF // 11111111 #define TRIS_D_OUT 0x00 // 00000000 #define TRIS_D_RTC_OUT 0xFC #define TRIS_D_RTC_IN 0xFE // Function Prototypes void print_prompt(); #separate void save_audio(); #separate void save_data(); #separate void send_data(); #separate void send_data_bim(); #separate void send_data_Tim(); #separate void send_player_info(); void led_off(); void led_red(); void led_green(); #separate boolean process_command(); void print_help(); int fromHex(char hex); void set_default_signals(); void cf_task_file_read(int addr); void cf_task_file_write(int addr, int data); byte rtc_read(int addr); void rtc_write(int addr, int data); #separate boolean get_disk_configuration(); void cf_set_addr(int addr); // Global variables // Data file name on CF card char const fname[12] = "ESL DAT"; // A/D buffer #define buf_size 32 long buffer[buf_size]; int buf_head; int buf_count; int ad_count; boolean ad_on; boolean audio; long voltage; int curData; // Holds data to be sent int curAddr; // Holds address to be read/written char sector[4]; // Current CF sector number for Read/Write operations boolean disk_valid; // CF seems ok boolean file_valid; // Data file seems ok // FAT (file allocation table) variables char data_start[4]; char fat_start[4]; // first sector of first copy of FAT char dir_start[4]; // first sector of root directory char data_sectors[4]; // number of data sectors char data_file_size[4]; char sector_counter[4]; // to count down number of unused sectors in data file byte sectors_per_cluster; long root_entries; // number of entries in root directory long cluster; // Real time clock buffer char time[8]; // hold all 8 time bytes from RTC chip // Time in ms after last reset (if timer int set to 1kHz) char ms[4]; // millisecond timer char cmd; // last command character long write_pos; // write position in current sector long crc16; // self-programming function // reprograms PIC thru serial port // host sends pieces of code as: // 1 byte header 0xAB // 2 bytes start address // 2 bytes (N) number of words to program // N words (N*2 bytes) program words // // after each program word function sends back // 1 if word programmed successfully // 0 if not // // send non 0XAB byte to exit the cycle and restart Hoarder // #ifdef InitialProgram #ORG 0x1F00, 0x1FFF void self_program() { long addr, count, val, i; disable_interrupts(GLOBAL); while(getc()==0xAB) { *(&addr)=getc(); *(&addr+1)=getc(); *(&count)=getc(); *(&count+1)=getc(); for (i=0; i 3) ad_count=0; } //#ifdef GAME // if (ad_count==1) set_adc_channel(4); else set_adc_channel(ad_count); //#else set_adc_channel(ad_count); //#endif } } // Resets AD buffer void purge_adc_buffer() { buf_head=0; buf_count=0; set_adc_channel(0); ad_count=0; } // Green-Red... Happy? void blink_happy() { while (TRUE) { led_green(); delay_ms(250); led_red(); delay_ms(250); } } void blink_sad() { while (TRUE) { led_red(); delay_ms(250); led_off(); delay_ms(250); } } // Turn off CF void disable_cf() { set_default_signals(); } // exit if CF is plugged; otherwise sleep waking up on WDT to check for CF; void take_a_nap() { if (input(CF_POWER)) { output_low(CF_POWER); delay_ms(10); } disable_cf(); do { while(cf_out) { led_red(); delay_ms(1); CF_DATA=0; SET_TRIS_D(TRIS_D_OUT); set_tris_c(TRIS_C_SLEEP); led_off(); sleep(); } delay_ms(500); } while(cf_out); // make sure CF is still in after 0.5 sec output_low(CF_POWER); // power up output_high(CF_N_OE); output_high(CF_N_WE); SET_TRIS_D(TRIS_D_IN); led_green(); delay_ms(250); led_off(); // Check CF card configuration disk_valid=get_disk_configuration(); } boolean enable_cf() { // sleep until CF is present take_a_nap(); return TRUE; } #define I2CWRITE 0b00000000 #define I2CREAD 0b00000001 void putI2C(int device, int data) { i2c_start(); i2c_write(device); i2c_write(data); i2c_stop(); } int getI2C(int device) { i2c_start(); i2c_write(device | I2CREAD); _return_ = i2c_read(); i2c_stop(); } void send_hello() { while (!input(RCIF)) printf("Hello! "); } void main() { setup_adc_ports(A_ANALOG); // port A all analog inputs setup_adc(ADC_CLOCK_DIV_32); // set ADC clock setup_psp(PSP_DISABLED); set_default_signals(); // preset some of the signals SET_TRIS_A(TRIS_A); // set TRIS values SET_TRIS_B(TRIS_B); SET_TRIS_C(TRIS_C); SET_TRIS_D(TRIS_D_IN); SET_TRIS_E(TRIS_E); port_b_pullups(TRUE); // Should be enabled; Used for B6 and B7 (CF power and CF detection) setup_timer_2(T2_DIV_BY_4, 250, 5); // default timer: 1mS interval @ 20 MHz; see timer2() zero32(ms); // zero millisecond counter ad_on=FALSE; audio=FALSE; purge_adc_buffer(); // enable_interrupts(INT_RB); enable_interrupts(INT_TIMER2); enable_interrupts(GLOBAL); disable_cf(); // set_default_signals(); // send_hello(); #ifdef GAME puts("GAME"); send_player_info(); #else // take_a_nap(); #endif #ifdef Rochester puts("Roch"); delay_ms(5000); save_audio(); #endif #ifdef ESL puts("HackFest v odno slovo"); // send_data_bim(); #endif #ifdef Tim puts("Tim"); send_data_Tim(); #endif print_prompt(); while(TRUE) { led_off(); process_command(); led_red(); led_green(); led_green(); // if (cf_out) take_a_nap(); } } void set_default_signals() { // default RTC signals output_low(RTC_RST); output_low(RTC_CLK); output_low(RTC_IO); // default CF power down signals output_low(CF_N_OE); output_low(CF_N_WE); cf_set_addr(0); output_high(CF_POWER); // default radio modem signals output_high(BIM_TX); // do not transmit output_high(BIM_RX); // do not recive // disable EKG amplifiers if present output_high(EKG_EN); // presumption of invalidity disk_valid=false; } // reset CF #separate void cf_reset() { output_high(CF_POWER); delay_ms(500); output_low(CF_POWER); } // set CF port address (see task file in CF specs) // Horder uses ports 0-7 to control CF void cf_set_addr(int addr) { output_bit(CF_A0, bit_test(addr, 0)); output_bit(CF_A1, bit_test(addr, 1)); output_bit(CF_A2, bit_test(addr, 2)); } // write 1 byte into current CF port void cf_write(int data) { // set data CF_DATA_TRIS = TRIS_D_OUT; CF_DATA = data; // Strobe write signal OUTPUT_LOW(CF_N_WE); OUTPUT_HIGH(CF_N_WE); CF_DATA_TRIS = TRIS_D_IN; } // read 1 byte from current CF port int cf_read() { CF_DATA_TRIS = TRIS_D_IN; // strobe read signal and get data output_low(CF_N_OE); _return_ = CF_DATA; output_high(CF_N_OE); } // skip bytes from current sector buffer // assumes: CF port set to 0 void cf_read_skip(unsigned int count) { CF_DATA_TRIS = TRIS_D_IN; do { output_low(CF_N_OE); output_high(CF_N_OE); count--; } while (count>0); } // write data to CF port addr void cf_task_file_write(int addr, int data) { cf_set_addr(addr); cf_write(data); } // read byte from CF port addr int cf_task_file_read(int addr) { cf_set_addr(addr); return(cf_read()); } // enable nice power-saving features of Microdrive (see Microdrive specs) // does nothing if used with regular CF memory cards void enable_microdrive_write_cache() { while ((cf_task_file_read(7)&0xC0)!=0x40); cf_task_file_write(1, 0x02); // 0x02 = enable write cache cf_task_file_write(6, 0xE0); cf_task_file_write(7, 0xEF); // set features command while ((cf_read()&0xC0)!=0x40); cf_task_file_write(1, 0xAA); // 0xAA = enable read look ahead cf_task_file_write(6, 0xE0); cf_task_file_write(7, 0xEF); // set features command while ((cf_read()&0xC0)!=0x40); #ifdef DelayedWrite cf_task_file_write(1, 0x07); // 7 = enable delayed write cf_task_file_write(6, 0xE0); cf_task_file_write(7, 0xFA); // set delayed write command while ((cf_read()&0x80)==0x80); #endif } // start reading CF sector // global var sector indicates sector number // after calling this function use cf_read() and cf_skip(int) // to read/skip 512 bytes from sector void cf_start_sector_read() { while ((cf_task_file_read(7)&0xC0)!=0x40); cf_task_file_write(2, 1); cf_task_file_write(3, sector[0]); cf_task_file_write(4, sector[1]); cf_task_file_write(5, sector[2]); cf_task_file_write(6, 0xE0 | (sector[3]&0x0F)); cf_task_file_write(7, 0x20); // read sector command while ((cf_read()&0x88)!=0x08); cf_set_addr(0); } // start writing CF sector // global var sector contains sector number // after calling this function use cf_write() // to write 512 bytes to sector void cf_start_sector_write() { while ((cf_task_file_read(7)&0xC0)!=0x40); cf_task_file_write(2, 1); cf_task_file_write(3, sector[0]); cf_task_file_write(4, sector[1]); cf_task_file_write(5, sector[2]); cf_task_file_write(6, 0xE0 | (sector[3]&0x0F)); cf_task_file_write(7, 0x30); // write sector command while ((cf_read()&0x88)!=0x08); cf_set_addr(0); } // put CF to sleep mode (see CF specs) #separate void cf_sleep() // put the card into sleep mode { while ((cf_task_file_read(7)&0xC0)!=0x40); cf_task_file_write(6, 0xE0); cf_task_file_write(7, 0x99); // sleep command } // put CF to standby mode (see CF specs) #separate void cf_standby() // put the card into stadby mode { while ((cf_task_file_read(7)&0xC0)!=0x40); cf_task_file_write(6, 0xE0); cf_task_file_write(7, 0x94); // standby immediate command } // put CF to idle mode (see CF specs) #separate void cf_idle(int delay) // put the card into idle mode, sets a delay for auto power-down { while ((cf_task_file_read(7)&0xC0)!=0x40); cf_task_file_write(2, delay); cf_task_file_write(6, 0xE0); cf_task_file_write(7, 0x97); // idle command } void print_prompt() { putc('>'); } void led_off() { OUTPUT_LOW(CF_LED0); OUTPUT_LOW(CF_LED1); } void led_green() { OUTPUT_LOW(CF_LED1); OUTPUT_HIGH(CF_LED0); } void led_red() { OUTPUT_LOW(CF_LED0); OUTPUT_HIGH(CF_LED1); } // getc() after taking care of possible overflow error char loadc() { while (!input(RCIF)) { if (input(OERR)) { output_low(CREN); output_high(CREN); } } return getc(); } // Yep! It's nope. Used for short delays. #inline void nop() { #asm nop #endasm } // RTC functions // see RTC chip specs http://pdfserv.maxim-ic.com/arpdf/DS1302.pdf (if still there) // for data format etc // IMPORTANT // RTC READ/WRITE DOES NOT WORK IF CF CARD IS PLUGGED IN AND POWERED DOWN // This is because of sharing port D pins // So make sure CF is either out or powered up before using RTC // Read time from RTC chip into time[] // 8-byte burst operation // Note: nop() are important to get proper timing at 20MHz void rtc_read_time() { static byte i, j, result; set_tris_d(TRIS_D_RTC_OUT); output_high(RTC_RST); output_high(RTC_IO); for (i=0; i<6; i++) { output_high(RTC_CLK); nop(); output_low(RTC_CLK); } output_low(RTC_IO); output_high(RTC_CLK); nop(); output_low(RTC_CLK); output_high(RTC_IO); output_high(RTC_CLK); nop(); set_tris_d(TRIS_D_RTC_IN); for (j=0; j<8; j++) { for (i=0; i<8; i++) { output_low(RTC_CLK); nop(); shift_right(&result, 1, input(RTC_IO)); output_high(RTC_CLK); } time[j]=result; } output_low(RTC_CLK); output_low(RTC_IO); output_low(RTC_RST); SET_TRIS_D(TRIS_D_IN); } // Read and return one byte from RTC chip at addr int rtc_read(int addr) { int i; set_tris_d(TRIS_D_RTC_OUT); output_high(RTC_RST); output_high(RTC_IO); output_high(RTC_CLK); nop(); output_low(RTC_CLK); for (i=0; i<6; i++) { output_bit(RTC_IO, bit_test(addr, 0)); output_high(RTC_CLK); addr>>=1; output_low(RTC_CLK); } output_high(RTC_IO); output_high(RTC_CLK); set_tris_d(TRIS_D_RTC_IN); for (i=0; i<8; i++) { output_low(RTC_CLK); nop(); shift_right(&_return_, 1, input(RTC_IO)); output_high(RTC_CLK); } output_low(RTC_CLK); output_low(RTC_IO); output_low(RTC_RST); SET_TRIS_D(TRIS_D_IN); } // Write data to RTC chip at addr void rtc_write(int addr, int data) { int i; set_tris_d(TRIS_D_RTC_OUT); output_high(RTC_RST); output_low(RTC_IO); output_high(RTC_CLK); nop(); output_low(RTC_CLK); for (i=0; i<6; i++) { output_bit(RTC_IO, addr&1); output_high(RTC_CLK); addr>>=1; output_low(RTC_CLK); } output_high(RTC_IO); output_high(RTC_CLK); nop(); output_low(RTC_CLK); for (i=0; i<8; i++) { output_bit(RTC_IO, data&1); output_high(RTC_CLK); data>>=1; output_low(RTC_CLK); } output_low(RTC_IO); output_low(RTC_RST); set_tris_d(TRIS_D_IN); } // Write time to RTC chip // 8-byte burst operation void rtc_set_time() { int i, j, data; set_tris_d(TRIS_D_RTC_OUT); output_high(RTC_RST); output_low(RTC_IO); output_high(RTC_CLK); nop(); output_low(RTC_CLK); output_high(RTC_IO); for (i=0; i<5; i++) { output_high(RTC_CLK); output_low(RTC_CLK); } output_low(RTC_IO); output_high(RTC_CLK); nop(); output_low(RTC_CLK); output_high(RTC_IO); output_high(RTC_CLK); nop(); output_low(RTC_CLK); for (j=0; j<8; j++) { data=time[j]; for (i=0; i<8; i++) { output_bit(RTC_IO, data&1); output_high(RTC_CLK); data>>=1; output_low(RTC_CLK); } } output_low(RTC_IO); output_low(RTC_RST); set_tris_d(TRIS_D_IN); } // Use this function to skip previous records in data file and prevent // accidental loss of previously recorded data when Hoarder restarts. // Skips to first "unused" sector of data file. // - "unused" sector has either invalid signature or timestamp lower than previous sector // - sectors written by Hoarder have "ESL" signature and 6-byte time stamp in the beginning // // Function returns TRUE if data file is valid and not full // FALSE if data file is not valid or no space left // If function returns TRUE sector points to first "unused" sector of data file and // sector_counter indicates number of free sectors #separate boolean init_file_write() { int i, t[6]; if (cf_out || !(disk_valid && file_valid)) return FALSE; move32(sector, data_start); move32(sector_counter, data_file_size); for (i=0; i<6; i++) time[i]=0; while (!is_zero32(sector_counter)) { for (i=0; i<6; i++) t[i]=time[i]; cf_start_sector_read(); if ((cf_read()!='E')||(cf_read()!='S')||(cf_read()!='L')) return TRUE; for (i=0; i<6; i++) time[i]=cf_read(); i=6; while (--i!=0xFF) if (time[i] t[i]) i=0; inc32(sector); dec32(sector_counter); } cf_idle(100); return FALSE; } // Call cf_start_sector_write() for next sector in data file // return FALSE if no free sectors left // uses global vars sector and sector_counter #separate boolean next_file_sector_write() { if (cf_out) return FALSE; if (is_zero32(sector_counter)) { cf_idle(100); return FALSE; } cf_start_sector_write(); inc32(sector); dec32(sector_counter); return TRUE; } #separate void save_audio() { char tag1[4], tag2[4]; long tagtime, tag1time, tag2time; int tagphase; if (cf_out || !(disk_valid && file_valid)) return; // Start at beginning of data file move32(sector, data_start); move32(sector_counter, data_file_size); tag1time=0xFFFF; tag2time=0xFFFF; tagphase=0; // Set timer interrupt to 8kHz to sample audio setup_timer_2(T2_DIV_BY_1, 125, 5); // 8 kHz write_pos=0; // Set flags for timer interrupt data sampling audio=TRUE; ad_on=TRUE; // loop until something received thru serial port // and full sector is written while ((!input(RCIF))||(write_pos!=512)) { // if sector ended start a new one if (write_pos>=512) { write_pos=0; } else if (write_pos==0) { // exit if no space left in data file if (!next_file_sector_write()) return; // blink SET_TRIS_C(TRIS_C); led_red(); // write sector signature ESL cf_write('E'); cf_write('S'); cf_write('L'); // write time stamp rtc_read_time(); cf_write(time[0]); cf_write(time[1]); cf_write(time[2]); cf_write(time[3]); cf_write(time[4]); cf_write(time[6]); write_pos+=9; led_off(); } // save accelerometer data 3 times in each sector else if ((write_pos==170)||(write_pos==335)||(write_pos==500)) { putI2C(0xB0, 2); I2C_start(); I2C_write(0xB0 | I2CREAD); cf_write(i2c_read()); cf_write(i2c_read()); cf_write(i2c_read()); cf_write(i2c_read()); i2c_read(0); I2C_stop(); write_pos+=4; // write tag reader data once per sector if (write_pos==504) { if ((tagphase&0x1F)==0) { putI2C(0xA0, 2); I2C_start(); I2C_write(0xA0 | I2CREAD); tag1[0]=i2c_read(); tag1[1]=i2c_read(); tag1[2]=i2c_read(); tag1[3]=i2c_read(); tagtime=i2c_read(); tagtime=tagtime<<8|i2c_read(); i2c_read(0); I2C_stop(); if (tagtime>=tag1time) zero32(tag1); tag1time=tagtime; putI2C(0xA0, 3); I2C_start(); I2C_write(0xA0 | I2CREAD); tag2[0]=i2c_read(); tag2[1]=i2c_read(); tag2[2]=i2c_read(); tag2[3]=i2c_read(); tagtime=i2c_read(); tagtime=tagtime<<8|i2c_read(); i2c_read(0); I2C_stop(); if (tagtime>=tag2time) zero32(tag2); tag2time=tagtime; } tagphase++; cf_write(tag1[0]); cf_write(tag1[1]); cf_write(tag1[2]); cf_write(tag1[3]); cf_write(tag2[0]); cf_write(tag2[1]); cf_write(tag2[2]); cf_write(tag2[3]); write_pos+=8; } } else if (write_pos<512) { // save buffered audio samples // sampling happens in timer interrupt while (buf_count==0); cf_write(buffer[buf_head]>>2); write_pos++; disable_interrupts(GLOBAL); buf_head=(buf_head+1)%buf_size; buf_count--; enable_interrupts(GLOBAL); } } // stop sampling, restore 1000Hz timer frequency ad_on=FALSE; audio=FALSE; purge_adc_buffer(); setup_timer_2(T2_DIV_BY_4, 250, 5); // 1mS interval @ 20 MHz } #separate void save_data() { if (!disk_valid) return; write_pos=0; move32(sector, data_start); ad_on=TRUE; while ((!input(RCIF))||(write_pos!=512)) { if (write_pos>=512) { write_pos=0; inc32(sector); } if (write_pos==0) { led_red(); cf_start_sector_write(); cf_write('E'); cf_write('S'); rtc_read_time(); cf_write(time[0]); cf_write(time[1]); cf_write(time[2]); cf_write(time[3]); cf_write(time[4]); cf_write(time[6]); write_pos+=8; led_off(); } while (buf_count==0); cf_write(buffer[buf_head]); cf_write(buffer[buf_head]>>8); write_pos+=2; disable_interrupts(GLOBAL); buf_head=(buf_head+1)%buf_size; buf_count--; enable_interrupts(GLOBAL); } ad_on=FALSE; purge_adc_buffer(); inc32(sector); cf_start_sector_write(); for (write_pos=0; write_pos<512; write_pos++) cf_write(0); } #separate void send_data() { unsigned int temp; long int id; ad_on=TRUE; while (!input(RCIF)) { //for (temp=0; temp<19; temp++) putc(0xF0); putc(0x5A); for (temp=0; temp<4; temp++) { while (buf_count==0); if (temp==3) { putc(buffer[buf_head]); if (id>0) putc((buffer[buf_head]>>8)|((id-1) << 2)|0xA8); else putc(buffer[buf_head]>>8); } if (temp==2) { if (buffer[buf_head]>768) id=0; else if (buffer[buf_head]<256) id=1; else id=2; } disable_interrupts(GLOBAL); buf_head=(buf_head+1)%buf_size; buf_count--; enable_interrupts(GLOBAL); } } ad_on=FALSE; purge_adc_buffer(); } // Calculates standard 16-bit CRC // uses global var crc16 // Note: crc16 should be set to 0 before each series of CRC calculations void crc (unsigned int data) { int i, j; for (i=0; i<8; i++) { j=(data^crc16)&1; crc16>>=1; if (j) crc16^=0xA001; data>>=1; } } // send data and update CRC void put_crc(unsigned int data) { putc(data); crc(data); } #separate void send_data_bim() { unsigned int temp; unsigned int bits; unsigned long order; unsigned int i; if (!init_file_write()) return; ad_on=TRUE; order=0; output_low(BIM_TX); while (!input(RCIF) && next_file_sector_write()) { led_red(); cf_write('E'); cf_write('S'); cf_write('L'); rtc_read_time(); cf_write(time[0]); cf_write(time[1]); cf_write(time[2]); cf_write(time[3]); cf_write(time[4]); cf_write(time[6]); led_off(); for (i=0; i<100; i++) { for (temp=0; temp<5; temp++) putc(0x0F<<(temp%5)); //total packet length 22 crc16=0; put_crc(0xA5); put_crc(order); put_crc(order>>8); for (temp=0; temp<4; temp++) { while (buf_count==0); put_crc(buffer[buf_head]); cf_write(buffer[buf_head]); bits=(bits<<2)|((buffer[buf_head]>>8)&0x03); disable_interrupts(GLOBAL); buf_head=(buf_head+1)%buf_size; buf_count--; enable_interrupts(GLOBAL); } put_crc(bits); cf_write(bits); putc(crc16); putc(crc16>>8); order++; } cf_write('E'); cf_write('N'); cf_write('D'); } output_high(BIM_TX); ad_on=FALSE; purge_adc_buffer(); } #separate void send_data_Tim() { unsigned int temp; unsigned int bits; unsigned int i; boolean OldButton, NewButton; unsigned int ButtonCount; if (!init_file_write()) return; ad_on=TRUE; OldButton=Button; while (!input(RCIF) && next_file_sector_write()) { ButtonCount=0; cf_write('E'); cf_write('S'); cf_write('L'); rtc_read_time(); cf_write(time[0]); cf_write(time[1]); cf_write(time[2]); cf_write(time[3]); cf_write(time[4]); cf_write(time[6]); for (i=0; i<100; i++) { for (temp=0; temp<4; temp++) { do { NewButton=input(BUTTON); if (!NewButton && OldButton) ButtonCount++; OldButton=NewButton; } while (buf_count==0); if (buffer[buf_head]>voltage+100) { if (voltage<559) led_green(); else led_red(); }; cf_write(buffer[buf_head]); bits=(bits<<2)|((buffer[buf_head]>>8)&0x03); disable_interrupts(GLOBAL); buf_head=(buf_head+1)%buf_size; buf_count--; enable_interrupts(GLOBAL); led_off(); } cf_write(bits); } cf_write(ButtonCount); cf_write(0); cf_write(0); } ad_on=FALSE; purge_adc_buffer(); } #separate void send_player_info() { unsigned int temp; unsigned int bits; unsigned long order; unsigned int i; ad_on=TRUE; order=0; output_low(BIM_TX); while (!input(RCIF)) { for (temp=0; temp<5; temp++) putc(0x5A); //total packet length 15 @ 38400; 22 @ 57600 crc16=0; put_crc(0xA5); put_crc(order); put_crc(order>>8); for (temp=0; temp<4; temp++) { while (buf_count==0); put_crc(buffer[buf_head]); bits=(bits<<2)|((buffer[buf_head]>>8)&0x03); //if (temp==1) if (buffer[buf_head]<15) output_low(BIM_TX); else output_high(BIM_TX); disable_interrupts(GLOBAL); buf_head=(buf_head+1)%buf_size; buf_count--; enable_interrupts(GLOBAL); } put_crc(bits); putc(crc16); putc(crc16>>8); order++; } output_high(BIM_TX); ad_on=FALSE; purge_adc_buffer(); } // Print RTC time #separate void print_time() { rtc_read_time(); printf("%2X/%2X/%2X %2X:%2X:%2X", time[4], time[3], time[6], time[2], time[1], time[0]); } // Enable RTC oscillator and counter #separate void reset_time() { printf("Time reset"); rtc_write(7,0); rtc_write(0,0); } // Print CF information #separate void check_cf() { if (!enable_cf()) { printf("Invalid disk\n"); } else { printf("Dir 0x%2X%2X%2X%2X\n", dir_start[3], dir_start[2], dir_start[1], dir_start[0]); printf("Data sectors 0x%2X%2X%2X%2X\n", data_sectors[3], data_sectors[2], data_sectors[1], data_sectors[0]); if (file_valid) { printf("File start 0x%2X%2X%2X%2X\n", data_start[3], data_start[2], data_start[1], data_start[0]); printf("File size 0x%2X%2X%2X%2X\n", data_file_size[3], data_file_size[2], data_file_size[1], data_file_size[0]); } else printf("File not found"); } } // Set RTC time to 8 bytes received thru serial port #separate void set_time() { int i; for (i=0; i<8; i++) time[i]=loadc(); rtc_write(7,0); rtc_set_time(); } // Well... void print_help() { return; } /* | int fromHex(char hex) | Preconditions: hex is 1-f | Postconditions: returned int is 1-16 */ int fromHex(char hex) { if(hex >= '0' && hex <= '9') return(hex - 48); // 0 --> 0 if(hex >= 'a' && hex <= 'f') return(hex - 87); // a --> 10 if(hex >= 'A' && hex <= 'F') return(hex - 55); // A --> 10 // Still here? Invalid return(20); } // Issues identify drive command (0xEC) and sends result to serial port #separate void identify_drive() { unsigned int cnt; while ((cf_task_file_read(7)&0xC0)!=0x40); cf_task_file_write(6, 0xA0); // drive 0 cf_task_file_write(7, 0xEC); // identify drive command while ((cf_read()&0x80)==0x80); cf_set_addr(0); for(cnt = 0; cnt < 0xFF; cnt++) { putc(cf_read()); } for(cnt = 0; cnt < 0xFF; cnt++) { putc(cf_read()); } putc(cf_read()); putc(cf_read()); } // reads sector and sends result to serial port #separate void read_sector() { unsigned int cnt; sector[0]=loadc(); sector[1]=loadc(); sector[2]=loadc(); sector[3]=loadc(); cf_start_sector_read(); for(cnt = 0; cnt < 0xFF; cnt++) { putc(cf_read()); } for(cnt = 0; cnt < 0xFF; cnt++) { putc(cf_read()); } putc(cf_read()); putc(cf_read()); } // CF debugging: // read and print CF register #separate void read_register() { int temp; temp=cf_task_file_read(curAddr); printf("%d: 0x%2X(%u)\n", curAddr, temp, temp); } // CF debugging: // write CF register #separate void write_register() { printf("Writing 0x%2X(%u) to addr %u\n", curData, curData, curAddr); cf_task_file_write(curAddr, curData); } // CF debugging: // set data to write to CF register #separate void set_data() { int temp; printf("Data (hex): "); temp = loadc(); putc(temp); if((temp = fromHex(temp)) > 16) return; curData = (temp << 4); temp = loadc(); putc(temp); if ((temp = fromHex(temp)) > 16) return; curData |= temp; printf("\nData 0x%2X(%u)\n", curData, curData); } // CF debugging: // set CF register address #separate void set_address() { int temp; printf("Addr (0-7): "); temp=loadc(); putc(temp); temp = fromHex(temp); if (temp > 7) return; curAddr = temp; printf("\nAddr %u\n", curAddr); } // Find data file in root directory // If found returns TRUE and first cluster in global var cluster #separate boolean find_data_file_name() { int i, j, k, l; boolean match; move32(sector, dir_start); for (i=0; i >4; i++) { cf_start_sector_read(); for (j=0; j<16; j++) { match=true; for (k=0; k<11; k++) if (cf_read()!=fname[k]) match=false; cf_read_skip(26-11); cluster=cf_read()|((long)cf_read()<<8); if (match) return true; cf_read_skip(32-28); } inc32(sector); } return false; } // Scan FAT to determine the length of first consecutive cluster chain in the data file // Returns file chain length (number of clusters) in data_file_size // Note: Current implementationonly works with consecutive cluster chains; // if file is fragmented only first piece is used #separate void scan_data_file_clusters() { char tmp[4]; long ptr; long c; zero32(tmp); move32(sector, fat_start); tmp[0]=cluster>>8; add32(sector, tmp); cf_start_sector_read(); ptr=cluster&0xFF00; while (ptr++ >4; add32(data_start, dir_start); if (is_zero32(data_sectors)) { // If data_sectors is 0 we got it in a wrong place cf_read_skip(0x20-0x18); data_sectors[0]=cf_read(); data_sectors[1]=cf_read(); data_sectors[2]=cf_read(); data_sectors[3]=cf_read(); cf_read_skip(0x3A-0x24); } else cf_read_skip(0x3A-0x18); if (cf_read()!=0x36) return FALSE; // file system id must be FAT16 sub32(data_sectors, data_start); add32(data_sectors, sector); // Enable Microdrive write cache... Send me e-mail for more information enable_microdrive_write_cache(); // File is valid if we can find valid file. file_valid=find_data_file(); cf_idle(100); if (file_valid) { // convert data file size from clusters to sectors // Note: sectors per cluster must be power of 2 tmp=sectors_per_cluster; while (!(tmp&1)) { shift_left(data_file_size,4,0); tmp>>=1; } // calculate first sector of data file zero32(sector); sector[0]=(cluster-2); sector[1]=(cluster-2)>>8; tmp=sectors_per_cluster; while (!(tmp&1)) { shift_left(sector,4,0); tmp>>=1; } // and now data_start points to first sector of data file add32(data_start, sector); return true; } else { // File not found: let's get idle and depressed return false; } } // Tests IR tag reader from Borg lab #separate void tag_test() { char tag[4]; long tagtime; putI2C(0xA0, 2); I2C_start(); I2C_write(0xA0 | I2CREAD); tag[0]=i2c_read(); tag[1]=i2c_read(); tag[2]=i2c_read(); tag[3]=i2c_read(); tagtime=i2c_read(); tagtime=tagtime<<8|i2c_read(); i2c_read(0); I2C_stop(); printf("%2X%2X%2X%2X ", tag[0], tag[1], tag[2], tag[3]); putI2C(0xA0, 3); I2C_start(); I2C_write(0xA0 | I2CREAD); tag[0]=i2c_read(); tag[1]=i2c_read(); tag[2]=i2c_read(); tag[3]=i2c_read(); tagtime=i2c_read(); tagtime=tagtime<<8|i2c_read(); i2c_read(0); I2C_stop(); printf("%2X%2X%2X%2X\n", tag[0], tag[1], tag[2], tag[3]); } // reads ADC channel and sends result #separate void send_adc_sample(int channel) { long sample; set_adc_channel(channel); sample=read_adc(); putc(sample); putc(sample>>8); } // I2C command processor // ib - I2C start // ie - I2C stop // ir - I2C read with ACK // i0 - I2C read without ACK // iw - I2C write // ip - I2C poll #separate void access_i2c() { switch (loadc()) { case 'b': i2c_start(); break; case 'e': i2c_stop(); break; case 'r': putc(i2c_read()); break; case '0': putc(i2c_read(0)); break; case 'w': i2c_write(loadc()); break; case 'p': putc(i2c_poll()); break; } } #separate void read_mithril_sensor() { byte addr; addr=loadc(); putI2C(addr, loadc()); I2C_start(); I2C_write(addr | I2CREAD); putc(i2c_read()); putc(i2c_read()); putc(i2c_read()); putc(i2c_read(0)); I2C_stop(); } // Command processor #separate boolean process_command() { if (!input(RCIF)) return FALSE; cmd = loadc(); /* Echo the character */ if ((cmd>='0')&&(cmd<='7')) { send_adc_sample(cmd-'0'); } else if (cmd=='i') access_i2c(); else if (cmd=='m') read_mithril_sensor(); else { putc(cmd); puts(""); switch (cmd) { case 0xA5: reprogram(); break; case '+': print_time(); break; case '-': reset_time(); break; case '=': check_cf(); break; case '*': identify_drive(); break; case '$': read_sector(); break; case '@': cf_idle(100); break; case '.': cf_sleep(); break; case ',': cf_standby(); break; case 't': set_time(); break; case '(': putc(rtc_read(loadc())); break; case '!': cf_reset(); break; case 'd': set_data(); break; case 'a': set_address(); break; case 'r': read_register(); break; case 'w': write_register(); break; #ifdef Rochester case '?': tag_test(); break; #endif case '#': #ifdef GAME send_player_info(); #endif #ifdef Rochester save_audio(); #endif #ifdef ESL send_data_bim(); #endif #ifdef Tim send_data_Tim(); #endif break; } print_prompt(); } return TRUE; }