📄 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 <vadim@media.mit.edu>
// 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<count; i++) {
*(&val)=getc();
*(&val+1)=getc();
if (val==read_program_eeprom(addr)) putc(1);
else {
write_program_eeprom(addr, val);
if (val==read_program_eeprom(addr)) putc(1);
else putc(0);
}
addr++;
restart_wdt();
}
}
#asm
movlw 0
movwf 0x0A
goto 0
#endasm
}
#endif
// jumps to self_program()
// normally called from command processor
// Note: if you want serial programming to work make sure you can always interrupt
// your program from serial port and have a command that calls this function
#inline
void reprogram()
{
#ifdef InitialProgram
self_program();
#else
#asm
movlw 0x18
movwf 0x0A
goto 0x700
#endasm
#endif
}
// timer function
// increments ms counter
// performs timed AD conversion
// can do a lot of other neat stuff!
// normally interrupts 1000 times per second
// Note: in multisensor boards configuration can be set to 8000 times/sec
// to sample audio
#int_timer2
void timer2() {
static int i;
// resets watchdog timer
// Note: if you disable timer interrupt do this periodically somewhere else
// otherwise WDT will reset PIC in ~2 seconds
restart_wdt();
// inc32(ms);
if (++ms[0]==0) if (++ms[1]==0) if (++ms[2]==0) ++ms[3];
if (ad_on) {
#ifdef Tim
if (ad_count==3) voltage=read_adc();
if (ad_count==0)
#endif
if (/*(ad_count==3) && */(buf_count<buf_size)) {
i=(buf_head+buf_count)&0x1F;
buffer[i]=read_adc();
buf_count++;
}
// else overflow
if (audio) ad_count=0;
else {
ad_count++;
if (ad_count>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()
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -