static inline void poll_sockets(void) { // TODO: Allow to override by ports mp_hal_delay_ms(1); }
STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { lwip_socket_obj_t *socket = self_in; if (socket->pcb.tcp == NULL) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EBADF))); } if (socket->type != MOD_NETWORK_SOCK_STREAM) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EOPNOTSUPP))); } // I need to do this because "tcp_accepted", later, is a macro. struct tcp_pcb *listener = socket->pcb.tcp; if (listener->state != LISTEN) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL))); } // accept incoming connection if (socket->incoming.connection == NULL) { if (socket->timeout != -1) { for (mp_uint_t retries = socket->timeout / 100; retries--;) { mp_hal_delay_ms(100); if (socket->incoming.connection != NULL) break; } if (socket->incoming.connection == NULL) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ETIMEDOUT))); } } else { while (socket->incoming.connection == NULL) { mp_hal_delay_ms(100); } } } // create new socket object lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t); socket2->base.type = (mp_obj_t)&lwip_socket_type; // We get a new pcb handle... socket2->pcb.tcp = socket->incoming.connection; socket->incoming.connection = NULL; // ...and set up the new socket for it. socket2->domain = MOD_NETWORK_AF_INET; socket2->type = MOD_NETWORK_SOCK_STREAM; socket2->incoming.pbuf = NULL; socket2->timeout = socket->timeout; socket2->state = STATE_CONNECTED; socket2->leftover_count = 0; tcp_arg(socket2->pcb.tcp, (void*)socket2); tcp_err(socket2->pcb.tcp, _lwip_tcp_error); tcp_recv(socket2->pcb.tcp, _lwip_tcp_recv); tcp_accepted(listener); // make the return value uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE]; memcpy(ip, &(socket2->pcb.tcp->remote_ip), sizeof(ip)); mp_uint_t port = (mp_uint_t)socket2->pcb.tcp->remote_port; mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); client->items[0] = socket2; client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); return client; }
STATIC mp_obj_t microbit_sleep(mp_obj_t ms_in) { mp_int_t ms = mp_obj_get_int(ms_in); mp_hal_delay_ms(ms); return mp_const_none; }
STATIC mp_uint_t _webrepl_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) { // We know that os.dupterm always calls with size = 1 assert(size == 1); mp_obj_webrepl_t *self = self_in; const mp_stream_p_t *sock_stream = mp_get_stream(self->sock); mp_uint_t out_sz = sock_stream->read(self->sock, buf, size, errcode); //DEBUG_printf("webrepl: Read %d initial bytes from websocket\n", out_sz); if (out_sz == 0 || out_sz == MP_STREAM_ERROR) { return out_sz; } if (self->state == STATE_PASSWD) { char c = *(char*)buf; if (c == '\r' || c == '\n') { self->hdr.fname[self->data_to_recv] = 0; DEBUG_printf("webrepl: entered password: %s\n", self->hdr.fname); if (strcmp(self->hdr.fname, webrepl_passwd) != 0) { write_webrepl_str(self->sock, SSTR(denied_prompt)); return 0; } self->state = STATE_NORMAL; self->data_to_recv = 0; write_webrepl_str(self->sock, SSTR(connected_prompt)); } else if (self->data_to_recv < 10) { self->hdr.fname[self->data_to_recv++] = c; } return -2; } // If last read data belonged to text record (== REPL) int err; if (sock_stream->ioctl(self->sock, MP_STREAM_GET_DATA_OPTS, 0, &err) == 1) { return out_sz; } DEBUG_printf("webrepl: received bin data, hdr_to_recv: %d, data_to_recv=%d\n", self->hdr_to_recv, self->data_to_recv); if (self->hdr_to_recv != 0) { char *p = (char*)&self->hdr + sizeof(self->hdr) - self->hdr_to_recv; *p++ = *(char*)buf; if (--self->hdr_to_recv != 0) { mp_uint_t hdr_sz = sock_stream->read(self->sock, p, self->hdr_to_recv, errcode); if (hdr_sz == MP_STREAM_ERROR) { return hdr_sz; } self->hdr_to_recv -= hdr_sz; if (self->hdr_to_recv != 0) { return -2; } } DEBUG_printf("webrepl: op: %d, file: %s, chunk @%x, sz=%d\n", self->hdr.type, self->hdr.fname, (uint32_t)self->hdr.offset, self->hdr.size); handle_op(self); return -2; } if (self->data_to_recv != 0) { static byte filebuf[512]; filebuf[0] = *(byte*)buf; mp_uint_t buf_sz = 1; if (--self->data_to_recv != 0) { size_t to_read = MIN(sizeof(filebuf) - 1, self->data_to_recv); mp_uint_t sz = sock_stream->read(self->sock, filebuf + 1, to_read, errcode); if (sz == MP_STREAM_ERROR) { return sz; } self->data_to_recv -= sz; buf_sz += sz; } if (self->hdr.type == PUT_FILE) { DEBUG_printf("webrepl: Writing %lu bytes to file\n", buf_sz); int err; mp_uint_t res = mp_stream_write_exactly(self->cur_file, filebuf, buf_sz, &err); if (err != 0 || res != buf_sz) { assert(0); } } else if (self->hdr.type == GET_FILE) { assert(buf_sz == 1); assert(self->data_to_recv == 0); assert(filebuf[0] == 0); mp_uint_t out_sz = write_file_chunk(self); if (out_sz != 0) { self->data_to_recv = 1; } } if (self->data_to_recv == 0) { mp_stream_close(self->cur_file); self->hdr_to_recv = sizeof(struct webrepl_file); DEBUG_printf("webrepl: Finished file operation %d\n", self->hdr.type); write_webrepl_resp(self->sock, 0); } #ifdef MICROPY_PY_WEBREPL_DELAY // Some platforms may have broken drivers and easily gets // overloaded with modest traffic WebREPL file transfers // generate. The basic workaround is a crude rate control // done in such way. mp_hal_delay_ms(MICROPY_PY_WEBREPL_DELAY); #endif } return -2; }
/// \function sleep(seconds) /// Sleep for the given number of seconds. STATIC mp_obj_t time_sleep(mp_obj_t seconds_o) { mp_hal_delay_ms(1000 * mp_obj_get_int(seconds_o)); return mp_const_none; }
STATIC mp_obj_t time_sleep_ms(mp_obj_t arg) { mp_hal_delay_ms(mp_obj_get_int(arg)); return mp_const_none; }
void TASK_MicroPython (void *pvParameters) { // get the top of the stack to initialize the garbage collector uint32_t sp = gc_helper_get_sp(); bool safeboot = false; mptask_pre_init(); #ifndef DEBUG safeboot = PRCMGetSpecialBit(PRCM_SAFE_BOOT_BIT); #endif soft_reset: // Thread init #if MICROPY_PY_THREAD mp_thread_init(); #endif // initialise the stack pointer for the main thread (must be done after mp_thread_init) mp_stack_set_top((void*)sp); // GC init gc_init(&_boot, &_eheap); // MicroPython init mp_init(); mp_obj_list_init(mp_sys_path, 0); mp_obj_list_init(mp_sys_argv, 0); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_)); // current dir (or base dir of the script) // execute all basic initializations mp_irq_init0(); pyb_sleep_init0(); pin_init0(); mperror_init0(); uart_init0(); timer_init0(); readline_init0(); mod_network_init0(); rng_init0(); pybsleep_reset_cause_t rstcause = pyb_sleep_get_reset_cause(); if (rstcause < PYB_SLP_SOFT_RESET) { if (rstcause == PYB_SLP_HIB_RESET) { // when waking up from hibernate we just want // to enable simplelink and leave it as is wlan_first_start(); } else { // only if not comming out of hibernate or a soft reset mptask_enter_ap_mode(); } // enable telnet and ftp servers_start(); } // initialize the serial flash file system mptask_init_sflash_filesystem(); // append the flash paths to the system path mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash)); mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR__slash_flash_slash_lib)); // reset config variables; they should be set by boot.py MP_STATE_PORT(machine_config_main) = MP_OBJ_NULL; if (!safeboot) { // run boot.py int ret = pyexec_file("boot.py"); if (ret & PYEXEC_FORCED_EXIT) { goto soft_reset_exit; } if (!ret) { // flash the system led mperror_signal_error(); } } // now we initialise sub-systems that need configuration from boot.py, // or whose initialisation can be safely deferred until after running // boot.py. // at this point everything is fully configured and initialised. if (!safeboot) { // run the main script from the current directory. if (pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) { const char *main_py; if (MP_STATE_PORT(machine_config_main) == MP_OBJ_NULL) { main_py = "main.py"; } else { main_py = mp_obj_str_get_str(MP_STATE_PORT(machine_config_main)); } int ret = pyexec_file(main_py); if (ret & PYEXEC_FORCED_EXIT) { goto soft_reset_exit; } if (!ret) { // flash the system led mperror_signal_error(); } } } // main script is finished, so now go into REPL mode. // the REPL mode can change, or it can request a soft reset. for ( ; ; ) { if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { if (pyexec_raw_repl() != 0) { break; } } else { if (pyexec_friendly_repl() != 0) { break; } } } soft_reset_exit: // soft reset pyb_sleep_signal_soft_reset(); mp_printf(&mp_plat_print, "MPY: soft reboot\n"); // disable all callbacks to avoid undefined behaviour // when coming out of a soft reset mp_irq_disable_all(); // cancel the RTC alarm which might be running independent of the irq state pyb_rtc_disable_alarm(); // flush the serial flash buffer sflash_disk_flush(); // clean-up the user socket space modusocket_close_all_user_sockets(); // unmount all user file systems osmount_unmount_all(); // wait for pending transactions to complete mp_hal_delay_ms(20); goto soft_reset; }