Wavebubble 2010 Firmware

main.c

Go to the documentation of this file.
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 }