menu.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. /*
  2. * menu - mbr menuing system
  3. *
  4. * Copyright (c) 2009 Openmoko Inc.
  5. *
  6. * Authors Christopher Hall <hsw@openmoko.com>
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #define APPLICATION_TITLE "boot menu"
  22. #include <stdbool.h>
  23. #include <string.h>
  24. #include <samo.h>
  25. #include <lcd.h>
  26. #include <contrast.h>
  27. #include <analog.h>
  28. // redirect functions to mbr versions - see application.lds / mbr.c
  29. #define FLASH_read mbr_FLASH_read
  30. #define SPI_exchange mbr_SPI_exchange
  31. // this is to get constants, do not access any of its functions
  32. #include <FLASH.h>
  33. #include <SPI.h>
  34. #include "application.h"
  35. // enable this to have a small battery voltage indicator during boot
  36. #if !defined(BATTERY_METER)
  37. #define BATTERY_METER 1
  38. #endif
  39. #include "splash.h"
  40. #include "empty.h"
  41. #include "adjust.h"
  42. #define MAXIMUM_BLOCKS 7
  43. #define HEADER_MAGIC 0x4f4d4153
  44. #define MAXIMUM_APPS 8
  45. // allocate the very last sector for saving parameters
  46. #define PARAMETER_START (FLASH_TotalBytes - FLASH_SectorSize)
  47. #define PARAMETER_SIZE (FLASH_SectorSize)
  48. #define PARAMETER_MAGIC_1 0x5041524c
  49. #define PARAMETER_MAGIC_2 0x424c434b
  50. // the byte approximately just above the history key
  51. // to flag contrast has been changed
  52. #define ContrastChanged (((uint8_t *)LCD_VRAM)[LCD_VRAM_SIZE - 14])
  53. #define SetContrastChanged() do { ContrastChanged = 0xff; } while (0)
  54. #define ClearContrastChanged() do { ContrastChanged = 0x00; } while (0)
  55. // NameType length is defined in the awk script: GenerateApplicationHeader.awk
  56. typedef char NameType[32];
  57. struct {
  58. uint32_t magic;
  59. uint32_t count;
  60. NameType name[8];
  61. } header;
  62. typedef struct {
  63. int block;
  64. int offset;
  65. } ProcessReturnType;
  66. // the size of this must be an exact integer multiple of FLASH_PageSize
  67. // or programming FLASH will not work correctly
  68. // (There is some code below to cause a linker error if this is not true)
  69. typedef struct {
  70. uint32_t magic1;
  71. uint32_t magic2;
  72. uint32_t contrast;
  73. uint32_t spare_items[5];
  74. } ParameterType;
  75. // copied from drivers/src/FLASH.c
  76. typedef enum {
  77. FLASH_COMMAND_NoOperation = 0x00,
  78. FLASH_COMMAND_WriteStatus = 0x01,
  79. FLASH_COMMAND_PageProgram = 0x02,
  80. FLASH_COMMAND_ReadData = 0x03,
  81. FLASH_COMMAND_WriteDisable = 0x04,
  82. FLASH_COMMAND_ReadStatus = 0x05,
  83. FLASH_COMMAND_WriteEnable = 0x06,
  84. FLASH_COMMAND_FastRead = 0x0b,
  85. FLASH_COMMAND_SectorErase = 0x20,
  86. FLASH_COMMAND_ChipErase = 0xc7,
  87. } FLASH_CommandType;
  88. static void PrintName(const char *name, size_t size);
  89. static void DisplayInfo(void);
  90. static void SendCommand(uint8_t command);
  91. static void WaitReady(void);
  92. static void SendCommandWithAddress(uint8_t command, uint32_t ROMAddress);
  93. static void ProgramBlock(const void *buffer, size_t length, uint32_t ROMAddress);
  94. static void SectorErase(uint32_t ROMAddress);
  95. ProcessReturnType process(int block, int status);
  96. bool parameters_load(ParameterType *param);
  97. void parameters_save(ParameterType *param);
  98. void print_cpu_type(void);
  99. bool battery_empty(void);
  100. void battery_status(void);
  101. // this must be the first executable code as the loader executes from the first program address
  102. ReturnType menu(int block, int status)
  103. {
  104. ProcessReturnType result;
  105. APPLICATION_INITIALISE();
  106. LCD_initialise();
  107. Analog_initialise();
  108. {
  109. ParameterType param;
  110. Contrast_initialise();
  111. memset(&param, 0, sizeof(param));
  112. if (parameters_load(&param)) {
  113. Contrast_set(param.contrast);
  114. }
  115. }
  116. result = process(block, status);
  117. // If the structure ParameterType is not an exact multiple of FLASH_PageSize
  118. // then cause an error at link time.
  119. // this is the best that C can do since CPP cannot evaluate such an expression.
  120. // If typedef is correct compiler will not generate any code for this.
  121. if (((FLASH_PageSize / sizeof(ParameterType)) * sizeof(ParameterType)) != FLASH_PageSize) {
  122. void ParameterType_has_invalid_size__Fix_the_typedef(void);
  123. ParameterType_has_invalid_size__Fix_the_typedef(); // deliberate undefined reference
  124. }
  125. // next program
  126. APPLICATION_FINALISE(result.block, result.offset);
  127. }
  128. static void PrintName(const char *name, size_t size)
  129. {
  130. register int k;
  131. for (k = 0; k < size; ++k) {
  132. register char c = *name++;
  133. if ('\0' == c || '\xff' == c) {
  134. break;
  135. }
  136. print_char(c);
  137. }
  138. }
  139. static void DisplayInfo(void)
  140. {
  141. Analog_scan();
  142. print("\nCPU: ");
  143. print_cpu_type();
  144. print("\nRAM: ");
  145. print_uint(ram_size() >> 10);
  146. print("kB\nBAT: ");
  147. print_uint(Analog_BatteryMilliVolts());
  148. print(" mV\nTMP: ");
  149. print_int(Analog_TemperatureCelcius());
  150. print(" DegC\nLCD: ");
  151. print_uint(Analog_ContrastMilliVolts());
  152. print(" mV\nREV: ");
  153. uint32_t rev = board_revision();
  154. if (rev >= 5) {
  155. rev -= 4;
  156. print_char('V');
  157. } else {
  158. print_char('A');
  159. }
  160. print_uint(rev);
  161. print("\nMBR: ");
  162. FLASH_read(&rev, sizeof(rev), FLASH_RevisionNumberAddress);
  163. print_uint(0xffffffff == rev ? 0 : rev);
  164. char SerialNumber[FLASH_SerialNumberSize];
  165. FLASH_read(SerialNumber, sizeof(SerialNumber), FLASH_SerialNumberAddress);
  166. print("\nS/N: ");
  167. PrintName(SerialNumber, sizeof(SerialNumber));
  168. print("\n");
  169. }
  170. // process:
  171. // status == 0 => return from a program, therefore must display menu
  172. // != 0 => automatic boot, therefore check keys
  173. // run app[0] with status set to:
  174. // 0 if no keys pressed
  175. // 1,2 or 3 if any keys left, centre or right are pressed
  176. ProcessReturnType process(int block, int status)
  177. {
  178. ProcessReturnType rc = {0, 0};
  179. Analog_scan(); // update analog values
  180. if (battery_empty()) {
  181. LCD_DisplayImage(LCD_PositionCentre, true, &empty_image);
  182. } else {
  183. LCD_DisplayImage(LCD_PositionCentre, true, &splash_image);
  184. }
  185. if (0 != status) {
  186. bool MenuFlag = false;
  187. DisplayInfo();
  188. print("\n\nmenu? ");
  189. status = 0;
  190. static const char spinner[4] = "-\\|/";
  191. unsigned int i;
  192. for (i = 0; i < 4 * sizeof(spinner); ++i) {
  193. unsigned int k;
  194. for (k = 0; k < sizeof(spinner); ++k) {
  195. delay_us(5000);
  196. print_char(spinner[k]);
  197. print_char('\x08');
  198. battery_status();
  199. }
  200. if (console_input_available()) {
  201. MenuFlag = true;
  202. break;
  203. }
  204. k = REG_P6_P6D & 0x07;
  205. if (1 == k) { // right button
  206. status = 1;
  207. break;
  208. } else if (4 == k) { // centre button
  209. status = 2;
  210. break;
  211. } else if (2 == k) { // right button
  212. status = 3;
  213. break;
  214. } else if (0 != k) { // multiple buttons
  215. MenuFlag = true;
  216. break;
  217. }
  218. }
  219. print_char('\n');
  220. if (!MenuFlag) {
  221. rc.block = block + 1;
  222. rc.offset = status;
  223. return rc;
  224. }
  225. }
  226. LCD_DisplayImage(LCD_PositionBottom, false, &adjust_image);
  227. for (;;) {
  228. ProcessReturnType app[MAXIMUM_APPS * MAXIMUM_BLOCKS] = {{0, 0}};
  229. print("\nBoot Menu\n\n");
  230. print("0. Power Off\n");
  231. print("1. Board Information\n");
  232. int MenuItem = 0;
  233. // not zero since this program should be in block zero
  234. unsigned int i;
  235. for (i = 1; i < MAXIMUM_BLOCKS; ++i) {
  236. FLASH_read(&header, sizeof(header), (i << 13));
  237. if (HEADER_MAGIC == header.magic && 0 < header.count && MAXIMUM_APPS >= header.count) {
  238. unsigned int k;
  239. for (k = 0; k < header.count; ++k) {
  240. print_char(MenuItem + 'A');
  241. print(". ");
  242. PrintName(header.name[k], sizeof(header.name));
  243. print_char('\n');
  244. app[MenuItem].block = i;
  245. app[MenuItem].offset = k;
  246. ++MenuItem;
  247. }
  248. }
  249. }
  250. print("\nEnter selection: ");
  251. char k = ' ';
  252. while (k <= ' ') {
  253. while (!console_input_available()) {
  254. switch (REG_P6_P6D & 0x07) {
  255. case 1:
  256. Contrast_set(Contrast_get() + 1);
  257. SetContrastChanged();
  258. delay_us(3000);
  259. break;
  260. case 2:
  261. Contrast_set(Contrast_get() - 1);
  262. SetContrastChanged();
  263. delay_us(3000);
  264. break;
  265. case 4:
  266. // Contrast_set(Contrast_default);
  267. {
  268. ParameterType param;
  269. parameters_load(&param);
  270. param.contrast = Contrast_get();
  271. parameters_save(&param);
  272. ClearContrastChanged();
  273. }
  274. break;
  275. }
  276. battery_status();
  277. delay_us(1000);
  278. }
  279. k = console_input_char();
  280. }
  281. if ('0' == k) {
  282. power_off();
  283. } else if ('1' == k) {
  284. DisplayInfo();
  285. } else {
  286. if ('A' <= k && 'Z' >= k) {
  287. k += 'a' - 'A';
  288. }
  289. i = k - 'a';
  290. if (0 <= i && MAXIMUM_APPS * MAXIMUM_BLOCKS > i) {
  291. if (0 != app[i].block) {
  292. print_char(k);
  293. print_char('\n');
  294. rc = app[i];
  295. break;
  296. }
  297. }
  298. }
  299. }
  300. return rc;
  301. }
  302. bool parameters_load(ParameterType *param)
  303. {
  304. SDCARD_CS_HI();
  305. disable_card_power();
  306. EEPROM_CS_HI();
  307. EEPROM_WP_HI();
  308. unsigned int i;
  309. for (i = 0; i <= PARAMETER_SIZE - sizeof(*param); i += sizeof(*param)) {
  310. FLASH_read(param, sizeof(*param), PARAMETER_START + i);
  311. if (PARAMETER_MAGIC_1 == param->magic1 && PARAMETER_MAGIC_2 == param->magic2) {
  312. return true;
  313. }
  314. }
  315. return false;
  316. }
  317. void parameters_save(ParameterType *param)
  318. {
  319. SDCARD_CS_HI();
  320. disable_card_power();
  321. EEPROM_CS_HI();
  322. EEPROM_WP_HI();
  323. param->magic1 = PARAMETER_MAGIC_1;
  324. param->magic2 = PARAMETER_MAGIC_2;
  325. unsigned int i;
  326. ParameterType p;
  327. for (i = 0; i < PARAMETER_SIZE - sizeof(p); i += sizeof(p)) {
  328. FLASH_read(&p, sizeof(p), PARAMETER_START + i);
  329. if (PARAMETER_MAGIC_1 == p.magic1 && PARAMETER_MAGIC_2 == p.magic2) {
  330. if (0 == memcmp(param, &p, sizeof(p))) {
  331. return; // do not save the same value again
  332. } else {
  333. break;
  334. }
  335. }
  336. }
  337. bool erase = false;
  338. if (0 == i) {
  339. erase = true;
  340. } else {
  341. i -= sizeof(p);
  342. FLASH_read(&p, sizeof(p), PARAMETER_START + i);
  343. if (!(0xffffffff == p.magic1 && 0xffffffff == p.magic2)) {
  344. erase = true;
  345. }
  346. }
  347. if (erase) {
  348. SectorErase(PARAMETER_START);
  349. i = PARAMETER_SIZE - sizeof(p); // last available slot
  350. }
  351. ProgramBlock(param, sizeof(*param), PARAMETER_START + i);
  352. }
  353. static void SendCommand(uint8_t command)
  354. {
  355. delay_us(10);
  356. EEPROM_CS_LO();
  357. SPI_exchange(command);
  358. EEPROM_CS_HI();
  359. }
  360. static void WaitReady(void)
  361. {
  362. delay_us(10);
  363. EEPROM_CS_LO();
  364. SPI_exchange(FLASH_COMMAND_ReadStatus);
  365. while (0 != (SPI_exchange(FLASH_COMMAND_NoOperation) & 0x01)) {
  366. }
  367. EEPROM_CS_HI();
  368. }
  369. static void SendCommandWithAddress(uint8_t command, uint32_t ROMAddress)
  370. {
  371. WaitReady();
  372. SendCommand(FLASH_COMMAND_WriteEnable);
  373. EEPROM_CS_LO();
  374. SPI_exchange(command);
  375. SPI_exchange(ROMAddress >> 16); // A23..A16
  376. SPI_exchange(ROMAddress >> 8); // A15..A08
  377. SPI_exchange(ROMAddress); // A07..A00
  378. }
  379. static void ProgramBlock(const void *buffer, size_t length, uint32_t ROMAddress)
  380. {
  381. SendCommandWithAddress(FLASH_COMMAND_PageProgram, ROMAddress);
  382. size_t i;
  383. register uint8_t *bytes = (uint8_t *)buffer;
  384. for (i = 0; i < length; ++i) {
  385. SPI_exchange(*bytes++);
  386. }
  387. EEPROM_CS_HI();
  388. WaitReady();
  389. SendCommand(FLASH_COMMAND_WriteDisable);
  390. }
  391. static void SectorErase(uint32_t ROMAddress)
  392. {
  393. SendCommandWithAddress(FLASH_COMMAND_SectorErase, ROMAddress);
  394. EEPROM_CS_HI();
  395. WaitReady();
  396. }
  397. void print_cpu_type(void)
  398. {
  399. switch (CORE_ID) {
  400. case CORE_ID_STANDARD:
  401. print(CORE_ID_STANDARD_DESC);
  402. break;
  403. case CORE_ID_MINI:
  404. print(CORE_ID_MINI_DESC);
  405. break;
  406. case CORE_ID_ADVANCED:
  407. print(CORE_ID_ADVANCED_DESC);
  408. break;
  409. case CORE_ID_PE:
  410. print(CORE_ID_PE_DESC);
  411. break;
  412. case CORE_ID_PE_LE:
  413. print(CORE_ID_PE_LE_DESC);
  414. break;
  415. default:
  416. print_char('?');
  417. break;
  418. }
  419. print(" ");
  420. switch (PRODUCT_ID) {
  421. case PRODUCT_ID_3:
  422. print(PRODUCT_ID_3_DESC);
  423. break;
  424. case PRODUCT_ID_4:
  425. print(PRODUCT_ID_4_DESC);
  426. break;
  427. case PRODUCT_ID_3E:
  428. print(PRODUCT_ID_3E_DESC);
  429. break;
  430. case PRODUCT_ID_3L:
  431. print(PRODUCT_ID_3L_DESC);
  432. break;
  433. default:
  434. print_char('?');
  435. break;
  436. }
  437. print_byte(MODEL_ID);
  438. print(" V 0x");
  439. print_byte(VERSION_ID);
  440. }
  441. bool battery_empty(void)
  442. {
  443. Analog_scan();
  444. int v = Analog_BatteryMilliVolts();
  445. return v <= BATTERY_LOW;
  446. }
  447. void battery_status(void)
  448. {
  449. #if BATTERY_METER
  450. static bool initialised;
  451. uint8_t *fb = (uint8_t*)LCD_VRAM;
  452. static const char pos[] = {
  453. 0x03, 0x02, 0x02, 0x0e,
  454. 0x08, 0x08, 0x08, 0x08,
  455. 0x0e, 0x02, 0x02, 0x03,
  456. };
  457. static const char neg[] = {
  458. 0xff, 0xff, 0xfc
  459. };
  460. static const char body[] = {
  461. 0x00, 0x00, 0x04
  462. };
  463. register int i;
  464. register int j;
  465. register uint32_t indicator = 0;
  466. Analog_scan();
  467. int v = Analog_BatteryMilliVolts();
  468. if (v < BATTERY_EMPTY) {
  469. v = BATTERY_EMPTY;
  470. } else if (v > BATTERY_FULL) {
  471. v = BATTERY_FULL;
  472. }
  473. unsigned int full = 20 * (v - BATTERY_EMPTY) / (BATTERY_FULL - BATTERY_EMPTY);
  474. if (!initialised) {
  475. uint8_t *p = fb + 2 * LCD_VRAM_WIDTH_BYTES;
  476. initialised = true;
  477. for (i = 0; i < sizeof(pos); ++i) {
  478. p[0] = pos[i];
  479. if (0 == i || sizeof(pos) - 1 == i) {
  480. for (j = 0; j < sizeof(neg); ++j) {
  481. p[j + 1] = neg[j];
  482. }
  483. } else {
  484. for (j = 0; j < sizeof(body); ++j) {
  485. p[j + 1] = body[j];
  486. }
  487. }
  488. p += LCD_VRAM_WIDTH_BYTES;
  489. }
  490. }
  491. for (i = 0; i < full; ++i) {
  492. indicator |= 0x10 << i;
  493. }
  494. fb += 4 * LCD_VRAM_WIDTH_BYTES;
  495. for (i = 0; i < 8; ++i) {
  496. fb[1] = indicator >> 16;
  497. fb[2] = indicator >> 8;
  498. fb[3] = (indicator >> 0) | 0x04;
  499. fb += LCD_VRAM_WIDTH_BYTES;
  500. }
  501. #endif
  502. }