123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- /*
- * menu - mbr menuing system
- *
- * Copyright (c) 2009 Openmoko Inc.
- *
- * Authors Christopher Hall <hsw@openmoko.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #define APPLICATION_TITLE "boot menu"
- #include <stdbool.h>
- #include <string.h>
- #include <samo.h>
- #include <lcd.h>
- #include <contrast.h>
- #include <analog.h>
- // redirect functions to mbr versions - see application.lds / mbr.c
- #define FLASH_read mbr_FLASH_read
- #define SPI_exchange mbr_SPI_exchange
- // this is to get constants, do not access any of its functions
- #include <FLASH.h>
- #include <SPI.h>
- #include "application.h"
- // enable this to have a small battery voltage indicator during boot
- #if !defined(BATTERY_METER)
- #define BATTERY_METER 1
- #endif
- #include "splash.h"
- #include "empty.h"
- #include "adjust.h"
- #define MAXIMUM_BLOCKS 7
- #define HEADER_MAGIC 0x4f4d4153
- #define MAXIMUM_APPS 8
- // allocate the very last sector for saving parameters
- #define PARAMETER_START (FLASH_TotalBytes - FLASH_SectorSize)
- #define PARAMETER_SIZE (FLASH_SectorSize)
- #define PARAMETER_MAGIC_1 0x5041524c
- #define PARAMETER_MAGIC_2 0x424c434b
- // the byte approximately just above the history key
- // to flag contrast has been changed
- #define ContrastChanged (((uint8_t *)LCD_VRAM)[LCD_VRAM_SIZE - 14])
- #define SetContrastChanged() do { ContrastChanged = 0xff; } while (0)
- #define ClearContrastChanged() do { ContrastChanged = 0x00; } while (0)
- // NameType length is defined in the awk script: GenerateApplicationHeader.awk
- typedef char NameType[32];
- struct {
- uint32_t magic;
- uint32_t count;
- NameType name[8];
- } header;
- typedef struct {
- int block;
- int offset;
- } ProcessReturnType;
- // the size of this must be an exact integer multiple of FLASH_PageSize
- // or programming FLASH will not work correctly
- // (There is some code below to cause a linker error if this is not true)
- typedef struct {
- uint32_t magic1;
- uint32_t magic2;
- uint32_t contrast;
- uint32_t spare_items[5];
- } ParameterType;
- // copied from drivers/src/FLASH.c
- typedef enum {
- FLASH_COMMAND_NoOperation = 0x00,
- FLASH_COMMAND_WriteStatus = 0x01,
- FLASH_COMMAND_PageProgram = 0x02,
- FLASH_COMMAND_ReadData = 0x03,
- FLASH_COMMAND_WriteDisable = 0x04,
- FLASH_COMMAND_ReadStatus = 0x05,
- FLASH_COMMAND_WriteEnable = 0x06,
- FLASH_COMMAND_FastRead = 0x0b,
- FLASH_COMMAND_SectorErase = 0x20,
- FLASH_COMMAND_ChipErase = 0xc7,
- } FLASH_CommandType;
- static void PrintName(const char *name, size_t size);
- static void DisplayInfo(void);
- static void SendCommand(uint8_t command);
- static void WaitReady(void);
- static void SendCommandWithAddress(uint8_t command, uint32_t ROMAddress);
- static void ProgramBlock(const void *buffer, size_t length, uint32_t ROMAddress);
- static void SectorErase(uint32_t ROMAddress);
- ProcessReturnType process(int block, int status);
- bool parameters_load(ParameterType *param);
- void parameters_save(ParameterType *param);
- void print_cpu_type(void);
- bool battery_empty(void);
- void battery_status(void);
- // this must be the first executable code as the loader executes from the first program address
- ReturnType menu(int block, int status)
- {
- ProcessReturnType result;
- APPLICATION_INITIALISE();
- LCD_initialise();
- Analog_initialise();
- {
- ParameterType param;
- Contrast_initialise();
- memset(¶m, 0, sizeof(param));
- if (parameters_load(¶m)) {
- Contrast_set(param.contrast);
- }
- }
- result = process(block, status);
- // If the structure ParameterType is not an exact multiple of FLASH_PageSize
- // then cause an error at link time.
- // this is the best that C can do since CPP cannot evaluate such an expression.
- // If typedef is correct compiler will not generate any code for this.
- if (((FLASH_PageSize / sizeof(ParameterType)) * sizeof(ParameterType)) != FLASH_PageSize) {
- void ParameterType_has_invalid_size__Fix_the_typedef(void);
- ParameterType_has_invalid_size__Fix_the_typedef(); // deliberate undefined reference
- }
- // next program
- APPLICATION_FINALISE(result.block, result.offset);
- }
- static void PrintName(const char *name, size_t size)
- {
- register int k;
- for (k = 0; k < size; ++k) {
- register char c = *name++;
- if ('\0' == c || '\xff' == c) {
- break;
- }
- print_char(c);
- }
- }
- static void DisplayInfo(void)
- {
- Analog_scan();
- print("\nCPU: ");
- print_cpu_type();
- print("\nRAM: ");
- print_uint(ram_size() >> 10);
- print("kB\nBAT: ");
- print_uint(Analog_BatteryMilliVolts());
- print(" mV\nTMP: ");
- print_int(Analog_TemperatureCelcius());
- print(" DegC\nLCD: ");
- print_uint(Analog_ContrastMilliVolts());
- print(" mV\nREV: ");
- uint32_t rev = board_revision();
- if (rev >= 5) {
- rev -= 4;
- print_char('V');
- } else {
- print_char('A');
- }
- print_uint(rev);
- print("\nMBR: ");
- FLASH_read(&rev, sizeof(rev), FLASH_RevisionNumberAddress);
- print_uint(0xffffffff == rev ? 0 : rev);
- char SerialNumber[FLASH_SerialNumberSize];
- FLASH_read(SerialNumber, sizeof(SerialNumber), FLASH_SerialNumberAddress);
- print("\nS/N: ");
- PrintName(SerialNumber, sizeof(SerialNumber));
- print("\n");
- }
- // process:
- // status == 0 => return from a program, therefore must display menu
- // != 0 => automatic boot, therefore check keys
- // run app[0] with status set to:
- // 0 if no keys pressed
- // 1,2 or 3 if any keys left, centre or right are pressed
- ProcessReturnType process(int block, int status)
- {
- ProcessReturnType rc = {0, 0};
- Analog_scan(); // update analog values
- if (battery_empty()) {
- LCD_DisplayImage(LCD_PositionCentre, true, &empty_image);
- } else {
- LCD_DisplayImage(LCD_PositionCentre, true, &splash_image);
- }
- if (0 != status) {
- bool MenuFlag = false;
- DisplayInfo();
- print("\n\nmenu? ");
- status = 0;
- static const char spinner[4] = "-\\|/";
- unsigned int i;
- for (i = 0; i < 4 * sizeof(spinner); ++i) {
- unsigned int k;
- for (k = 0; k < sizeof(spinner); ++k) {
- delay_us(5000);
- print_char(spinner[k]);
- print_char('\x08');
- battery_status();
- }
- if (console_input_available()) {
- MenuFlag = true;
- break;
- }
- k = REG_P6_P6D & 0x07;
- if (1 == k) { // right button
- status = 1;
- break;
- } else if (4 == k) { // centre button
- status = 2;
- break;
- } else if (2 == k) { // right button
- status = 3;
- break;
- } else if (0 != k) { // multiple buttons
- MenuFlag = true;
- break;
- }
- }
- print_char('\n');
- if (!MenuFlag) {
- rc.block = block + 1;
- rc.offset = status;
- return rc;
- }
- }
- LCD_DisplayImage(LCD_PositionBottom, false, &adjust_image);
- for (;;) {
- ProcessReturnType app[MAXIMUM_APPS * MAXIMUM_BLOCKS] = {{0, 0}};
- print("\nBoot Menu\n\n");
- print("0. Power Off\n");
- print("1. Board Information\n");
- int MenuItem = 0;
- // not zero since this program should be in block zero
- unsigned int i;
- for (i = 1; i < MAXIMUM_BLOCKS; ++i) {
- FLASH_read(&header, sizeof(header), (i << 13));
- if (HEADER_MAGIC == header.magic && 0 < header.count && MAXIMUM_APPS >= header.count) {
- unsigned int k;
- for (k = 0; k < header.count; ++k) {
- print_char(MenuItem + 'A');
- print(". ");
- PrintName(header.name[k], sizeof(header.name));
- print_char('\n');
- app[MenuItem].block = i;
- app[MenuItem].offset = k;
- ++MenuItem;
- }
- }
- }
- print("\nEnter selection: ");
- char k = ' ';
- while (k <= ' ') {
- while (!console_input_available()) {
- switch (REG_P6_P6D & 0x07) {
- case 1:
- Contrast_set(Contrast_get() + 1);
- SetContrastChanged();
- delay_us(3000);
- break;
- case 2:
- Contrast_set(Contrast_get() - 1);
- SetContrastChanged();
- delay_us(3000);
- break;
- case 4:
- // Contrast_set(Contrast_default);
- {
- ParameterType param;
- parameters_load(¶m);
- param.contrast = Contrast_get();
- parameters_save(¶m);
- ClearContrastChanged();
- }
- break;
- }
- battery_status();
- delay_us(1000);
- }
- k = console_input_char();
- }
- if ('0' == k) {
- power_off();
- } else if ('1' == k) {
- DisplayInfo();
- } else {
- if ('A' <= k && 'Z' >= k) {
- k += 'a' - 'A';
- }
- i = k - 'a';
- if (0 <= i && MAXIMUM_APPS * MAXIMUM_BLOCKS > i) {
- if (0 != app[i].block) {
- print_char(k);
- print_char('\n');
- rc = app[i];
- break;
- }
- }
- }
- }
- return rc;
- }
- bool parameters_load(ParameterType *param)
- {
- SDCARD_CS_HI();
- disable_card_power();
- EEPROM_CS_HI();
- EEPROM_WP_HI();
- unsigned int i;
- for (i = 0; i <= PARAMETER_SIZE - sizeof(*param); i += sizeof(*param)) {
- FLASH_read(param, sizeof(*param), PARAMETER_START + i);
- if (PARAMETER_MAGIC_1 == param->magic1 && PARAMETER_MAGIC_2 == param->magic2) {
- return true;
- }
- }
- return false;
- }
- void parameters_save(ParameterType *param)
- {
- SDCARD_CS_HI();
- disable_card_power();
- EEPROM_CS_HI();
- EEPROM_WP_HI();
- param->magic1 = PARAMETER_MAGIC_1;
- param->magic2 = PARAMETER_MAGIC_2;
- unsigned int i;
- ParameterType p;
- for (i = 0; i < PARAMETER_SIZE - sizeof(p); i += sizeof(p)) {
- FLASH_read(&p, sizeof(p), PARAMETER_START + i);
- if (PARAMETER_MAGIC_1 == p.magic1 && PARAMETER_MAGIC_2 == p.magic2) {
- if (0 == memcmp(param, &p, sizeof(p))) {
- return; // do not save the same value again
- } else {
- break;
- }
- }
- }
- bool erase = false;
- if (0 == i) {
- erase = true;
- } else {
- i -= sizeof(p);
- FLASH_read(&p, sizeof(p), PARAMETER_START + i);
- if (!(0xffffffff == p.magic1 && 0xffffffff == p.magic2)) {
- erase = true;
- }
- }
- if (erase) {
- SectorErase(PARAMETER_START);
- i = PARAMETER_SIZE - sizeof(p); // last available slot
- }
- ProgramBlock(param, sizeof(*param), PARAMETER_START + i);
- }
- static void SendCommand(uint8_t command)
- {
- delay_us(10);
- EEPROM_CS_LO();
- SPI_exchange(command);
- EEPROM_CS_HI();
- }
- static void WaitReady(void)
- {
- delay_us(10);
- EEPROM_CS_LO();
- SPI_exchange(FLASH_COMMAND_ReadStatus);
- while (0 != (SPI_exchange(FLASH_COMMAND_NoOperation) & 0x01)) {
- }
- EEPROM_CS_HI();
- }
- static void SendCommandWithAddress(uint8_t command, uint32_t ROMAddress)
- {
- WaitReady();
- SendCommand(FLASH_COMMAND_WriteEnable);
- EEPROM_CS_LO();
- SPI_exchange(command);
- SPI_exchange(ROMAddress >> 16); // A23..A16
- SPI_exchange(ROMAddress >> 8); // A15..A08
- SPI_exchange(ROMAddress); // A07..A00
- }
- static void ProgramBlock(const void *buffer, size_t length, uint32_t ROMAddress)
- {
- SendCommandWithAddress(FLASH_COMMAND_PageProgram, ROMAddress);
- size_t i;
- register uint8_t *bytes = (uint8_t *)buffer;
- for (i = 0; i < length; ++i) {
- SPI_exchange(*bytes++);
- }
- EEPROM_CS_HI();
- WaitReady();
- SendCommand(FLASH_COMMAND_WriteDisable);
- }
- static void SectorErase(uint32_t ROMAddress)
- {
- SendCommandWithAddress(FLASH_COMMAND_SectorErase, ROMAddress);
- EEPROM_CS_HI();
- WaitReady();
- }
- void print_cpu_type(void)
- {
- switch (CORE_ID) {
- case CORE_ID_STANDARD:
- print(CORE_ID_STANDARD_DESC);
- break;
- case CORE_ID_MINI:
- print(CORE_ID_MINI_DESC);
- break;
- case CORE_ID_ADVANCED:
- print(CORE_ID_ADVANCED_DESC);
- break;
- case CORE_ID_PE:
- print(CORE_ID_PE_DESC);
- break;
- case CORE_ID_PE_LE:
- print(CORE_ID_PE_LE_DESC);
- break;
- default:
- print_char('?');
- break;
- }
- print(" ");
- switch (PRODUCT_ID) {
- case PRODUCT_ID_3:
- print(PRODUCT_ID_3_DESC);
- break;
- case PRODUCT_ID_4:
- print(PRODUCT_ID_4_DESC);
- break;
- case PRODUCT_ID_3E:
- print(PRODUCT_ID_3E_DESC);
- break;
- case PRODUCT_ID_3L:
- print(PRODUCT_ID_3L_DESC);
- break;
- default:
- print_char('?');
- break;
- }
- print_byte(MODEL_ID);
- print(" V 0x");
- print_byte(VERSION_ID);
- }
- bool battery_empty(void)
- {
- Analog_scan();
- int v = Analog_BatteryMilliVolts();
- return v <= BATTERY_LOW;
- }
- void battery_status(void)
- {
- #if BATTERY_METER
- static bool initialised;
- uint8_t *fb = (uint8_t*)LCD_VRAM;
- static const char pos[] = {
- 0x03, 0x02, 0x02, 0x0e,
- 0x08, 0x08, 0x08, 0x08,
- 0x0e, 0x02, 0x02, 0x03,
- };
- static const char neg[] = {
- 0xff, 0xff, 0xfc
- };
- static const char body[] = {
- 0x00, 0x00, 0x04
- };
- register int i;
- register int j;
- register uint32_t indicator = 0;
- Analog_scan();
- int v = Analog_BatteryMilliVolts();
- if (v < BATTERY_EMPTY) {
- v = BATTERY_EMPTY;
- } else if (v > BATTERY_FULL) {
- v = BATTERY_FULL;
- }
- unsigned int full = 20 * (v - BATTERY_EMPTY) / (BATTERY_FULL - BATTERY_EMPTY);
- if (!initialised) {
- uint8_t *p = fb + 2 * LCD_VRAM_WIDTH_BYTES;
- initialised = true;
- for (i = 0; i < sizeof(pos); ++i) {
- p[0] = pos[i];
- if (0 == i || sizeof(pos) - 1 == i) {
- for (j = 0; j < sizeof(neg); ++j) {
- p[j + 1] = neg[j];
- }
- } else {
- for (j = 0; j < sizeof(body); ++j) {
- p[j + 1] = body[j];
- }
- }
- p += LCD_VRAM_WIDTH_BYTES;
- }
- }
- for (i = 0; i < full; ++i) {
- indicator |= 0x10 << i;
- }
- fb += 4 * LCD_VRAM_WIDTH_BYTES;
- for (i = 0; i < 8; ++i) {
- fb[1] = indicator >> 16;
- fb[2] = indicator >> 8;
- fb[3] = (indicator >> 0) | 0x04;
- fb += LCD_VRAM_WIDTH_BYTES;
- }
- #endif
- }
|