📄 phonerec.c
字号:
void inline spi_finish(void);void mmc_command(unsigned char cmd, unsigned long arg);/* ------------------------------ Main Program ---------------------------- */int main(void){ DDRD |= _BV(PD1); // UART TX is output RTS_DDR |= _BV(RTS_BIT); // CTS is output RTS_PORT |= _BV(RTS_BIT); // We can't accept data right now /* Set PBD in PORTD to output -- it's the Playback PWM output*/ DDRD |= _BV(PD4) | _BV(PD7); /* The whole C port is for input */ DDRC=0; HOOK_DDR |= _BV(HOOK_BIT); // Hook relay // Timer 0 Setup -- Used to make the basic 8KHz samping rate used by the // ADC and most everything else TCCR0 = _BV(WGM01) // Enable CTC mode | 2; // Enable counter with prescaling=CLK/8 // Set OCR0 initial value for making ADC auto-trigger rate = 8000Hz // Nearly everything is synchronous with this rate, so we have // 1382.4 cycles to do all our work. We acheive this non-integral number // of cycles at the Timer0 compare match interrupt service routine by // making OCR0=171 every 5 samples or 172 otherwise. // For sake of timing issues, it is safer to think that we have at most // 172*8 = 1376 cycles at most to do everything OCR0 = 172; // Generate interrupts on compare matches TIMSK |= _BV(OCIE0); // Timer 1 Setup -- Used for generating output audio for the phone line // OC1A disconnect, OC1B clear on upcounting match, set on downcouting // match; PWM mode = phase and frequency correct with top at OC1A // (mode 9, here we set just the 2 low bits = 1) TCCR1A = (0<<COM1A0) | (2<<COM1B0) | (3<<WGM10); // PWM mode = phase and frequency correct with top at OC1A // (mode 9, here we set just the 2 upper bits = 2) // Timer clock = no prescaling // No input captures TCCR1B = (2<<WGM12) | (1<<CS10); /* 500 upcounts + 500 downcounts = 1000 cycles, fits exactly with the main 8KHz sample rate generated from timer1 */ OCR1A=255; // Timer2 setup -- generates output audio for the monitor speaker TCCR2 = _BV(WGM20) | _BV(WGM21) // Fast PWM | _BV(COM21) | _BV(COM20) // Set at compare match, clear at bottom | _BV(CS20); // enable counter with prescaler = 1 // UART setup -- used for transmitting audio and detected line events // to the computer; and for receiving commands from the PC UCSRC = 0x80|(3<<UCSZ0); // Set async 8bit, no parity, 1 stop bit UCSRB = _BV(TXEN) // Enable transmitter,... | _BV(RXEN) // receiver,... | _BV(RXCIE); // receiver interrupts,... //| _BV(UDRIE); // and transmit interrupts. UBRRL = 5; // Set 115200bps with external 11.0592MHz clock UBRRH = 0; // (this yields 0.00% error) // ADC Setup -- Gets the actual audio // Enable ADC, single conversion, generate interrupt on done // prescaler=clk/64 (yields ADC clock=172.8KHz, well within the // recommended 200KHz maximum). Normal conversions take about 832 cycles. ADCSRA = _BV(ADEN) | (6<<ADPS0) | _BV(ADIE) | _BV(ADATE); ADMUX = 0 | _BV(ADLAR); // Use AREF, channel 0, left adjust result ADMUX |= _BV(REFS0) | _BV(REFS1); // 2.56V reference SFIOR = (SFIOR & 0x1F)|(3<<ADTS0); // Auto Tigger on Timer0 compare match // Analog Comparator setup -- used to detect whether the phone line is // in use, idle or disconnected SFIOR &= ~_BV(ACME); // Disable Analog Comparator Mux, AIN1 is neg input ACSR &= ~_BV(ACBG); // Disable Bandgap ref, positive input is from AIN0 ACSR &= ~_BV(ACD); // Enable Analog Comparator#ifdef HAVE_MMC // SPI setup -- used for talking to the MMC/SD card PORTB |= _BV(PB7); // Set SCK hi DDRB |= _BV(PB7) | _BV(PB5) | _BV(PB4); // SCK, MOSI and SS are outputs SPCR |= _BV(MSTR) // Master mode | _BV(SPE); // Enable SPI // Sets up the audio and IO buffers to buffer A and B arbitrarily. // Could just as well be the reverse. Those pointers are exchanged // at the end of each read/write/playback/record cycle audio_buf=buffer_a; io_buf=buffer_b;#endif // HAVE_MMC fifo_head=fifo_tail=0; #ifdef HAVE_GOERTZEL // Sets up the accumulators for the MAC (multiply-and-accumulate) phase // of Goertzel's algorithm. These pointers are exchanged after each // block is processed. d=q1; q=q2;#endif // HAVE_GOERTZEL // ---------------- Setup port directions #ifdef HAVE_LCD // Set LCD backlight port as output LCD_BACKLIGHT_DDR |= _BV(LCD_BACKLIGHT_BIT); // Turn backlight on LCD_BACKLIGHT_PORT &= ~_BV(LCD_BACKLIGHT_BIT); lcd_init(LCD_DISP_ON);#endif has_sample=FALSE; /* Enable interrupts */ sei(); for (;;) { //set_sleep_mode(0); //sleep_mode(); if (has_sample) { has_sample=FALSE; process_sample(); } } /* We never return, but we put this here to avoid gcc warnings */ return 0;}#ifdef HAVE_MMCvoid inline do_block_mmc_io(void){ if (mmc_read_state==3) { if (mmc_ptr_count) { //dtmf_string[4]='-'; if (spi_has_reply) { //dtmf_string[4]='+'; *mmc_ptr++=spi_reply; mmc_ptr_count--; spi_get_next(); } } else { //dtmf_string[1]='O'; mmc_read_state++; spi_finish(); } } else if (mmc_write_state==3) { if (mmc_ptr_count) { //dtmf_string[10]='+'; SPDR=*mmc_ptr++; mmc_ptr_count--; } else { mmc_write_state++; spi_buf_putc(0xFF); // First byte of the dummy 16-bit CRC spi_start_xmit(); spi_autofinish=FALSE; } }}void stop_playback(void){ if (mmc_read_cluster) audio_status |= AS_PLAYBACK_SHUTTING_DOWN;#ifdef ALLOW_SIMULTANEOUS_RECORD_AND_PLAYBACK if (has_index & DEFERRED_INDEX_WRITE) { has_index &= ~DEFERRED_INDEX_WRITE; mmc_write_index_state=1; }#endif // ALLOW_SIMULTANEOUS_RECORD_AND_PLAYBACK}void start_playback(unsigned short from_cluster, unsigned short to_cluster){ if (mmc_read_cluster) { // We're already playing something -- so all we've got to do is // to arrange the new places to read mmc_read_cluster=from_cluster; mmc_read_stop_at=to_cluster; mmc_read_cluster_sector=0; } else { // We're not playing anything yet#ifdef ALLOW_SIMULTANEOUS_RECORD_AND_PLAYBACK if (mmc_write_cluster) { // Attempt to have combined record&playback... for now, we // can't start playback if there is already a recording in // progress mmc_read_cluster=1; //dtmf_string[11]='C'; } else #endif // ALLOW_SIMULTANEOUS_RECORD_AND_PLAYBACK { // We should only start playing back if the MMC card has // been sucessfully initialized in the past at least once if (!mmc_init_state) { mmc_read_buf_state=1; mmc_read_cluster=from_cluster; mmc_read_stop_at=to_cluster; //dtmf_string[11]='P'; mmc_init_state=6; mmc_read_cluster_sector=0; audio_cnt=0; } } }}void stop_recording(void){ if (audio_status & AS_RECORDING_IN_PROGRESS) audio_status |= AS_RECORDING_SHUTTING_DOWN; xmit(CMD_BLOCK_START); xmit(CMD_RECORDING_STOPPED);}void start_recording(unsigned short cluster){ if (!mmc_init_state && !mmc_write_cluster) {#ifndef ALLOW_SIMULTANEOUS_RECORD_AND_PLAYBACK if (mmc_read_cluster) { // Attempt to have combined record & playback... // for now, the two of them won't work together, // so we stop the playback first // audio_status |= AS_PLAYBACK_SHUTTING_DOWN; //dtmf_string[11]='C'; }#endif // ALLOW_SIMULTANEOUS_RECORD_AND_PLAYBACK if (!cluster) cluster=mmc_index.last_cluster; mmc_write_cluster=cluster; mmc_index.start[mmc_index.last_call++]=cluster; if (mmc_index.last_call==MAXCALLS) mmc_index.last_call=0; current_playback_call=mmc_index.last_call; if (mmc_index.last_call==mmc_index.first_call) { mmc_index.first_call++; if (mmc_index.first_call==MAXCALLS) mmc_index.first_call=0; } audio_status |= AS_RECORDING_IN_PROGRESS; if (!mmc_read_cluster) { audio_cnt=0; } mmc_write_cluster_sector=0; } xmit(CMD_BLOCK_START); xmit(CMD_RECORDING_STARTED); call_number_already_copied=FALSE; call_year = now_year; call_month = now_month; call_day = now_day; call_hour = now_hour; call_min = now_min; call_sec = now_sec;}#endif // HAVE_MMC#define MMC_MANY_IO_BLOCKSvoid process_sample(void){ #ifdef HAVE_MMC#ifdef MMC_MANY_IO_BLOCKS do_block_mmc_io();#endif // MMC_MANY_IO_BLOCKS#endif // HAVE_MMC // Tell the computer we can receive data on the serial port RTS_PORT &= ~_BV(RTS_BIT); unsigned char pwm=0; if (has_rx_data()) { pwm=recv(); if (cmd_cnt>0) { if (cmd_cnt==1) { if (pwm==CMD_BLOCK_START) { cmd_cnt=0; } #ifdef HAVE_LCD else if (pwm==CMD_LCD_BACKLIGHT_ON) { cmd_cnt=0; // Turn backlight on LCD_BACKLIGHT_PORT &= ~_BV(LCD_BACKLIGHT_BIT); } else if (pwm==CMD_LCD_BACKLIGHT_OFF) { cmd_cnt=0; // Turn backlight off LCD_BACKLIGHT_PORT |= _BV(LCD_BACKLIGHT_BIT); }#endif // HAVE_LCD else if (pwm==CMD_GO_OFF_HOOK) { cmd_cnt=0; HOOK_PORT |= _BV(HOOK_BIT); // Turn on hook relay } else if (pwm==CMD_GO_ON_HOOK) { cmd_cnt=0; HOOK_PORT &= ~_BV(HOOK_BIT); // Turn off hook relay } else if (pwm==CMD_SET_TIME) { cmd_cnt++; pending_cmd=pwm; } } else if (pending_cmd==CMD_SET_TIME) { if (cmd_cnt==2) now_hour= pwm; if (cmd_cnt==3) now_min = pwm; if (cmd_cnt==4) now_sec = pwm; cmd_cnt++; if (cmd_cnt==5) cmd_cnt=0; } else if (pending_cmd==CMD_SET_DATE) { if (cmd_cnt==2) now_year = pwm; if (cmd_cnt==3) now_month = pwm; if (cmd_cnt==4) now_day = pwm; cmd_cnt++; if (cmd_cnt==5) cmd_cnt=0; } pwm=last_pwm; } else { if (pwm==CMD_BLOCK_START) { cmd_cnt++; pwm=last_pwm; } else { age=0; if (pwm>248) pwm=248; last_pwm=pwm; } } } else { if (age>10) { age=0; pwm=0; last_pwm=0; } else { pwm=last_pwm; age++; } } if (wav_cnt) { pwm=pgm_read_byte(wavp++); if (!pwm) { wavp=wavp0; pwm=pgm_read_byte(wavp++); if (!--wav_rep) { wav_rep=wav_rep0; wav_cnt--; } } if (wav_cnt & wav_mask) pwm=128; } OCR1B = pwm; //OCR2=pwm; //OCR2 = last_reported_hook==OffHook ? sample8 : 0; //OCR2=pgm_read_byte(wav440+w440); //if (++w440==18) w440=0; #ifdef HAVE_MMC if (audio_status && !audio_cnt) { unsigned char *tmp=audio_buf; audio_buf=io_buf; io_buf=tmp; //dtmf_string[9]='*'; if (mmc_read_buf_state) { //dtmf_string[5]='^'; } if (mmc_write_cluster) { //dtmf_string[10]='r'; mmc_init_state=1; mmc_write_buf_state=1; if (audio_status & AS_RECORDING_SHUTTING_DOWN) { if (mmc_write_cluster_sector==15) { unsigned char i,*p=io_buf+ MMC_BLOCK_SIZE-7-MAXDTMFSTRINGLENGTH; *p++=1; // Version info for (i=0;i<MAXDTMFSTRINGLENGTH+6;i++) *p++=call_number[i]; } } } else if (mmc_read_cluster) { //dtmf_string[9]='p'; mmc_read_buf_state=10; //mmc_init_state=6; } } unsigned char *p=audio_buf+audio_cnt; if (audio_status & AS_PLAYBACK_IN_PROGRESS) { OCR2=*p;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -