Wavebubble 2010 Firmware
|
00001 00044 #include <avr/io.h> 00045 #include <avr/pgmspace.h> 00046 #include <avr/interrupt.h> 00047 #include <util/delay.h> 00048 #include <avr/eeprom.h> 00049 #include <ctype.h> 00050 #include "serial.h" 00051 #include "pll.h" 00052 #include "main.h" 00053 00054 uint16_t EEMEM dummy = 0; 00055 uint16_t EEMEM validity = 0; 00056 uint8_t EEMEM max_programs=0; 00057 uint8_t EEMEM curr_program=0; 00058 00059 uint8_t EEMEM settings_ee; 00060 00061 volatile uint16_t global_delay = 0; 00062 volatile uint16_t led_delay = 0; 00063 volatile uint16_t key_delay = 0; 00064 volatile uint8_t lowbatt_timer = 0; 00065 00074 void delay_ms(uint16_t ms) { 00075 00076 global_delay = ms; 00077 00078 // global_delay will be decreased in timer0 ISR 00079 while (global_delay > 0) 00080 asm volatile ("nop"); 00081 } 00082 00087 static void power_off(void) { 00088 pc_puts_P(PSTR("Powering OFF...\n")); 00089 delay_ms(300); 00090 #ifdef HW_REV_A 00091 // Power OFF device 00092 POWERON_PORT |= _BV(POWERON); 00093 #else 00094 // Power OFF device 00095 POWERON_PORT &=~ _BV(POWERON); 00096 #endif 00097 } 00098 00105 void set_sawtooth_high(void) { 00106 // set the pin to be a high output 00107 FREQSET_DDR |= _BV(FREQSET); 00108 FREQSET_PORT |= _BV(FREQSET); 00109 } 00110 00117 void set_sawtooth_low(void) { 00118 // set the pin to be a high input 00119 FREQSET_DDR &= ~_BV(FREQSET); 00120 FREQSET_PORT |= _BV(FREQSET); 00121 } 00122 00130 void set_resistor(uint8_t rnum, uint8_t rval) { 00131 uint16_t d; 00132 00133 d = rnum; 00134 d <<= 8; 00135 d |= rval; 00136 00137 SPICS_PORT &= ~_BV(SPICS); 00138 asm volatile ("nop"); 00139 asm volatile ("nop"); 00140 asm volatile ("nop"); 00141 asm volatile ("nop"); 00142 00143 for (rnum=0; rnum < 10; rnum++) { 00144 if (d & 0x200) { 00145 SPIDO_PORT |= _BV(SPIDO); 00146 } else { 00147 SPIDO_PORT &= ~_BV(SPIDO); 00148 } 00149 SPICLK_PORT |= _BV(SPICLK); 00150 asm volatile ("nop"); 00151 asm volatile ("nop"); 00152 asm volatile ("nop"); 00153 asm volatile ("nop"); 00154 asm volatile ("nop"); 00155 asm volatile ("nop"); 00156 SPICLK_PORT &= ~_BV(SPICLK); 00157 d <<= 1; 00158 } 00159 asm volatile ("nop"); 00160 asm volatile ("nop"); 00161 asm volatile ("nop"); 00162 asm volatile ("nop"); 00163 SPICS_PORT |= _BV(SPICS); 00164 } 00165 00171 static void init_eeprom(void) { 00172 uint16_t temp; 00173 00174 uint8_t *p = 0; 00175 00176 // Read validity word 00177 temp = eeprom_read_word(&validity); 00178 00179 // Check validity, BEEF is good here. 00180 if( temp != 0xEFBE ) { 00181 //Not correct? Init EEPROM. 00182 for(uint16_t i = 0; i < E2END+1; i++) eeprom_write_byte(p++, 0); 00183 } 00184 eeprom_write_word(&validity, 0xEFBE); 00185 } 00186 00191 static void init_pwm(void) { 00192 DDRB |= _BV(PB1); // make OCR1A it an output 00193 DDRB |= _BV(PB2); // make OCR1B it an output 00194 TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM12) | _BV(WGM11) | _BV(WGM10); // 10bit FastPWM 00195 TCCR1B = _BV(CS10); 00196 OCR1A = 0x0; // change this value to adjust PWM. 00197 OCR1B = 0x0; // change this value to adjust PWM. 00198 } 00199 00204 static void print_menu(void) { 00205 print_div(); 00206 pc_puts_P(PSTR(" p > Display progs\n")); 00207 pc_puts_P(PSTR(" a > Add prog\n")); 00208 pc_puts_P(PSTR(" d > Delete prog\n")); 00209 pc_puts_P(PSTR(" t > Tune prog\n")); 00210 pc_puts_P(PSTR(" e > Erase all\n")); 00211 pc_puts_P(PSTR(" q > Quit menu\n")); 00212 pc_puts_P(PSTR(" o > Power off\n")); 00213 print_div(); 00214 pc_puts_P(PSTR("=> ")); 00215 } 00216 00225 static void print_program(jammer_setting *setting, uint8_t n, uint8_t m) { 00226 print_div(); 00227 pc_puts_P(PSTR("Program #")); putnum_ud(n+1); 00228 pc_puts_P(PSTR(" of ")); 00229 putnum_ud(m); pc_putc('\n'); 00230 00231 pc_puts_P(PSTR("High band VCO: ")); 00232 if(setting->startfreq1 == 0) { 00233 pc_puts_P(PSTR("OFF")); 00234 } else { 00235 putnum_ud(setting->startfreq1); 00236 pc_puts_P(PSTR(" -> ")); 00237 putnum_ud(setting->endfreq1); 00238 pc_puts_P(PSTR(" (")); putnum_ud(setting->dc_offset1); 00239 pc_puts_P(PSTR(", ")); putnum_ud(setting->bandwidth1); 00240 pc_putc(')'); 00241 } 00242 pc_puts_P(PSTR("\nLow band VCO: ")); 00243 if(setting->startfreq2 == 0) { 00244 pc_puts_P(PSTR("OFF")); 00245 } else { 00246 putnum_ud(setting->startfreq2); 00247 pc_puts_P(PSTR(" -> ")); 00248 putnum_ud(setting->endfreq2); 00249 pc_puts_P(PSTR(" (")); putnum_ud(setting->dc_offset2); 00250 pc_puts_P(PSTR(", ")); putnum_ud(setting->bandwidth2); 00251 pc_putc(')'); 00252 } 00253 pc_puts_P(PSTR("\n")); 00254 } 00255 00260 static void display_programs(void) { 00261 uint8_t i, progs; 00262 jammer_setting setting; 00263 00264 progs = eeprom_read_byte(&max_programs); 00265 if(progs > MAX_PROGRAMS) progs = MAX_PROGRAMS; 00266 putnum_ud(progs); pc_puts_P(PSTR(" of ")); 00267 putnum_ud(MAX_PROGRAMS); pc_puts_P(PSTR(" programs in memory\n\r")); 00268 for (i=0; i< progs; i++) { 00269 eeprom_read_block(&setting, 00270 &settings_ee+sizeof(jammer_setting)*i, 00271 sizeof(jammer_setting)); 00272 00273 print_program(&setting, i, progs); 00274 } 00275 } 00276 00281 static void delete_program(void) { 00282 uint8_t n, max; 00283 jammer_setting setting; 00284 00285 display_programs(); 00286 print_div(); 00287 pc_puts_P(PSTR("Delete #? ")); 00288 n = pc_read16(); 00289 max = eeprom_read_byte(&max_programs); 00290 if(max > MAX_PROGRAMS) max = MAX_PROGRAMS; 00291 00292 if ( (n == 0) || (n > max)) { 00293 pc_puts_P(PSTR("\n\rInvalid\n\r")); 00294 return; 00295 } 00296 00297 if (n == max) { 00298 // easy, just reduce program count 00299 eeprom_write_byte(&max_programs, max-1); 00300 } else { 00301 // Delete desired program 00302 for(; n < max; n++) { 00303 // Shift trailing program blocks 00304 eeprom_read_block(&setting, 00305 &settings_ee+sizeof(jammer_setting)*n, 00306 sizeof(jammer_setting)); 00307 00308 eeprom_write_block(&setting, 00309 &settings_ee+(sizeof(jammer_setting)*(n-1)), 00310 sizeof(jammer_setting)); 00311 // Remove deleted program from count 00312 eeprom_write_byte(&max_programs, max-1); 00313 } 00314 } 00315 } 00316 00323 static void tune_it (uint8_t n, uint8_t save) { 00324 jammer_setting setting; 00325 00326 eeprom_read_block(&setting, 00327 &settings_ee+sizeof(jammer_setting)*n, 00328 sizeof(jammer_setting)); 00329 // Tune high band VCO 00330 if ((setting.startfreq1 != 0) && (setting.endfreq1 != 0)) { 00331 setting.bandwidth1 = tune_rf_band(setting.startfreq1, setting.endfreq1, 0); 00332 setting.dc_offset1 = OCR1A; 00333 } 00334 // Tune low band VCO 00335 if ((setting.startfreq2 != 0) && (setting.endfreq2 != 0)) { 00336 setting.bandwidth2 = tune_rf_band(setting.startfreq2, setting.endfreq2, 1); 00337 setting.dc_offset2 = OCR1B; 00338 } 00339 if (save) { 00340 eeprom_write_block(&setting, 00341 &settings_ee+sizeof(jammer_setting)*n, 00342 sizeof(jammer_setting)); 00343 } 00344 } 00345 00350 static void tune_program(void) { 00351 uint8_t n; 00352 00353 if (eeprom_read_byte(&max_programs) == 0) { 00354 pc_puts_P(PSTR("\nNo programs stored.\n")); 00355 return; 00356 } 00357 00358 display_programs(); 00359 print_div(); 00360 pc_puts_P(PSTR("Tune prog # ")); 00361 n = pc_read16(); 00362 if (n > eeprom_read_byte(&max_programs)) { 00363 pc_puts_P(PSTR("\n\rInvalid #\n")); 00364 } else { 00365 tune_it(n-1, 1); 00366 } 00367 } 00368 00373 static void add_program(void) { 00374 jammer_setting new_setting; 00375 uint8_t progs; 00376 00377 progs = eeprom_read_byte(&max_programs); 00378 if(progs >= MAX_PROGRAMS) { 00379 pc_puts_P(PSTR("Memory full.\n")); 00380 return; 00381 } 00382 00383 pc_puts_P(PSTR("Enter start and stop frequency for each VCO.\nEnter 0 to turn OFF VCO.\n")); 00384 pc_puts_P(PSTR("Low Band: 345-1350MHz - High Band 1225-2715MHz\n\n")); 00385 00386 highbandstart: 00387 pc_puts_P(PSTR("High band VCO\nstart: ")); 00388 new_setting.startfreq1 = pc_read16(); 00389 if(new_setting.startfreq1 == 0) { 00390 new_setting.endfreq1 = 0; 00391 goto lowbandstart; 00392 } 00393 if(new_setting.startfreq1 < HIGHBAND_VCO_LOW) { 00394 pc_puts_P(PSTR("Frequency to low.\n")); 00395 goto highbandstart; 00396 } 00397 highbandend: 00398 pc_puts_P(PSTR("end: ")); 00399 new_setting.endfreq1 = pc_read16(); 00400 if(new_setting.endfreq1 > HIGHBAND_VCO_HIGH) { 00401 pc_puts_P(PSTR("Frequency to high.\n")); 00402 goto highbandend; 00403 } 00404 lowbandstart: 00405 pc_puts_P(PSTR("\nLow band VCO\nstart: ")); 00406 new_setting.startfreq2 = pc_read16(); 00407 if(new_setting.startfreq2 == 0) { 00408 new_setting.endfreq2 = 0; 00409 goto saveprog; 00410 } 00411 if(new_setting.startfreq2 < LOWBAND_VCO_LOW) { 00412 pc_puts_P(PSTR("Frequency to low.\n")); 00413 goto lowbandstart; 00414 } 00415 lowbandend: 00416 pc_puts_P(PSTR("end: ")); 00417 new_setting.endfreq2 = pc_read16(); 00418 if(new_setting.endfreq2 > LOWBAND_VCO_HIGH) { 00419 pc_puts_P(PSTR("Frequency to high.\n")); 00420 goto lowbandend; 00421 } 00422 saveprog: 00423 if( (new_setting.startfreq1 == 0) && (new_setting.startfreq2 == 0)) { 00424 pc_puts_P(PSTR("Nothing to save.\n")); 00425 return; 00426 } 00427 new_setting.dc_offset1 = new_setting.dc_offset2 = 0; 00428 new_setting.bandwidth1 = new_setting.bandwidth2 = 0; 00429 00430 eeprom_write_block(&new_setting, 00431 &settings_ee+(sizeof(jammer_setting)*progs), 00432 sizeof(jammer_setting)); 00433 00434 eeprom_write_byte(&max_programs, progs+1); 00435 pc_puts_P(PSTR("Saved program ")); putnum_ud(progs+1); 00436 00437 pc_putc('\n'); 00438 } 00439 00444 static void run_menu(void) { 00445 char c; 00446 do { 00447 print_menu(); 00448 c = pc_getc(); 00449 pc_putc(c); 00450 pc_putc('\n'); 00451 switch (c) { 00452 case 'p': 00453 display_programs(); 00454 break; 00455 case 'a': 00456 add_program(); 00457 break; 00458 case 'd': 00459 delete_program(); 00460 break; 00461 case 't': 00462 tune_program(); 00463 break; 00464 case 'e': 00465 pc_puts_P(PSTR("Erase all programs? y/n: ")); 00466 c = pc_getc(); 00467 pc_putc(c); 00468 pc_putc('\n'); 00469 if(c == 'y') { 00470 eeprom_write_word(&validity, 0x0000); 00471 init_eeprom(); 00472 } 00473 break; 00474 case 'q': break; 00475 case 'o': 00476 power_off(); 00477 break; 00478 default: 00479 pc_puts_P(PSTR("Bad command\n")); 00480 } 00481 } while (c != 'q'); 00482 } 00483 00484 00491 int main(void) { 00492 00493 OSCCAL = 0xC0; // Calibrate internal RC oscillator 00494 00495 // setup system tick counter 00496 OCR0A = 125; // timer0 capture at 1ms 00497 TCCR0A |= _BV(WGM01); 00498 TCCR0B |= _BV(CS01) | _BV(CS00); // Set timer0 CTC mode, prescaler 64 00499 TIMSK0 |= _BV (OCIE0A); // Enable timer0 output compare interrupt 00500 00501 sei(); // Enable global interrupts 00502 00503 key_delay = 0; 00504 // Power key must be pressed at least 2 seconds to power ON 00505 while(key_delay < 2000) asm volatile ("nop"); 00506 00507 // Power ON switch pin output and force HIGH to keep device running 00508 POWERON_PORT |= _BV(POWERON); 00509 POWERON_DDR |= _BV(POWERON); 00510 00511 usart_init(); // Init serial communication 00512 00513 DDRD |= _BV(PD1); // USART TxD0 output 00514 00515 // LED pin output and LED on 00516 LEDDDR |= _BV(LED); 00517 LEDPORT |= _BV(LED); 00518 00519 // Program key input and pull-up 00520 PROGKEY_PORT |= _BV(PROGKEY); 00521 PROGKEY_DDR &=~ _BV(PROGKEY); 00522 00523 // Setup port and pins for software SPI operation to control digital potentiometer 00524 SPICS_DDR |= _BV(SPICS); 00525 SPIDO_DDR |= _BV(SPIDO); 00526 SPICLK_DDR |= _BV(SPICLK); 00527 00528 SPICS_PORT |= _BV(SPICS); 00529 SPICLK_PORT &= ~_BV(SPICLK); 00530 00531 // Setup VCO power control port and pins 00532 POWERCTL1_DDR |= _BV(POWERCTL1); 00533 POWERCTL2_DDR |= _BV(POWERCTL2); 00534 POWERCTL1_PORT &= ~_BV(POWERCTL1); // turn off VCO1+gain stage 00535 POWERCTL2_PORT &= ~_BV(POWERCTL2); // turn off VCO2+gain stage 00536 00537 init_pwm(); // Init tuning voltage generator 00538 00539 pll_init(); // Init PLL control 00540 00541 // Set digital potentiometer to minimum 00542 set_resistor(BANDWADJ1_RES, 0); 00543 set_resistor(BANDWADJ2_RES, 0); 00544 00545 set_sawtooth_low(); // Set NE555 mode 00546 00547 init_eeprom(); // Check EEPROM validity 00548 00549 pc_puts_P(PSTR("Wave Bubble 2010\nFW: " __DATE__" / " __TIME__"\n\n")); 00550 00551 uint8_t progs, programnum; 00552 jammer_setting setting; 00553 00554 progs = eeprom_read_byte(&max_programs); 00555 if(progs > MAX_PROGRAMS) progs = MAX_PROGRAMS; 00556 00557 if (progs != 0) { 00558 pc_puts_P(PSTR("Press key to enter menu...")); 00559 delay_ms(2000); 00560 } 00561 00562 no_progs: // Go here in case 'q' is pressed and no programs are stored 00563 00564 if ( (UCSR0A & _BV(RXC0)) && isascii(pc_getc()) ) { 00565 pc_putc('\n'); 00566 run_menu(); 00567 } else if (progs == 0) 00568 run_menu(); 00569 00570 run_prog: // Go here when program key is pressed, switch to next program 00571 00572 progs = eeprom_read_byte(&max_programs); 00573 if(progs == 0) { 00574 pc_puts_P(PSTR("No programs stored.\n")); 00575 goto no_progs; 00576 } 00577 if(progs > MAX_PROGRAMS) progs = MAX_PROGRAMS; 00578 00579 programnum = eeprom_read_byte(&curr_program); 00580 if (programnum >= progs) 00581 programnum = 0; 00582 00583 eeprom_read_block(&setting, 00584 &settings_ee+sizeof(jammer_setting)*programnum, 00585 sizeof(jammer_setting)); 00586 00587 pc_putc('\n'); 00588 print_program(&setting, programnum, progs); 00589 00590 print_div(); 00591 00592 if ((setting.dc_offset1 == 0) && (setting.bandwidth1 == 0) && 00593 (setting.dc_offset2 == 0) && (setting.bandwidth2 == 0)) { 00594 tune_it(programnum, 0); // mem check return 00595 } else { 00596 if (setting.startfreq1 != 0) { 00597 OCR1A = setting.dc_offset1; 00598 set_resistor(BANDWADJ1_RES, setting.bandwidth1); 00599 POWERCTL1_PORT |= _BV(POWERCTL1); // turn on vcos/gain 00600 } 00601 if (setting.startfreq2 != 0) { 00602 OCR1B = setting.dc_offset2; 00603 set_resistor(BANDWADJ2_RES, setting.bandwidth2); 00604 POWERCTL2_PORT |= _BV(POWERCTL2); // turn on vcos/gain 00605 } 00606 } 00607 00608 uint8_t key_press = 0, led_count = 0; 00609 00610 for(;;) { 00611 // check battery voltage 00612 uint16_t batt = 0; 00613 ADMUX = 6; 00614 ADCSRA |= _BV(ADSC); 00615 while (ADCSRA & _BV(ADSC)); // wait for conversion to finish 00616 batt = ADC; 00617 //putnum_ud(batt); pc_putc('\n'); 00618 00619 // Reset low battery timer as long as battery voltage is good 00620 if(batt > 310) lowbatt_timer = 100; // 100 x 10ms time for low batt before power off 00621 00622 if(lowbatt_timer == 0) 00623 { 00624 #ifdef HW_REV_A 00625 // Power OFF device 00626 POWERON_PORT |= _BV(POWERON); 00627 #else 00628 // Power OFF device 00629 POWERON_PORT &=~ _BV(POWERON); 00630 #endif 00631 while(1); 00632 } 00633 00634 // check if a key was pressed earlier 00635 if (key_press) { 00636 // check if key has been realesed 00637 if (bit_is_set (PROGKEY_PIN, PROGKEY)) { 00638 // key is released 00639 if ((key_delay > 0) && (key_delay < 800)) { // max 0.8 sec for shortpress 00640 LEDPORT &=~ _BV(LED); // turn LED off in any case 00641 POWERCTL1_PORT &=~ _BV(POWERCTL1); // turn VCOs off 00642 POWERCTL2_PORT &=~ _BV(POWERCTL2); // will be turned on dependent on next program 00643 eeprom_write_byte(&curr_program, programnum+1); 00644 goto run_prog; 00645 } 00646 key_press = 0; 00647 } 00648 else if ((key_delay > 800) && (key_delay < 5000)) { // long keypress ? 00649 power_off(); 00650 } 00651 } 00652 else { 00653 // check if key is pressed 00654 if (bit_is_clear (PROGKEY_PIN, PROGKEY)) { 00655 key_delay = 0; // reset key press timer 00656 key_press = 1; 00657 } 00658 } 00659 00660 /* Indicate selected program with blinking LED 00661 * 00662 * LED will blink program number of times followed by 1s pause 00663 */ 00664 if( led_delay == 0) { 00665 if( led_count == 0) { 00666 led_count = programnum+1; 00667 led_delay = 1000; 00668 } 00669 else { 00670 if(bit_is_clear(LEDPORT,LED)) { 00671 LEDPORT |= _BV(LED); 00672 if(led_count == 0) { 00673 led_delay = 1000; 00674 } 00675 else { 00676 led_delay = 100; 00677 } 00678 } 00679 else { 00680 LEDPORT &=~ _BV(LED); 00681 led_delay = 300; 00682 --led_count; 00683 } 00684 } 00685 } 00686 00687 } // end for(;;) 00688 00689 return 0; 00690 } 00691 00692 00699 ISR(TIMER0_COMPA_vect) 00700 { 00701 if (global_delay > 0) --global_delay; 00702 if (led_delay > 0) --led_delay; 00703 if (lowbatt_timer > 0) --lowbatt_timer; 00704 key_delay++; 00705 }