circuitpython/stm/main.c
Damien George c5966128c7 Implement proper exception type hierarchy.
Each built-in exception is now a type, with base type BaseException.
C exceptions are created by passing a pointer to the exception type to
make an instance of.  When raising an exception from the VM, an
instance is created automatically if an exception type is raised (as
opposed to an exception instance).

Exception matching (RT_BINARY_OP_EXCEPTION_MATCH) is now proper.

Handling of parse error changed to match new exceptions.

mp_const_type renamed to mp_type_type for consistency.
2014-02-15 16:10:44 +00:00

944 lines
28 KiB
C

#include <stdio.h>
#include <string.h>
#include <stm32f4xx.h>
#include <stm32f4xx_rcc.h>
#include <stm32f4xx_syscfg.h>
#include <stm32f4xx_gpio.h>
#include <stm32f4xx_exti.h>
#include <stm32f4xx_tim.h>
#include <stm32f4xx_pwr.h>
#include <stm32f4xx_rtc.h>
#include <stm32f4xx_usart.h>
#include <stm32f4xx_rng.h>
#include <usbd_storage_msd.h>
#include <stm_misc.h>
#include "std.h"
#include "misc.h"
#include "ff.h"
#include "mpconfig.h"
#include "qstr.h"
#include "nlr.h"
#include "misc.h"
#include "lexer.h"
#include "lexerfatfs.h"
#include "parse.h"
#include "obj.h"
#include "parsehelper.h"
#include "compile.h"
#include "runtime0.h"
#include "runtime.h"
#include "repl.h"
#include "gc.h"
#include "gccollect.h"
#include "systick.h"
#include "pendsv.h"
#include "led.h"
#include "servo.h"
#include "lcd.h"
#include "storage.h"
#include "sdcard.h"
#include "mma.h"
#include "usart.h"
#include "usb.h"
#include "timer.h"
#include "audio.h"
#include "pybwlan.h"
#include "i2c.h"
#include "usrsw.h"
#include "adc.h"
#include "rtc.h"
#include "file.h"
int errno;
static FATFS fatfs0;
static FATFS fatfs1;
void flash_error(int n) {
for (int i = 0; i < n; i++) {
led_state(PYB_LED_R1, 1);
led_state(PYB_LED_R2, 0);
sys_tick_delay_ms(250);
led_state(PYB_LED_R1, 0);
led_state(PYB_LED_R2, 1);
sys_tick_delay_ms(250);
}
led_state(PYB_LED_R2, 0);
}
void __fatal_error(const char *msg) {
#if MICROPY_HW_HAS_LCD
lcd_print_strn("\nFATAL ERROR:\n", 14);
lcd_print_strn(msg, strlen(msg));
#endif
for (;;) {
flash_error(1);
}
}
static mp_obj_t pyb_config_source_dir = MP_OBJ_NULL;
static mp_obj_t pyb_config_main = MP_OBJ_NULL;
mp_obj_t pyb_source_dir(mp_obj_t source_dir) {
if (MP_OBJ_IS_STR(source_dir)) {
pyb_config_source_dir = source_dir;
}
return mp_const_none;
}
mp_obj_t pyb_main(mp_obj_t main) {
if (MP_OBJ_IS_STR(main)) {
pyb_config_main = main;
}
return mp_const_none;
}
// sync all file systems
mp_obj_t pyb_sync(void) {
storage_flush();
return mp_const_none;
}
mp_obj_t pyb_delay(mp_obj_t count) {
sys_tick_delay_ms(mp_obj_get_int(count));
return mp_const_none;
}
void fatality(void) {
led_state(PYB_LED_R1, 1);
led_state(PYB_LED_G1, 1);
led_state(PYB_LED_R2, 1);
led_state(PYB_LED_G2, 1);
}
static const char fresh_boot_py[] =
"# boot.py -- run on boot-up\n"
"# can run arbitrary Python, but best to keep it minimal\n"
"\n"
"pyb.source_dir('/src')\n"
"pyb.main('main.py')\n"
"#pyb.usb_usr('VCP')\n"
"#pyb.usb_msd(True, 'dual partition')\n"
"#pyb.flush_cache(False)\n"
"#pyb.error_log('error.txt')\n"
;
static const char fresh_main_py[] =
"# main.py -- put your code here!\n"
;
static const char *help_text =
"Welcome to Micro Python!\n\n"
"This is a *very* early version of Micro Python and has minimal functionality.\n\n"
"Specific commands for the board:\n"
" pyb.info() -- print some general information\n"
" pyb.gc() -- run the garbage collector\n"
" pyb.repl_info(<val>) -- enable/disable printing of info after each command\n"
" pyb.delay(<n>) -- wait for n milliseconds\n"
" pyb.Led(<n>) -- create Led object for LED n (n=1,2)\n"
" Led methods: on(), off()\n"
" pyb.Servo(<n>) -- create Servo object for servo n (n=1,2,3,4)\n"
" Servo methods: angle(<x>)\n"
" pyb.switch() -- return True/False if switch pressed or not\n"
" pyb.accel() -- get accelerometer values\n"
" pyb.rand() -- get a 16-bit random number\n"
" pyb.gpio(<port>) -- get port value (port='A4' for example)\n"
" pyb.gpio(<port>, <val>) -- set port value, True or False, 1 or 0\n"
" pyb.ADC(<port>) -- make an analog port object (port='C0' for example)\n"
" ADC methods: read()\n"
;
// get some help about available functions
static mp_obj_t pyb_help(void) {
printf("%s", help_text);
return mp_const_none;
}
// get lots of info about the board
static mp_obj_t pyb_info(void) {
// get and print unique id; 96 bits
{
byte *id = (byte*)0x1fff7a10;
printf("ID=%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x\n", id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], id[10], id[11]);
}
// get and print clock speeds
// SYSCLK=168MHz, HCLK=168MHz, PCLK1=42MHz, PCLK2=84MHz
{
RCC_ClocksTypeDef rcc_clocks;
RCC_GetClocksFreq(&rcc_clocks);
printf("S=%lu\nH=%lu\nP1=%lu\nP2=%lu\n", rcc_clocks.SYSCLK_Frequency, rcc_clocks.HCLK_Frequency, rcc_clocks.PCLK1_Frequency, rcc_clocks.PCLK2_Frequency);
}
// to print info about memory
{
printf("_text_end=%p\n", &_text_end);
printf("_data_start_init=%p\n", &_data_start_init);
printf("_data_start=%p\n", &_data_start);
printf("_data_end=%p\n", &_data_end);
printf("_bss_start=%p\n", &_bss_start);
printf("_bss_end=%p\n", &_bss_end);
printf("_stack_end=%p\n", &_stack_end);
printf("_ram_start=%p\n", &_ram_start);
printf("_heap_start=%p\n", &_heap_start);
printf("_heap_end=%p\n", &_heap_end);
printf("_ram_end=%p\n", &_ram_end);
}
// qstr info
{
uint n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
printf("qstr:\n n_pool=%u\n n_qstr=%u\n n_str_data_bytes=%u\n n_total_bytes=%u\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
}
// GC info
{
gc_info_t info;
gc_info(&info);
printf("GC:\n");
printf(" %lu total\n", info.total);
printf(" %lu : %lu\n", info.used, info.free);
printf(" 1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block);
}
// free space on flash
{
DWORD nclst;
FATFS *fatfs;
f_getfree("0:", &nclst, &fatfs);
printf("LFS free: %u bytes\n", (uint)(nclst * fatfs->csize * 512));
}
return mp_const_none;
}
static bool repl_display_debugging_info = 0;
static mp_obj_t pyb_set_repl_info(mp_obj_t o_value) {
repl_display_debugging_info = mp_obj_get_int(o_value);
return mp_const_none;
}
static void SYSCLKConfig_STOP(void) {
/* After wake-up from STOP reconfigure the system clock */
/* Enable HSE */
RCC_HSEConfig(RCC_HSE_ON);
/* Wait till HSE is ready */
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET) {
}
/* Enable PLL */
RCC_PLLCmd(ENABLE);
/* Wait till PLL is ready */
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {
}
/* Select PLL as system clock source */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Wait till PLL is used as system clock source */
while (RCC_GetSYSCLKSource() != 0x08) {
}
}
static mp_obj_t pyb_stop(void) {
PWR_EnterSTANDBYMode();
//PWR_FlashPowerDownCmd(ENABLE); don't know what the logic is with this
/* Enter Stop Mode */
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
/* Configures system clock after wake-up from STOP: enable HSE, PLL and select
* PLL as system clock source (HSE and PLL are disabled in STOP mode) */
SYSCLKConfig_STOP();
//PWR_FlashPowerDownCmd(DISABLE);
return mp_const_none;
}
static mp_obj_t pyb_standby(void) {
PWR_EnterSTANDBYMode();
return mp_const_none;
}
char *strdup(const char *str) {
uint32_t len = strlen(str);
char *s2 = m_new(char, len + 1);
memcpy(s2, str, len);
s2[len] = 0;
return s2;
}
#define READLINE_HIST_SIZE (8)
static const char *readline_hist[READLINE_HIST_SIZE] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
void stdout_tx_str(const char *str) {
if (pyb_usart_global_debug != PYB_USART_NONE) {
usart_tx_str(pyb_usart_global_debug, str);
}
#if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
lcd_print_str(str);
#endif
usb_vcp_send_str(str);
}
int readline(vstr_t *line, const char *prompt) {
stdout_tx_str(prompt);
int len = vstr_len(line);
int escape = 0;
int hist_num = 0;
for (;;) {
char c;
for (;;) {
#ifdef USE_HOST_MODE
pyb_usb_host_process();
c = pyb_usb_host_get_keyboard();
if (c != 0) {
break;
}
#endif
if (usb_vcp_rx_any() != 0) {
c = usb_vcp_rx_get();
break;
} else if (pyb_usart_global_debug != PYB_USART_NONE && usart_rx_any(pyb_usart_global_debug)) {
c = usart_rx_char(pyb_usart_global_debug);
break;
}
sys_tick_delay_ms(1);
if (storage_needs_flush()) {
storage_flush();
}
}
if (escape == 0) {
if (c == VCP_CHAR_CTRL_D && vstr_len(line) == len) {
return 0;
} else if (c == '\r') {
stdout_tx_str("\r\n");
for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) {
readline_hist[i] = readline_hist[i - 1];
}
readline_hist[0] = strdup(vstr_str(line));
return 1;
} else if (c == 27) {
escape = true;
} else if (c == 127) {
if (vstr_len(line) > len) {
vstr_cut_tail(line, 1);
stdout_tx_str("\b \b");
}
} else if (32 <= c && c <= 126) {
vstr_add_char(line, c);
stdout_tx_str(line->buf + line->len - 1);
}
} else if (escape == 1) {
if (c == '[') {
escape = 2;
} else {
escape = 0;
}
} else if (escape == 2) {
escape = 0;
if (c == 'A') {
// up arrow
if (hist_num < READLINE_HIST_SIZE && readline_hist[hist_num] != NULL) {
// erase line
for (int i = line->len - len; i > 0; i--) {
stdout_tx_str("\b \b");
}
// set line to history
line->len = len;
vstr_add_str(line, readline_hist[hist_num]);
// draw line
stdout_tx_str(readline_hist[hist_num]);
// increase hist num
hist_num += 1;
}
}
} else {
escape = 0;
}
sys_tick_delay_ms(10);
}
}
void do_repl(void) {
#if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
// in host mode, we enable the LCD for the repl
mp_obj_t lcd_o = rt_call_function_0(rt_load_name(qstr_from_str("LCD")));
rt_call_function_1(rt_load_attr(lcd_o, qstr_from_str("light")), mp_const_true);
#endif
stdout_tx_str("Micro Python build <git hash> on 25/1/2014; " MICROPY_HW_BOARD_NAME " with STM32F405RG\r\n");
stdout_tx_str("Type \"help()\" for more information.\r\n");
vstr_t line;
vstr_init(&line, 32);
for (;;) {
vstr_reset(&line);
int ret = readline(&line, ">>> ");
if (ret == 0) {
// EOF
break;
}
if (vstr_len(&line) == 0) {
continue;
}
if (mp_repl_is_compound_stmt(vstr_str(&line))) {
for (;;) {
vstr_add_char(&line, '\n');
int len = vstr_len(&line);
int ret = readline(&line, "... ");
if (ret == 0 || vstr_len(&line) == len) {
// done entering compound statement
break;
}
}
}
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0);
mp_parse_error_kind_t parse_error_kind;
mp_parse_node_t pn = mp_parse(lex, MP_PARSE_SINGLE_INPUT, &parse_error_kind);
qstr source_name = mp_lexer_source_name(lex);
if (pn == MP_PARSE_NODE_NULL) {
// parse error
mp_parse_show_exception(lex, parse_error_kind);
mp_lexer_free(lex);
} else {
// parse okay
mp_lexer_free(lex);
mp_obj_t module_fun = mp_compile(pn, source_name, true);
mp_parse_node_free(pn);
if (module_fun != mp_const_none) {
nlr_buf_t nlr;
uint32_t start = sys_tick_counter;
if (nlr_push(&nlr) == 0) {
usb_vcp_set_interrupt_char(VCP_CHAR_CTRL_C); // allow ctrl-C to interrupt us
rt_call_function_0(module_fun);
usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
nlr_pop();
} else {
// uncaught exception
// FIXME it could be that an interrupt happens just before we disable it here
usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
}
// display debugging info if wanted
if (repl_display_debugging_info) {
uint32_t ticks = sys_tick_counter - start; // TODO implement a function that does this properly
printf("took %lu ms\n", ticks);
gc_collect();
pyb_info();
}
}
}
}
stdout_tx_str("\r\n");
}
bool do_file(const char *filename) {
mp_lexer_t *lex = mp_lexer_new_from_file(filename);
if (lex == NULL) {
printf("could not open file '%s' for reading\n", filename);
return false;
}
mp_parse_error_kind_t parse_error_kind;
mp_parse_node_t pn = mp_parse(lex, MP_PARSE_FILE_INPUT, &parse_error_kind);
qstr source_name = mp_lexer_source_name(lex);
if (pn == MP_PARSE_NODE_NULL) {
// parse error
mp_parse_show_exception(lex, parse_error_kind);
mp_lexer_free(lex);
return false;
}
mp_lexer_free(lex);
mp_obj_t module_fun = mp_compile(pn, source_name, false);
mp_parse_node_free(pn);
if (module_fun == mp_const_none) {
return false;
}
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
usb_vcp_set_interrupt_char(VCP_CHAR_CTRL_C); // allow ctrl-C to interrupt us
rt_call_function_0(module_fun);
usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
nlr_pop();
return true;
} else {
// uncaught exception
// FIXME it could be that an interrupt happens just before we disable it here
usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
mp_obj_print_exception((mp_obj_t)nlr.ret_val);
return false;
}
}
mp_obj_t pyb_gpio(uint n_args, mp_obj_t *args) {
//assert(1 <= n_args && n_args <= 2);
const char *pin_name = mp_obj_str_get_str(args[0]);
GPIO_TypeDef *port;
switch (pin_name[0]) {
case 'A': case 'a': port = GPIOA; break;
case 'B': case 'b': port = GPIOB; break;
case 'C': case 'c': port = GPIOC; break;
default: goto pin_error;
}
uint pin_num = 0;
for (const char *s = pin_name + 1; *s; s++) {
if (!('0' <= *s && *s <= '9')) {
goto pin_error;
}
pin_num = 10 * pin_num + *s - '0';
}
if (!(0 <= pin_num && pin_num <= 15)) {
goto pin_error;
}
if (n_args == 1) {
// get pin
if ((port->IDR & (1 << pin_num)) != (uint32_t)Bit_RESET) {
return MP_OBJ_NEW_SMALL_INT(1);
} else {
return MP_OBJ_NEW_SMALL_INT(0);
}
} else {
// set pin
if (rt_is_true(args[1])) {
// set pin high
port->BSRRL = 1 << pin_num;
} else {
// set pin low
port->BSRRH = 1 << pin_num;
}
return mp_const_none;
}
pin_error:
nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s does not exist", pin_name));
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_gpio_obj, 1, 2, pyb_gpio);
mp_obj_t pyb_hid_send_report(mp_obj_t arg) {
mp_obj_t *items = mp_obj_get_array_fixed_n(arg, 4);
uint8_t data[4];
data[0] = mp_obj_get_int(items[0]);
data[1] = mp_obj_get_int(items[1]);
data[2] = mp_obj_get_int(items[2]);
data[3] = mp_obj_get_int(items[3]);
usb_hid_send_report(data);
return mp_const_none;
}
mp_obj_t pyb_rng_get(void) {
return mp_obj_new_int(RNG_GetRandomNumber() >> 16);
}
mp_obj_t pyb_millis(void) {
return mp_obj_new_int(sys_tick_counter);
}
int main(void) {
// TODO disable JTAG
// update the SystemCoreClock variable
SystemCoreClockUpdate();
// set interrupt priority config to use all 4 bits for pre-empting
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
// enable the CCM RAM and the GPIO's
RCC->AHB1ENR |= RCC_AHB1ENR_CCMDATARAMEN | RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIODEN;
#if MICROPY_HW_HAS_SDCARD
{
// configure SDIO pins to be high to start with (apparently makes it more robust)
// FIXME this is not making them high, it just makes them outputs...
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
// Configure PD.02 CMD line
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
#endif
#if defined(NETDUINO_PLUS_2)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
#if MICROPY_HW_HAS_SDCARD
// Turn on the power enable for the sdcard (PB1)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_SET);
#endif
// Turn on the power for the 5V on the expansion header (PB2)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_SET);
}
#endif
// basic sub-system init
sys_tick_init();
pendsv_init();
led_init();
#if MICROPY_HW_ENABLE_RTC
rtc_init();
#endif
// turn on LED to indicate bootup
led_state(PYB_LED_G1, 1);
// more sub-system init
#if MICROPY_HW_HAS_SWITCH
switch_init();
#endif
#if MICROPY_HW_HAS_SDCARD
sdcard_init();
#endif
storage_init();
// uncomment these 2 lines if you want REPL on USART_6 (or another usart) as well as on USB VCP
//pyb_usart_global_debug = PYB_USART_3;
//usart_init(pyb_usart_global_debug, 115200);
int first_soft_reset = true;
soft_reset:
// GC init
gc_init(&_heap_start, &_heap_end);
// Micro Python init
qstr_init();
rt_init();
#if MICROPY_HW_HAS_LCD
// LCD init (just creates class, init hardware by calling LCD())
lcd_init();
#endif
#if MICROPY_HW_ENABLE_SERVO
// servo
servo_init();
#endif
#if MICROPY_HW_ENABLE_AUDIO
// audio
audio_init();
#endif
#if MICROPY_HW_ENABLE_TIMER
// timer
timer_init();
#endif
#if MICROPY_HW_ENABLE_RNG
// RNG
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_RNG, ENABLE);
RNG_Cmd(ENABLE);
#endif
// add some functions to the python namespace
{
rt_store_name(MP_QSTR_help, rt_make_function_n(0, pyb_help));
mp_obj_t m = mp_obj_new_module(MP_QSTR_pyb);
rt_store_attr(m, MP_QSTR_info, rt_make_function_n(0, pyb_info));
rt_store_attr(m, MP_QSTR_gc, (mp_obj_t)&pyb_gc_obj);
rt_store_attr(m, qstr_from_str("repl_info"), rt_make_function_n(1, pyb_set_repl_info));
#if MICROPY_HW_HAS_SDCARD
rt_store_attr(m, qstr_from_str("SD"), (mp_obj_t)&pyb_sdcard_obj);
#endif
rt_store_attr(m, MP_QSTR_stop, rt_make_function_n(0, pyb_stop));
rt_store_attr(m, MP_QSTR_standby, rt_make_function_n(0, pyb_standby));
rt_store_attr(m, MP_QSTR_source_dir, rt_make_function_n(1, pyb_source_dir));
rt_store_attr(m, MP_QSTR_main, rt_make_function_n(1, pyb_main));
rt_store_attr(m, MP_QSTR_sync, rt_make_function_n(0, pyb_sync));
rt_store_attr(m, MP_QSTR_delay, rt_make_function_n(1, pyb_delay));
#if MICROPY_HW_HAS_SWITCH
rt_store_attr(m, MP_QSTR_switch, (mp_obj_t)&pyb_switch_obj);
#endif
#if MICROPY_HW_ENABLE_SERVO
rt_store_attr(m, MP_QSTR_servo, rt_make_function_n(2, pyb_servo_set));
#endif
rt_store_attr(m, MP_QSTR_pwm, rt_make_function_n(2, pyb_pwm_set));
#if MICROPY_HW_HAS_MMA7660
rt_store_attr(m, MP_QSTR_accel, (mp_obj_t)&pyb_mma_read_obj);
rt_store_attr(m, MP_QSTR_mma_read, (mp_obj_t)&pyb_mma_read_all_obj);
rt_store_attr(m, MP_QSTR_mma_mode, (mp_obj_t)&pyb_mma_write_mode_obj);
#endif
rt_store_attr(m, MP_QSTR_hid, rt_make_function_n(1, pyb_hid_send_report));
#if MICROPY_HW_ENABLE_RTC
rt_store_attr(m, MP_QSTR_time, rt_make_function_n(0, pyb_rtc_read));
#endif
#if MICROPY_HW_ENABLE_RNG
rt_store_attr(m, MP_QSTR_rand, rt_make_function_n(0, pyb_rng_get));
#endif
rt_store_attr(m, MP_QSTR_Led, (mp_obj_t)&pyb_Led_obj);
#if MICROPY_HW_ENABLE_SERVO
rt_store_attr(m, MP_QSTR_Servo, rt_make_function_n(1, pyb_Servo));
#endif
rt_store_attr(m, MP_QSTR_I2C, rt_make_function_n(2, pyb_I2C));
rt_store_attr(m, MP_QSTR_gpio, (mp_obj_t)&pyb_gpio_obj);
rt_store_attr(m, MP_QSTR_Usart, rt_make_function_n(2, pyb_Usart));
rt_store_attr(m, qstr_from_str("ADC_all"), (mp_obj_t)&pyb_ADC_all_obj);
rt_store_attr(m, MP_QSTR_ADC, (mp_obj_t)&pyb_ADC_obj);
rt_store_attr(m, qstr_from_str("millis"), rt_make_function_n(0, pyb_millis));
rt_store_name(MP_QSTR_pyb, m);
rt_store_name(MP_QSTR_open, rt_make_function_n(2, pyb_io_open));
}
// check if user switch held (initiates reset of filesystem)
bool reset_filesystem = false;
#if MICROPY_HW_HAS_SWITCH
if (switch_get()) {
reset_filesystem = true;
for (int i = 0; i < 50; i++) {
if (!switch_get()) {
reset_filesystem = false;
break;
}
sys_tick_delay_ms(10);
}
}
#endif
// local filesystem init
{
// try to mount the flash
FRESULT res = f_mount(&fatfs0, "0:", 1);
if (!reset_filesystem && res == FR_OK) {
// mount sucessful
} else if (reset_filesystem || res == FR_NO_FILESYSTEM) {
// no filesystem, so create a fresh one
// TODO doesn't seem to work correctly when reset_filesystem is true...
// LED on to indicate creation of LFS
led_state(PYB_LED_R2, 1);
uint32_t stc = sys_tick_counter;
res = f_mkfs("0:", 0, 0);
if (res == FR_OK) {
// success creating fresh LFS
} else {
__fatal_error("could not create LFS");
}
// create src directory
res = f_mkdir("0:/src");
// ignore result from mkdir
// create empty main.py
FIL fp;
f_open(&fp, "0:/src/main.py", FA_WRITE | FA_CREATE_ALWAYS);
UINT n;
f_write(&fp, fresh_main_py, sizeof(fresh_main_py) - 1 /* don't count null terminator */, &n);
// TODO check we could write n bytes
f_close(&fp);
// keep LED on for at least 200ms
sys_tick_wait_at_least(stc, 200);
led_state(PYB_LED_R2, 0);
} else {
__fatal_error("could not access LFS");
}
}
// make sure we have a /boot.py
{
FILINFO fno;
FRESULT res = f_stat("0:/boot.py", &fno);
if (res == FR_OK) {
if (fno.fattrib & AM_DIR) {
// exists as a directory
// TODO handle this case
// see http://elm-chan.org/fsw/ff/img/app2.c for a "rm -rf" implementation
} else {
// exists as a file, good!
}
} else {
// doesn't exist, create fresh file
// LED on to indicate creation of boot.py
led_state(PYB_LED_R2, 1);
uint32_t stc = sys_tick_counter;
FIL fp;
f_open(&fp, "0:/boot.py", FA_WRITE | FA_CREATE_ALWAYS);
UINT n;
f_write(&fp, fresh_boot_py, sizeof(fresh_boot_py) - 1 /* don't count null terminator */, &n);
// TODO check we could write n bytes
f_close(&fp);
// keep LED on for at least 200ms
sys_tick_wait_at_least(stc, 200);
led_state(PYB_LED_R2, 0);
}
}
// run /boot.py
if (!do_file("0:/boot.py")) {
flash_error(4);
}
if (first_soft_reset) {
#if MICROPY_HW_HAS_MMA7660
// MMA: init and reset address to zero
mma_init();
#endif
}
// turn boot-up LED off
led_state(PYB_LED_G1, 0);
#if MICROPY_HW_HAS_SDCARD
// if an SD card is present then mount it on 1:/
if (sdcard_is_present()) {
FRESULT res = f_mount(&fatfs1, "1:", 1);
if (res != FR_OK) {
printf("[SD] could not mount SD card\n");
} else {
if (first_soft_reset) {
// use SD card as medium for the USB MSD
usbd_storage_select_medium(USBD_STORAGE_MEDIUM_SDCARD);
}
}
}
#endif
#ifdef USE_HOST_MODE
// USB host
pyb_usb_host_init();
#elif defined(USE_DEVICE_MODE)
// USB device
pyb_usb_dev_init();
#endif
// run main script
{
vstr_t *vstr = vstr_new();
vstr_add_str(vstr, "0:/");
if (pyb_config_source_dir == MP_OBJ_NULL) {
vstr_add_str(vstr, "src");
} else {
vstr_add_str(vstr, mp_obj_str_get_str(pyb_config_source_dir));
}
vstr_add_char(vstr, '/');
if (pyb_config_main == MP_OBJ_NULL) {
vstr_add_str(vstr, "main.py");
} else {
vstr_add_str(vstr, mp_obj_str_get_str(pyb_config_main));
}
if (!do_file(vstr_str(vstr))) {
flash_error(3);
}
vstr_free(vstr);
}
#if MICROPY_HW_HAS_MMA7660
// HID example
if (0) {
uint8_t data[4];
data[0] = 0;
data[1] = 1;
data[2] = -2;
data[3] = 0;
for (;;) {
#if MICROPY_HW_HAS_SWITCH
if (switch_get()) {
data[0] = 0x01; // 0x04 is middle, 0x02 is right
} else {
data[0] = 0x00;
}
#else
data[0] = 0x00;
#endif
mma_start(0x4c /* MMA_ADDR */, 1);
mma_send_byte(0);
mma_restart(0x4c /* MMA_ADDR */, 0);
for (int i = 0; i <= 1; i++) {
int v = mma_read_ack() & 0x3f;
if (v & 0x20) {
v |= ~0x1f;
}
data[1 + i] = v;
}
mma_read_nack();
usb_hid_send_report(data);
sys_tick_delay_ms(15);
}
}
#endif
#if MICROPY_HW_HAS_WLAN
// wifi
pyb_wlan_init();
pyb_wlan_start();
#endif
do_repl();
printf("PYB: sync filesystems\n");
pyb_sync();
printf("PYB: soft reboot\n");
first_soft_reset = false;
goto soft_reset;
}
// these 2 functions seem to actually work... no idea why
// replacing with libgcc does not work (probably due to wrong calling conventions)
double __aeabi_f2d(float x) {
// TODO
return 0.0;
}
float __aeabi_d2f(double x) {
// TODO
return 0.0;
}
double sqrt(double x) {
// TODO
return 0.0;
}
machine_float_t machine_sqrt(machine_float_t x) {
// TODO
return x;
}