/** * \brief This will display the temperature in degrees F or C. */ void menu_display_temp(void) { int16_t result = temp_get(temp_mode); /* Display the temp result on the lower 4 digit display with the proper symbol. */ if(temp_mode == TEMP_UNIT_CELCIUS){ lcd_symbol_clr(LCD_SYMBOL_F); lcd_symbol_set(LCD_SYMBOL_C); } else{ lcd_symbol_clr(LCD_SYMBOL_C); lcd_symbol_set(LCD_SYMBOL_F); } /* Check for the DEBUG JTAG enable bit and display a CAUTION symbol to the user. */ /* CAUTION represents false value. */ if(MCUCR & 0x80){ lcd_symbol_clr(LCD_SYMBOL_ATT); } else{ lcd_symbol_set(LCD_SYMBOL_ATT); } lcd_num_putdec(result, LCD_NUM_PADDING_SPACE); }
/** * \brief This is main... */ int main(void) { lcd_init(); key_init(); uart_init(); eeprom_init(); temp_init(); timer_init(); sei(); lcd_symbol_set(LCD_SYMBOL_RAVEN); //lcd_symbol_set(LCD_SYMBOL_IP); timer_start(); for (;;){ /* Make sure interrupts are always on */ sei(); /* Process any progress frames */ uart_serial_rcv_frame(false); } /* end for(). */ } /* end main(). */
/*========================= IMPLEMENTATION =========================*/ void int_evt_startup(void* evt) { rvn_loc_cmd_std_t cmd; uint32_t blcc; switch (avrraven.status.state) { case STATE_STARTUP: /* Restart ATmega1284 application program. If in bootloader mode, start * Application program. If command disappears (during ATmega1284 startup etc.) * this application will react on the application startup event sent by * ATmega1284. */ cmd.id = RVN_LOC_CMD_ENTER_BOOT; sipc_send_frame(sizeof(rvn_loc_cmd_std_t), (uint8_t *)&cmd); // Put init symbols lcd_symbol_set(LCD_SYMBOL_RAVEN); lcd_symbol_clr(LCD_SYMBOL_RX); lcd_symbol_clr(LCD_SYMBOL_TX); lcd_symbol_antenna_signal(LCD_SYMBOL_ANTENNA_DIS); avrraven.status.ntwk_address = NTWK_ADDRESS_INVALID; // led_status_set(LED_OFF); // lcd_puts_P("WAIT FOR M1284 BOOT LOADER"); // If m1284 factory default fw should be loaded: BLCC_READ(blcc); if (blcc == BLCC_LOAD_FACTORY_DEFAULT) { avrraven.status.state = STATE_M1284P_ENTER_BOOT_WAIT_BOOT_EVENT; } else { avrraven.status.state = STATE_M1284P_RESTART_WAIT_BOOT_EVENT; } break; default: // Startupevent in any other state is ignored break; } }
/** * \brief This will start a sleep operation. * * \param val Used for remembering the new menu to display after a wakeup. */ void menu_run_sleep(uint8_t *val) { /* Turn off LED, LCD, ADC, Timer 1, SPI */ led_off(); lcd_deinit(); key_deinit(); PRR |= (1 << PRTIM1) | (1 << PRSPI); /* Tell the 1284P to turn off the radio and sleep */ sleep_count=0; uart_serial_send_frame(SEND_SLEEP, 1, (uint8_t *)&sleep_count); /* Turn off UART when transmission is complete */ while(!(UCSR0A & (1 << TXC0))); _delay_us(10000); //deinit trash clears done flag on 1284p uart_deinit(); /* Go to sleep until button is pushed */ sleep_now(0); /* Yawn, waking up, turn on LCD with Raven Logo */ lcd_init(); lcd_symbol_set(LCD_SYMBOL_RAVEN); /* Disable interrupts before powering everything up */ cli(); key_init(); PRR &= ~((1 << PRTIM1) | (1 << PRSPI)); uart_init(); /* Enable interrupts, Wake up 1284p and radio */ sei(); sleep_wakeup(); // uart_init();//flush receive buffer /* Wait for buttons up */ while (key_state_get() != KEY_NO_KEY) ; if (is_button()){ get_button(); } }
/** * \brief This will start a sleep with wakes for temperature measurement and web requests. * * \param val Used for remembering the new menu to display after a wakeup. */ void menu_run_doze(uint8_t *val) { /* Turn off LED, LCD */ led_off(); lcd_deinit(); /* Debounce */ while (key_state_get() != KEY_NO_KEY) ; /* Stay in doze loop until button is pressed*/ while (ENTER_PORT & (1<<ENTER_PIN)) { /* Tell 1284p to sleep for 4 seconds */ /* It will ignore the request if TCP/IP sessions are active */ /* Alter these timings as desired, or comment out to sleep only the 3290p */ sleep_count=4; uart_serial_send_frame(SEND_SLEEP, 1, (uint8_t *)&sleep_count); /* Wait for transmission complete, then sleep 3290p for 5 seconds */ while(!(UCSR0A & (1 << TXC0))); // uart_deinit(); sleep_now(sleep_count+1); // uart_init(); /* 1284p should be awake by now, update temperature and give it time to process */ menu_send_temp(); _delay_us(20000); } /* Wake LCD, turn on Raven logo */ lcd_init(); lcd_symbol_set(LCD_SYMBOL_RAVEN); sleep_wakeup(); /* Wait for buttons up */ while (key_state_get() != KEY_NO_KEY) ; if (is_button()){ get_button(); } }
/*========================= IMPLEMENTATION =========================*/ void loc_rsp_ok(void* rsp) { rvn_loc_cmd_get_param_t cmd_get_param; rvn_loc_cmd_std_t cmd; uint32_t blcc; FMENU_item_flash_t* current_menu_entry = FMENU_GetCurrentItem(&MENU_menuHandle); SIPC_ACK_PACKET(); switch (avrraven.status.state) { /*======================== FW write ========================*/ case STATE_FW_WRITE_INIT: lcd_puts_P("RECEIVING FW IMAGE"); avrraven.status.state = STATE_FW_WRITE; break; case STATE_FW_WRITE_INIT_WAIT_RX_ENABLE_RESPONSE: avrraven.status.state = STATE_FW_WRITE; break; case STATE_FW_WRITE_COMPLETE_WAIT_RX_ENABLE_RESPONSE: lcd_puts_P("DONE"); avrraven.status.state = STATE_DISPLAY_MESSAGE; break; case STATE_OTA_TRANS_WAITING_FOR_RX_ENABLE_RESPONSE: avrraven.status.state = STATE_IDLE; break; case STATE_FW_WRITE_WAIT_RX_ENABLE_RESPONSE: avrraven.status.state = STATE_FW_WRITE; break; case STATE_FW_WRITE_WAIT_TX_DONE: avrraven.status.state = STATE_FW_WRITE; break; case STATE_FW_WRITE_COMPLETE_WAIT_TX_DONE: lcd_puts_P("DONE"); avrraven.status.state = STATE_DISPLAY_MESSAGE; break; case STATE_FW_WRITE_IMAGE: // Set ATmega1284p in boot loader mode led_status_set(LED_FAST_BLINK); lcd_puts_P("WRITING M1284 IMAGE"); cmd.id = RVN_LOC_CMD_ENTER_BOOT; sipc_send_frame(sizeof(cmd), (uint8_t *)&cmd); avrraven.status.state = STATE_M1284P_UPGRADE_INIT_WAIT_RESPOND; break; case STATE_FW_WRITE_COMPLETE_WAIT_RADIO: lcd_symbol_set(LCD_SYMBOL_ZLINK); lcd_symbol_set(LCD_SYMBOL_ZIGBEE); lcd_symbol_antenna_signal(LCD_SYMBOL_ANTENNA_SIG_3); cmd.id = RVN_LOC_CMD_RX_ON; sipc_send_frame(sizeof(cmd), (uint8_t *)&cmd); avrraven.status.state = STATE_FW_WRITTEN_WAIT_RX_ENABLE_RESPONSE; break; case STATE_FW_WRITTEN_WAIT_RX_ENABLE_RESPONSE: lcd_puts_P("FW WRITTEN SUCCESSFULLY"); ota_event(RVN_OTA_EVT_FW_WRITE_DONE, 0x0000); BLCC_WRITE(BLCC_NORMAL_APP_START); avrraven.status.state = STATE_DISPLAY_MESSAGE; break; case STATE_FW_WRITE: break; /*======================== Radio ========================*/ case STATE_RADIO_CONNECTING: lcd_symbol_set(LCD_SYMBOL_ZLINK); lcd_symbol_set(LCD_SYMBOL_ZIGBEE); lcd_symbol_antenna_signal(LCD_SYMBOL_ANTENNA_SIG_3); cmd.id = RVN_LOC_CMD_RX_ON; sipc_send_frame(sizeof(cmd), (uint8_t *)&cmd); avrraven.status.state = STATE_RADIO_WAIT_FOR_RX_ENABLE_RESPONSE; break; case STATE_RADIO_DISCONNECTING: lcd_symbol_clr(LCD_SYMBOL_ZLINK); lcd_symbol_clr(LCD_SYMBOL_ZIGBEE); lcd_symbol_clr(LCD_SYMBOL_RX); lcd_symbol_clr(LCD_SYMBOL_TX); lcd_symbol_antenna_signal(LCD_SYMBOL_ANTENNA_DIS); lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); lcd_num_clr_all(); avrraven.status.ntwk_address = NTWK_ADDRESS_INVALID; avrraven.status.state = STATE_IDLE; break; case STATE_RADIO_WAIT_FOR_RX_ENABLE_RESPONSE: case STATE_RADIO_WAIT_FOR_RX_REENABLE_RESPONSE: // Get short address cmd_get_param.id = RVN_LOC_CMD_GET_PARAM; cmd_get_param.param = NWK_ADDRESS; sipc_send_frame(sizeof(rvn_loc_cmd_get_param_t), (uint8_t *)&cmd_get_param); avrraven.status.state = STATE_RADIO_GET_ADDRESS_WAIT_RESPONSE; break; /*======================== ATmega1284p ========================*/ case STATE_M1284P_UPGRADE_INIT_WAIT_RESPOND: /*Does nothing. Waiting for enter bootloader event*/ break; case STATE_M1284P_UPGRADE_PACKET_WAIT_RESPOND: send_m1284p_fw_packet(avrraven.status.m1284p_img_offset, avrraven.status.m1284p_address_offset, m1284p_fw_packet); lcd_num_putdec((int)(avrraven.status.m1284p_address_offset/1024), LCD_NUM_PADDING_SPACE); if ((avrraven.status.m1284p_address_offset += RVN_FW_PACKET_SIZE) == M1284P_APP_FLASH_SIZE) { vrt_mem_free((void *)(m1284p_fw_packet)); lcd_puts_P("DONE"); avrraven.status.state = STATE_M1284P_UPGRADE_DONE_WAIT_RESPOND; } else { /* stay in same avrraven.status.state and wait for response on the FW packet*/ } break; case STATE_M1284P_UPGRADE_DONE_WAIT_RESPOND: // Start ATmega1284's new FW cmd.id = RVN_LOC_CMD_APP_START; sipc_send_frame(sizeof(cmd), (uint8_t *)&cmd); // If m1284 factory default fw loaded, m3290 fw allready upgraded, and BLCC_READ(blcc); if (blcc == BLCC_LOAD_FACTORY_DEFAULT) { BLCC_WRITE(BLCC_FW_UPGRADE_COMPLETE); reboot(); } else { // Start own bootloader without waitig for 1284 to reboot BLCC_WRITE(BLCC_FW_UPGRADE_START_REQUEST_FROM_APP); reboot(); } break; case STATE_M1284P_NEW_FW_WAIT_EVENT: /*Does nothing. Waiting for app prog start event*/ break; case STATE_M1284P_RESTART_WAIT_BOOT_EVENT: case STATE_M1284P_ENTER_BOOT_WAIT_BOOT_EVENT: /*Does nothing. Waiting for boot loader start event*/ break; case STATE_M1284P_RESTART_WAIT_APP_EVENT: /*Does nothing. Waiting for app prog start event*/ break; case STATE_M1284P_DISCONNECT_WAIT_RESPOND: // Set ATmega1284p in boot loader mode led_status_set(LED_FAST_BLINK); lcd_puts_P("WRITING 1284P FW"); cmd.id = RVN_LOC_CMD_ENTER_BOOT; sipc_send_frame(sizeof(cmd), (uint8_t *)&cmd); avrraven.status.state = STATE_M1284P_UPGRADE_INIT_WAIT_RESPOND; break; /*======================== Misc ========================*/ case STATE_OTA_TRANSACTION_WAITING_FOR_RESPONSE: lcd_symbol_clr(LCD_SYMBOL_RX); // TIMED_FUNCTION lcd_symbol_set(LCD_SYMBOL_TX); // TIMED_FUNCTION cmd.id = RVN_LOC_CMD_RX_ON; sipc_send_frame(sizeof(cmd), (uint8_t *)&cmd); avrraven.status.state = STATE_OTA_TRANS_WAITING_FOR_RX_ENABLE_RESPONSE; break; case STATE_MAIL_SEND_INIT: lcd_puts_P("SENDING"); led_status_set(LED_SOFT_BLINK); avrraven.status.state = STATE_MAIL_SENDING; break; default: // OK responses in unknown state is ignored break; } }
void loc_evt_ota_packet(void *evt) { rvn_loc_evt_ota_packet_t* ota_packet = evt; // Get OTA packet header (Network layer) rvn_ota_transport_t* ota_transport = (rvn_ota_transport_t*)&ota_packet->data; // Get transport header uint8_t* app_data = (uint8_t*)&ota_transport->data; // Get application data packet uint8_t id = app_data[0]; // Get application packet id // Update radio symbols lcd_symbol_clr(LCD_SYMBOL_TX); // TIMED_FUNCTION lcd_symbol_set(LCD_SYMBOL_RX); // TIMED_FUNCTION lcd_symbol_antenna_signal(3); if (ota_packet->lqi<220) { lcd_symbol_clr(LCD_SYMBOL_ANT_SIG3); } if (ota_packet->lqi<200) { lcd_symbol_clr(LCD_SYMBOL_ANT_SIG2); } if (ota_packet->lqi<150) { lcd_symbol_clr(LCD_SYMBOL_ANT_SIG1); } // Execute OTA command handler switch (id) { case RVN_OTA_CMD_FW_WRITE_INIT: ota_cmd_fw_write_initiated(ota_packet); break; case RVN_OTA_CMD_FW_WRITE_PACKET: ota_cmd_fw_write_packet(ota_packet); break; case RVN_OTA_CMD_FW_WRITE_COMPLETED: ota_cmd_fw_write_completed(ota_packet); break; case RVN_OTA_CMD_FW_WRITE_IMAGE: ota_cmd_fw_write_image(ota_packet); break; case RVN_OTA_CMD_TXTMSG: ota_cmd_txtmsg(ota_packet); break; case RVN_OTA_CMD_SHARED_RD: ota_cmd_shared_rd(ota_packet); break; case RVN_OTA_CMD_GETNAME: ota_cmd_getname(ota_packet); break; case RVN_OTA_CMD_FOPEN: ota_cmd_fopen(ota_packet); break; case RVN_OTA_CMD_FCLOSE: ota_cmd_fclose(ota_packet); break; case RVN_OTA_CMD_FREAD: ota_cmd_fread(ota_packet); break; case RVN_OTA_CMD_FWRITE: ota_cmd_fwrite(ota_packet); break; case RVN_OTA_CMD_SIGN_ON: ota_cmd_sign_on(ota_packet); break; case RVN_OTA_RSP_OK: ota_rsp_ok(ota_packet); break; case RVN_OTA_RSP_ERROR: case RVN_OTA_RSP_BUSY: case RVN_OTA_RSP_NOT_SUPPORTED: ota_rsp_error(ota_packet); break; default:{ // ACK unknown sipc packet SIPC_ACK_PACKET(); // Respond not supported ota_simple_response(RVN_OTA_RSP_NOT_SUPPORTED, ota_packet->adr, ota_transport->seq_nmbr);} break; } }
void int_evt_key(void* evt) { key_state_t key_state = *(key_state_t*)evt; FMENU_item_flash_t* current_menu_entry = FMENU_GetCurrentItem(&MENU_menuHandle); FMENU_item_flash_t* new_menu_entry = current_menu_entry; menu_action_t menu_action = MENU_ACTION_ENTER; int int_temp; static uint8_t file_name[SFS_MAX_FILENAME_BUFFER_SIZE]; unsigned char search_string[SFS_MAX_FILENAME_BUFFER_SIZE]; lcd_config_t config; static key_state_t auto_key_state; static bool auto_key_wait = true; static bool auto_key_registered = false; static asy_tmr_t auto_key_timer = ASY_TMR_NO_TIMER; // Navigate to next avrraven.status.state switch (key_state){ case KEY_UP: switch (avrraven.status.state) { case STATE_IDLE: new_menu_entry = FMENU_NavigateUp(&MENU_menuHandle); break; case STATE_CONFIG_DEBUG_ENABLE: lcd_puts_P("ENABLE"); avrraven.user_config.debug_enable = true; break; case STATE_CONFIG_TXTPREV_ENABLE: lcd_puts_P("ENABLE"); avrraven.user_config.txtmsg_preview = true; break; case STATE_CONFIG_FW_UPGRADE: lcd_puts_P("AUTO"); avrraven.user_config.fw_upgr_auto = true; break; case STATE_CONFIG_CONNECT: lcd_puts_P("AUTO"); avrraven.user_config.join_auto = true; break; case STATE_CONFIG_IMG_RCV: lcd_puts_P("AUTO"); avrraven.user_config.fw_rcv_auto = true; break; case STATE_CONFIG_NAME: case STATE_MAIL_COMPOSE: txtedit_event(TXTEDIT_KEY_UP); break; case STATE_CONFIG_LCD_CONTRAST: lcd_num_putdec((int)numedit_event(NUMEDIT_KEY_UP), LCD_NUM_PADDING_SPACE); config = lcd_config_get(); config.contrast = numedit_buffer; lcd_config_set(config); break; case STATE_CONFIG_CLOCK_MIN: { timendate_clk_t set_time; timndate_clock_get(&set_time, avrraven.user_config.unit.clock); // hours from current clock int clk = set_time.hour*100 + numedit_event(NUMEDIT_KEY_UP); // minutes from current editing lcd_num_putdec(clk, LCD_NUM_PADDING_ZERO); } break; case STATE_CONFIG_CLOCK_HOUR: { timendate_clk_t set_time; timndate_clock_get(&set_time, avrraven.user_config.unit.clock); // minutes from current clock int clk = numedit_event(NUMEDIT_KEY_UP)*100 + set_time.min; // hours from current editing lcd_num_putdec(clk, LCD_NUM_PADDING_ZERO); } break; case STATE_CONFIG_LCD_SCROLLING: lcd_num_putdec((int)numedit_event(NUMEDIT_KEY_UP), LCD_NUM_PADDING_SPACE); // Update LCD scrolling settings config = lcd_config_get(); config.scrolling = (lcd_scrolling_t)numedit_value_get(); lcd_config_set(config); break; case STATE_CONFIG_RADIO_CHANNEL: lcd_num_putdec((int)numedit_event(NUMEDIT_KEY_UP), LCD_NUM_PADDING_SPACE); break; case STATE_CONFIG_RADIO_PANID: case STATE_MAIL_COMPOSE_ADDRESS_SET: lcd_num_puthex(numedit_event(NUMEDIT_KEY_UP), LCD_NUM_PADDING_ZERO); break; case STATE_CONFIG_UNIT_TEMP: avrraven.user_config.unit.temp = TEMP_UNIT_CELCIUS; lcd_symbol_clr(LCD_SYMBOL_F); lcd_symbol_set(LCD_SYMBOL_C); break; case STATE_CONFIG_UNIT_CLOCK: avrraven.user_config.unit.clock = TIME_CLOCK_UNIT_24; if (avrraven.user_config.unit.clock == TIME_CLOCK_UNIT_24) { lcd_symbol_clr(LCD_SYMBOL_AM); lcd_symbol_clr(LCD_SYMBOL_PM); lcd_num_puthex(0x2400, LCD_NUM_PADDING_ZERO); } else { lcd_symbol_set(LCD_SYMBOL_AM); lcd_symbol_set(LCD_SYMBOL_PM); lcd_num_puthex(0x1200, LCD_NUM_PADDING_ZERO); } break; case STATE_MAIL_READ: mbox_mail_get(¤t_mail, MBOX_GET_NEXT); if (current_mail != NULL) { int_temp = current_mail->size; lcd_puta(current_mail->data, int_temp); lcd_num_puthex(current_mail->address, LCD_NUM_PADDING_ZERO); } break; case STATE_FW_WAIT_USER_CONFIRMATION: lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); avrraven.status.state = STATE_IDLE; break; case STATE_AUDIO_FILE_SELECT: strncpy_P((char*)search_string, AUDIO_FILE_TYPE, AUDIO_FILE_TYPE_SIZE); if (avrraven.status.batt_low == false) { sfs_fget(search_string, file_name, SFS_FGET_REV); lcd_puts((const char*)file_name); } else { lcd_puts_P("ERROR"); } break; case STATE_STORAGE_FILE_LIST: strncpy_P((char*)search_string, "*.*", 4); if (avrraven.status.batt_low == false) { sfs_fget(search_string, file_name, SFS_FGET_REV); lcd_puts((const char*)file_name); } else { lcd_puts_P("ERROR"); } break; default: // Key events in unknown state is ignored break; } break; case KEY_DOWN: switch (avrraven.status.state) { case STATE_IDLE: new_menu_entry = FMENU_NavigateDown(&MENU_menuHandle); break; case STATE_CONFIG_DEBUG_ENABLE: lcd_puts_P("DISABLE"); avrraven.user_config.debug_enable = false; break; case STATE_CONFIG_TXTPREV_ENABLE: lcd_puts_P("DISABLE"); avrraven.user_config.txtmsg_preview = false; break; case STATE_CONFIG_FW_UPGRADE: lcd_puts_P("USR ACK"); avrraven.user_config.fw_rcv_auto = false; break; case STATE_CONFIG_CONNECT: lcd_puts_P("MANUAL"); avrraven.user_config.join_auto = false; break; case STATE_CONFIG_IMG_RCV: lcd_puts_P("USR ACK"); avrraven.user_config.fw_rcv_auto = false; break; case STATE_MAIL_COMPOSE: case STATE_CONFIG_NAME: txtedit_event(TXTEDIT_KEY_DOWN); break; case STATE_CONFIG_LCD_CONTRAST: lcd_num_putdec((int)numedit_event(NUMEDIT_KEY_DOWN), LCD_NUM_PADDING_SPACE); config = lcd_config_get(); config.contrast = numedit_buffer; lcd_config_set(config); break; case STATE_CONFIG_CLOCK_MIN: { timendate_clk_t set_time; timndate_clock_get(&set_time, avrraven.user_config.unit.clock); // hours from current clock int clk = set_time.hour*100 + numedit_event(NUMEDIT_KEY_DOWN); // minutes from current editing lcd_num_putdec(clk, LCD_NUM_PADDING_ZERO); } break; case STATE_CONFIG_CLOCK_HOUR: { timendate_clk_t set_time; timndate_clock_get(&set_time, avrraven.user_config.unit.clock); // minutes from current clock int clk = numedit_event(NUMEDIT_KEY_DOWN)*100 + set_time.min; // hours from current editing lcd_num_putdec(clk, LCD_NUM_PADDING_ZERO); } break; case STATE_CONFIG_LCD_SCROLLING: lcd_num_putdec((int)numedit_event(NUMEDIT_KEY_DOWN), LCD_NUM_PADDING_SPACE); // Update LCD scrolling settings config = lcd_config_get(); config.scrolling = (lcd_scrolling_t)numedit_value_get(); lcd_config_set(config); break; case STATE_CONFIG_RADIO_CHANNEL: lcd_num_putdec((int)numedit_event(NUMEDIT_KEY_DOWN), LCD_NUM_PADDING_SPACE); break; case STATE_CONFIG_RADIO_PANID: case STATE_MAIL_COMPOSE_ADDRESS_SET: lcd_num_puthex(numedit_event(NUMEDIT_KEY_DOWN), LCD_NUM_PADDING_ZERO); break; case STATE_CONFIG_UNIT_TEMP: avrraven.user_config.unit.temp = TEMP_UNIT_FAHRENHEIT; lcd_symbol_clr(LCD_SYMBOL_C); lcd_symbol_set(LCD_SYMBOL_F); break; case STATE_CONFIG_UNIT_CLOCK: avrraven.user_config.unit.clock = TIME_CLOCK_UNIT_12; if (avrraven.user_config.unit.clock == TIME_CLOCK_UNIT_24) { lcd_symbol_clr(LCD_SYMBOL_AM); lcd_symbol_clr(LCD_SYMBOL_PM); lcd_num_puthex(0x2400, LCD_NUM_PADDING_ZERO); } else { lcd_symbol_set(LCD_SYMBOL_AM); lcd_symbol_set(LCD_SYMBOL_PM); lcd_num_puthex(0x1200, LCD_NUM_PADDING_ZERO); } break; case STATE_MAIL_READ: mbox_mail_get(¤t_mail, MBOX_GET_PREV); if (current_mail != NULL) { int_temp = current_mail->size; lcd_puta(current_mail->data, int_temp); lcd_num_puthex(current_mail->address, LCD_NUM_PADDING_ZERO); } break; case STATE_FW_WAIT_USER_CONFIRMATION: lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); avrraven.status.state = STATE_IDLE; break; case STATE_AUDIO_FILE_SELECT: strncpy_P((char*)search_string, AUDIO_FILE_TYPE, AUDIO_FILE_TYPE_SIZE); if (avrraven.status.batt_low == false) { sfs_fget(search_string, file_name, SFS_FGET_FWD); lcd_puts((const char*)file_name); } else { lcd_puts_P("ERROR"); } break; case STATE_STORAGE_FILE_LIST: strncpy_P((char*)search_string, "*.*", 4); if (avrraven.status.batt_low == false) { sfs_fget(search_string, file_name, SFS_FGET_FWD); lcd_puts((const char*)file_name); } else { lcd_puts_P("ERROR"); } break; default: // Key events in unknown state is ignored break; } break; case KEY_LEFT: switch (avrraven.status.state) { case STATE_IDLE: new_menu_entry = FMENU_NavigateLeft(&MENU_menuHandle); break; case STATE_CONFIG_CLOCK_MIN: { // Set min timendate_clk_t new_time; timndate_clock_get(&new_time, avrraven.user_config.unit.clock); new_time.min = numedit_buffer; new_time.sec = 0; timndate_clock_set(new_time, avrraven.user_config.unit.clock); } // Done numeric editing on hours numedit_done(); // Start numeric editor on hours { timendate_clk_t current_time; timndate_clock_get(¤t_time, avrraven.user_config.unit.clock); numedit_buffer = current_time.hour; numedit_config_t conf = { .number = &numedit_buffer, .min_value = 0, .max_value = 23, .radix = NUMEDIT_RADIX_DEC, .size = 2, .offset = 2 }; numedit_init(conf); } avrraven.status.state = STATE_CONFIG_CLOCK_HOUR; break; case STATE_AUDIO_FILE_SELECT: if (audio_playback_active() == true) { audio_playback_stop(); } lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); avrraven.status.state = STATE_IDLE; break; case STATE_CONFIG_NAME: case STATE_MAIL_COMPOSE: txtedit_event(TXTEDIT_KEY_LEFT); break; case STATE_CONFIG_RADIO_PANID: case STATE_MAIL_COMPOSE_ADDRESS_SET: lcd_num_puthex(numedit_event(NUMEDIT_KEY_LEFT), LCD_NUM_PADDING_ZERO); break; case STATE_CONFIG_UNIT_TEMP: break; case STATE_CONFIG_UNIT_CLOCK: break; /* case STATE_MAIL_READ: mbox_mail_getnext(&txtmsg); if (txtmsg != NULL) { int_temp = ((txtmsg->size) < LCD_SEGMENT_COUNT) ? txtmsg->size : LCD_SEGMENT_COUNT; mail_read_offset = ((mail_read_offset + LCD_SEGMENT_COUNT) >= txtmsg->size) ? mail_read_offset : (mail_read_offset + LCD_SEGMENT_COUNT); lcd_puta(&txtmsg->data[mail_read_offset], int_temp); } break;*/ case STATE_FW_WAIT_USER_CONFIRMATION: lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); avrraven.status.state = STATE_IDLE; break; default: // Key events in unknown state is ignored break; } break; case KEY_RIGHT: switch (avrraven.status.state) { case STATE_IDLE: new_menu_entry = FMENU_NavigateRight(&MENU_menuHandle); break; case STATE_CONFIG_CLOCK_HOUR: { // Set hour timendate_clk_t new_time; timndate_clock_get(&new_time, avrraven.user_config.unit.clock); new_time.hour = numedit_buffer; new_time.sec = 0; timndate_clock_set(new_time, avrraven.user_config.unit.clock); } // Done numeric editing on hours numedit_done(); // Start numeric editor on minutes { timendate_clk_t current_time; timndate_clock_get(¤t_time, avrraven.user_config.unit.clock); numedit_buffer = current_time.min; numedit_config_t conf = { .number = &numedit_buffer, .min_value = 0, .max_value = 59, .radix = NUMEDIT_RADIX_DEC, .size = 2, .offset = 0 }; numedit_init(conf); } avrraven.status.state = STATE_CONFIG_CLOCK_MIN; break; case STATE_MAIL_COMPOSE: case STATE_CONFIG_NAME: txtedit_event(TXTEDIT_KEY_RIGHT); break; case STATE_CONFIG_RADIO_PANID: case STATE_MAIL_COMPOSE_ADDRESS_SET: lcd_num_puthex(numedit_event(NUMEDIT_KEY_RIGHT), LCD_NUM_PADDING_ZERO); break; case STATE_CONFIG_UNIT_TEMP: break; case STATE_CONFIG_UNIT_CLOCK: break; case STATE_FW_WAIT_USER_CONFIRMATION: lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); avrraven.status.state = STATE_IDLE; break; default: // Key events in unknown state is ignored break; } break; case KEY_ENTER: switch (avrraven.status.state) { case STATE_DISPLAY_MESSAGE: // Default display avrraven.status.state lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); led_status_set(LED_OFF); lcd_num_clr_all(); // Refresh menu function (in case it affects the display) menu_action = MENU_ACTION_REFRESH; if (current_menu_entry->action != NULL) { current_menu_entry->action((void*)&menu_action); } avrraven.status.state = STATE_IDLE; break; case STATE_CONFIG_LCD_CONTRAST: // Done numeric editing, write value to user configuration numedit_done(); avrraven.user_config.lcd.contrast = (lcd_contrast_t)numedit_buffer; // Update LCD HW config = lcd_config_get(); config.contrast = avrraven.user_config.lcd.contrast; lcd_config_set(config); // Write new user configuration to EEPROM USER_CONFIG_STORE(); // Refresh menu title lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); avrraven.status.state = STATE_IDLE; break; case STATE_CONFIG_LCD_SCROLLING: // Done numeric editing, write value to user configuration avrraven.user_config.lcd.scrolling = (lcd_scrolling_t)numedit_value_get(); numedit_done(); // Update LCD scrolling settings config = lcd_config_get(); config.scrolling = avrraven.user_config.lcd.scrolling; lcd_config_set(config); // Write new user configuration to EEPROM USER_CONFIG_STORE(); // Refresh menu title lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); avrraven.status.state = STATE_IDLE; break; case STATE_CONFIG_RADIO_CHANNEL: // Done numeric editing, write value to user configuration avrraven.user_config.channel = numedit_value_get(); numedit_done(); // Write new user configuration to EEPROM USER_CONFIG_STORE(); // Refresh menu title lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); avrraven.status.state = STATE_IDLE; break; case STATE_CONFIG_CLOCK_HOUR: { // Set hour timendate_clk_t new_time; timndate_clock_get(&new_time, avrraven.user_config.unit.clock); new_time.hour = numedit_value_get(); new_time.sec = 0; timndate_clock_set(new_time, avrraven.user_config.unit.clock); } // Done numeric editing on hours numedit_done(); // Start show clock event menu_action = MENU_ACTION_REFRESH; if (current_menu_entry->action != NULL) { current_menu_entry->action((void*)&menu_action); } avrraven.status.state = STATE_IDLE; break; case STATE_CONFIG_CLOCK_MIN: { // Set min timendate_clk_t new_time; timndate_clock_get(&new_time, avrraven.user_config.unit.clock); new_time.min = numedit_value_get(); new_time.sec = 0; timndate_clock_set(new_time, avrraven.user_config.unit.clock); } // Done numeric editing on minutes numedit_done(); // Start show clock event menu_action = MENU_ACTION_REFRESH; if (current_menu_entry->action != NULL) { current_menu_entry->action((void*)&menu_action); } avrraven.status.state = STATE_IDLE; break; case STATE_CONFIG_DEBUG_ENABLE: // Write new user configuration to EEPROM USER_CONFIG_STORE(); // Refresh menu title lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); avrraven.status.state = STATE_IDLE; break; case STATE_CONFIG_RADIO_PANID: // Done numeric editing on hours numedit_done(); // Write new user configuration to EEPROM USER_CONFIG_STORE(); // Refresh menu title lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); avrraven.status.state = STATE_IDLE; break; case STATE_CONFIG_UNIT_TEMP: case STATE_CONFIG_UNIT_CLOCK: case STATE_CONFIG_TXTPREV_ENABLE: case STATE_CONFIG_FW_UPGRADE: case STATE_CONFIG_CONNECT: case STATE_CONFIG_IMG_RCV: // Write new user configuration to EEPROM USER_CONFIG_STORE(); // Refresh menu title lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); avrraven.status.state = STATE_IDLE; break; case STATE_MAIL_PREVIEW: lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); menu_action = MENU_ACTION_REFRESH; if (current_menu_entry->action != NULL) { current_menu_entry->action((void*)&menu_action); } led_status_set(LED_OFF); avrraven.status.state = STATE_IDLE; break; case STATE_AUDIO_FILE_SELECT: if (audio_playback_active() == false) { audio_playback_start(file_name, false); } else { audio_playback_stop(); } break; case STATE_STORAGE_FILE_LIST: lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); avrraven.status.state = STATE_IDLE; break; case STATE_FW_WAIT_USER_CONFIRMATION: avrraven.status.state = STATE_FW_WRITE_INIT; break; case STATE_IDLE: lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); if (current_menu_entry->action != NULL) { current_menu_entry->action((void*)&menu_action); } break; case STATE_AUDIO_RECORD: audio_record_stop(); lcd_symbol_clr(LCD_SYMBOL_MIC); avrraven.status.state = STATE_IDLE; break; case STATE_CONFIG_NAME: txtedit_event(TXTEDIT_KEY_ENTER); txtedit_done(); USER_CONFIG_STORE(); // Print the menu title to the display lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); avrraven.status.state = STATE_IDLE; break; case STATE_MAIL_READ: lcd_puts_P((PROGMEM_DECLARE(const char)*)FMENU_GetTitle(current_menu_entry)); // If any unread mail, show closed envelope if (mbox_unread() == true) { lcd_symbol_set(LCD_SYMBOL_ENV_MAIN); lcd_symbol_set(LCD_SYMBOL_ENV_CL); lcd_symbol_clr(LCD_SYMBOL_ENV_OP); // If all mail read, show open envelope } else { lcd_symbol_set(LCD_SYMBOL_ENV_MAIN); lcd_symbol_set(LCD_SYMBOL_ENV_CL); lcd_symbol_set(LCD_SYMBOL_ENV_OP); } // show number of mails on display int_temp = mbox_mail_count_get(); lcd_num_putdec(int_temp, LCD_NUM_PADDING_SPACE); mbox_close(); avrraven.status.state = STATE_IDLE; break; case STATE_MAIL_COMPOSE: txtedit_event(TXTEDIT_KEY_ENTER); txtedit_done(); mbox_mail_buffer_put(new_mail_buffer); { lcd_puts_P("ADDRESS"); numedit_config_t conf = { .number = &numedit_buffer, .min_value = 0, .max_value = UINT16_MAX, .radix = NUMEDIT_RADIX_DEC, .size = 1, .offset = 0 }; numedit_init(conf); } numedit_buffer = 0x0000; // default address lcd_num_puthex(numedit_buffer, LCD_NUM_PADDING_ZERO); avrraven.status.state = STATE_MAIL_COMPOSE_ADDRESS_SET; break; case STATE_MAIL_COMPOSE_ADDRESS_SET: avrraven.status.trans_seq_nmbr = mbox_mail_send(numedit_value_get(), txtedit_size_get()); avrraven.status.state = STATE_MAIL_SEND_INIT; numedit_done(); mbox_close(); break; default: lcd_puts_P("CANCELED"); led_status_set(LED_FAST_BLINK); lcd_num_clr_all(); avrraven.status.state = STATE_DISPLAY_MESSAGE; break; } break; case KEY_NO_KEY: // Do nothing? break; default: // Key events in unknown state is ignored break; } // Navigate menu if new menu entry is different from last if (new_menu_entry != current_menu_entry) { navigate_menu(current_menu_entry, new_menu_entry, menu_action); } // After processing the key event it is safe to enable auto key auto_key_state = key_state; if (key_state != KEY_NO_KEY) { if (auto_key_registered == false) { long delay; if (auto_key_wait == true) { delay = 300; auto_key_wait = false; } else { asy_tmr_put(auto_key_timer); delay = 80; auto_key_registered = true; } auto_key_timer = asy_tmr_get(int_evt_key, (void*)&auto_key_state, delay); } } else { asy_tmr_put(auto_key_timer); auto_key_wait = true; auto_key_registered = false; } } void int_evt_check_key(void* evt) { static bool first_time = true; // Static variable used as flag to indicate first execution of function static key_state_t last_key_state; // Variable hodling last value of the joystick. Used to detect changes in joystick state /* Check joystick state. Post event if any change since last * First time function is executed no event is posted. This is * done to not respond if joystick activated while booting */ key_state_t new_key_state; if (first_time) { last_key_state = key_state_get(); new_key_state = last_key_state; first_time = false; } else if((new_key_state = key_state_get()) != last_key_state){ last_key_state = new_key_state; vrt_post_event(int_evt_key, (void*)&last_key_state); } } void int_evt_lcd_shift_left(void* evt) { lcd_text_shift_left(); } void int_evt_lcd_cursor_toggle(void* evt) { lcd_cursor_toggle(); } void int_evt_lcd_num_refresh(void* evt) { lcd_num_refresh(); } void int_evt_update_batt(void* evt) { int16_t vcc_batt = battery_voltage_read(); lcd_symbol_battery_empty(); if (vcc_batt>2000) { lcd_symbol_set(LCD_SYMBOL_BAT_CAP1); } if (vcc_batt>2500) { lcd_symbol_set(LCD_SYMBOL_BAT_CAP2); } if (vcc_batt>2800) { lcd_symbol_set(LCD_SYMBOL_BAT_CAP3); } // Indicate low battery if voltage less than 2.6 V if (avrraven.status.batt_low == false) { if (vcc_batt<2600) { avrraven.status.batt_low = true; lcd_symbol_set(LCD_SYMBOL_ATT); mbox_deinit(); sfs_deinit(); } } } void int_evt_show_clock(void* evt) { static bool col = false; timendate_clk_t clk; timndate_clock_get(&clk, avrraven.user_config.unit.clock); int16_t display_clock = clk.hour*100 + clk.min; lcd_num_putdec(display_clock, LCD_NUM_PADDING_ZERO); if ((col = !col) == true){ lcd_symbol_set(LCD_SYMBOL_COL); } else { lcd_symbol_clr(LCD_SYMBOL_COL); } } void int_evt_toggle_num_digit(void* evt) { int8_t digit_mask = *(int8_t*)evt; lcd_num_enable(digit_mask); } void int_evt_audio(void* evt) { audio_event_handler(); }
void main(void) { #else int main(void) { #endif uint32_t blcc; // Prevent optimizing of bootloader revision in progmem volatile uint16_t tmp2 = ATmega3290p_bl_rev; // Disable watchdog watchdog_disable(); // Configuring LCD with Extern clock (TOSC, 32.768kHz) // 32786 Hz 32786 Hz // frame_rate = ------------------ = ------------- = 32 Hz // 8 * .prescl * .div 8 * 16 * 8 // lcd_config_t lcd_config = LCD_DEFAULT_CONFIG; // Initialization if (true != avr_init()) { // Generic MCU initialization error_handler(); } else if (df_init() != 0) { // Data flash initialization error_handler(); } else if (lcd_init(lcd_config) != 0) { // Display error_handler(); } else if (led_init() != 0) { // Led error_handler(); } /* start timer 2*/ ASSR |= (1<<AS2); // Asynchronous operation TCCR2A &= ~((1<<CS22)|(1<<CS21)|(1<<CS20)); TCCR2A |= (1<<CS20); // Check shorting of "Factory default pins" uint8_t prr = PRR; PRR &= ~(1 << PRADC); DIDR1 &= ~((1 << AIN1D)|(1 << AIN0D)); PRR = prr; BOOT_DDR |= (1 << BOOT_TX); // Tx output BOOT_PORT &= ~(1 << BOOT_TX); // Tx low BOOT_DDR &= ~(1 << BOOT_RX); // Rx input BOOT_PORT |= (1 << BOOT_RX); // Rx pullup on if ((BOOT_PIN & (1 << BOOT_RX)) != (1 << BOOT_RX)) { // Rx pin low? /* Check that RX goes high when TX is pulled high. */ BOOT_PORT |= (1 << BOOT_TX); // Set Tx high nop(); nop(); nop(); nop(); if ((BOOT_PIN & (1 << BOOT_RX)) == (1 << BOOT_RX)) { // Rx high? intvecs_to_boot(); // move interrutp vectors to boot section, and start boot loader sei(); // Check supply voltage if (supply_voltage_read() < 2600) { lcd_puts("LOW BAT"); error_handler(); } BLCC_WRITE(BLCC_NORMAL_APP_START); // write communication channel in case abnormal exit of boot loader (power off etc.) lcd_symbol_set(LCD_SYMBOL_RAVEN); lcd_puts("WRITING"); led_status_set(LED_FAST_BLINK); do_fw_upgrade(M3290P_FLASH_FD_IMG_ADR); // Signal ATmega3290p application program that FW upgrade is complete // This makes the application program continue upgrade ATmega1284p after booting BLCC_WRITE(BLCC_LOAD_FACTORY_DEFAULT); app_start(); // start application program } } // Read bootloader communication channel in EEPROM and take proper action BLCC_READ(blcc); if (blcc == BLCC_FW_UPGRADE_START_REQUEST_FROM_APP) { intvecs_to_boot(); // move interrutp vectors to boot section, and start boot loader sei(); // Check supply voltage if (supply_voltage_read() < 2600) { lcd_puts("LOW BAT"); error_handler(); } BLCC_WRITE(BLCC_NORMAL_APP_START); // write communication channel in case abnormal exit of boot loader (power off etc.) lcd_symbol_set(LCD_SYMBOL_RAVEN); lcd_puts("WRITING"); led_status_set(LED_FAST_BLINK); do_fw_upgrade(M3290P_FLASH_USR_IMG_ADR); // Signal ATmega3290p application program that FW upgrade is complete BLCC_WRITE(BLCC_FW_UPGRADE_COMPLETE); reboot(); } else if (blcc == BLCC_FW_UPGRADE_COMPLETE) { BLCC_WRITE(BLCC_FW_UPGRADE_COMPLETE); sei(); app_start(); // start application program } else if (blcc == BLCC_RESTART_REQUEST_FROM_APP) { /* Start application program*/ BLCC_WRITE(BLCC_NORMAL_APP_START); sei(); app_start(); } else { /*else, start application program*/ BLCC_WRITE(BLCC_NORMAL_APP_START); sei(); app_start(); } }
/** * \brief This is main... */ int main(void) { lcd_init(); key_init(); uart_init(); eeprom_init(); temp_init(); timer_init(); sei(); lcd_symbol_set(LCD_SYMBOL_RAVEN); lcd_symbol_set(LCD_SYMBOL_IP); /* Start with main menu */ read_menu(0); /* and draw it */ lcd_puts_P(menu.text); timer_start(); for (;;){ /* Make sure interrupts are always on */ sei(); /* The one second timer has fired. */ if(timer_flag){ timer_flag = false; /* Check if main menu needs toggled. */ check_main_menu(); /* Update LCD with temp data. */ if(temp_flag){ menu_display_temp(); } /* Auto send temp data to 1284p. */ if(auto_temp){ menu_send_temp(); } /* If ping mode, send 4 ping requests and then stop. */ if(ping_mode){ if((PING_ATTEMPTS == count) && !timeout_flag){ count = 0; timeout_count = 0; menu_stop_ping(); } else if(timeout_flag){ timeout_flag = false; timeout_count++; /* Display timeout message if all PING_ATTEMPTS were not successful. */ if(PING_ATTEMPTS == timeout_count){ lcd_puts_P(PSTR("PINGS FAILED")); } } else{ count = menu_send_ping(); } } } /* Check for button press and deal with it */ if (is_button()){ /* Dispatch the button pressed */ switch (get_button()){ case KEY_UP: read_menu(menu.up); lcd_puts_P(menu.text); break; case KEY_DOWN: read_menu(menu.down); lcd_puts_P(menu.text); break; case KEY_LEFT: read_menu(menu.left); lcd_puts_P(menu.text); break; case KEY_RIGHT: /* * Check to see if we should show another menu or * run a function */ if (!menu.enter_func){ /* Just another menu to display */ read_menu(menu.right); lcd_puts_P(menu.text); break; } /* Drop through here */ case KEY_ENTER: /* Call the menu function on right or enter buttons */ if (menu.enter_func){ menu.enter_func(menu.state); if (menu.state){ /* * We just called a selection menu (not a test), * so re-display the text for this menu level */ lcd_puts_P(menu.text); } /* After enter key, check the right button menu and display. */ read_menu(menu.right); lcd_puts_P(menu.text); } break; default: break; } /* After button press, check for menus... */ check_menu(); } /* Process any progress frames */ uart_serial_rcv_frame(false); } /* end for(). */ } /* end main(). */