> 4); // status is code_index for these guys
+ if(usb_midi_packet[1]==0xF2) usb_midi_packet[0] = 0x03; // special
+ if(usb_midi_message_slot == 0) {
+ usb_midi_packet[2] = byte;
+ usb_midi_message_slot = 1;
+ } else {
+ usb_midi_packet[3] = byte;
+ usb_midi_message_slot = 0;
+ send_single_midi_out_packet(usb_midi_packet);
+ }
+ // a 1 byte data message
+ } else if (status == 0xC0 || status == 0xD0) {
+ usb_midi_packet[0] = (status >> 4);
+ usb_midi_packet[2] = byte;
+ send_single_midi_out_packet(usb_midi_packet);
+ i = len+1;
+ } else if (usb_midi_packet[1] == 0xF3 || usb_midi_packet[1] == 0xF1) {
+ usb_midi_packet[0] = 0x02; // special
+ send_single_midi_out_packet(usb_midi_packet);
+ i = len+1;
+ }
+ }
+ }
+ }
+
+}
+
+
+void prepare_endpoint_midi(const void *p) {
+ const usb_ep_desc_t *endpoint = (const usb_ep_desc_t *)p;
+ esp_err_t err;
+
+ // must be bulk for MIDI
+ if ((endpoint->bmAttributes & USB_BM_ATTRIBUTES_XFERTYPE_MASK) != USB_BM_ATTRIBUTES_XFER_BULK) {
+ fprintf(stderr, "USB MIDI: Not bulk endpoint: 0x%02x\n", endpoint->bmAttributes);
+ return;
+ }
+ if (endpoint->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) {
+ // MIDI-IN endpoint.
+ for (int i = 0; i < MIDI_IN_BUFFERS; i++) {
+ if (MIDIIn[i] == NULL) {
+ err = usb_host_transfer_alloc(endpoint->wMaxPacketSize, 0, &MIDIIn[i]);
+ if (err != ESP_OK) {
+ MIDIIn[i] = NULL;
+ fprintf(stderr, "midi usb_host_transfer_alloc/In err: 0x%x\n", err);
+ midi_has_out = false;
+ return;
+ }
+ }
+ if (MIDIIn[i] != NULL) {
+ MIDIIn[i]->device_handle = Device_Handle_midi;
+ MIDIIn[i]->bEndpointAddress = endpoint->bEndpointAddress;
+ MIDIIn[i]->callback = midi_transfer_cb;
+ MIDIIn[i]->context = (void *)i;
+ MIDIIn[i]->num_bytes = endpoint->wMaxPacketSize;
+ esp_err_t err = usb_host_transfer_submit(MIDIIn[i]);
+ if (err != ESP_OK) {
+ fprintf(stderr, "midi usb_host_transfer_submit/In err: 0x%x\n", err);
+ }
+ midi_has_in = true;
+ }
+ }
+ } else {
+ // MIDI-OUT endpoint
+ if (MIDIOut == NULL) {
+ err = usb_host_transfer_alloc(endpoint->wMaxPacketSize, 0, &MIDIOut);
+ if (err != ESP_OK) {
+ MIDIOut = NULL;
+ fprintf(stderr, "midi usb_host_transfer_alloc/Out err: 0x%x\n", err);
+ midi_has_out = false;
+ return;
+ }
+ }
+ if (MIDIOut != NULL) {
+ DBGPRINTF1("MIDI USB Out data_buffer_size: %d\n", MIDIOut->data_buffer_size);
+ MIDIOut->device_handle = Device_Handle_midi;
+ MIDIOut->bEndpointAddress = endpoint->bEndpointAddress;
+ MIDIOut->callback = midi_transfer_cb;
+ MIDIOut->context = NULL;
+ // MIDIOut->flags |= USB_TRANSFER_FLAG_ZERO_PACK;
+ midi_has_out = true;
+ }
+ }
+ // MIDI is ready when both input and output endpoints are initialized.
+ midi_ready = midi_has_in && midi_has_out;
+}
+
+void new_enumeration_config_fn(const usb_config_desc_t *config_desc);
+
+
+void _client_event_callback(const usb_host_client_event_msg_t *event_msg, void *arg)
+{
+ esp_err_t err;
+ switch (event_msg->event)
+ {
+ /**< A new device has been enumerated and added to the USB Host Library */
+ case USB_HOST_CLIENT_EVENT_NEW_DEV:
+ DBGPRINTF1("New device address: %d\n", event_msg->new_dev.address);
+ err = usb_host_device_open(Client_Handle, event_msg->new_dev.address, &Device_Handle_unknown);
+ if (err != ESP_OK) fprintf(stderr, "usb_host_device_open: 0x%x\n", err);
+
+ usb_device_info_t dev_info;
+ err = usb_host_device_info(Device_Handle_unknown, &dev_info);
+ if (err != ESP_OK) fprintf(stderr, "usb_host_device_info: 0x%x\n", err);
+ //printf("speed: %d dev_addr %d vMaxPacketSize0 %d bConfigurationValue %d\n",
+ // dev_info.speed, dev_info.dev_addr, dev_info.bMaxPacketSize0,
+ // dev_info.bConfigurationValue);
+
+ const usb_device_desc_t *dev_desc;
+ err = usb_host_get_device_descriptor(Device_Handle_unknown, &dev_desc);
+ if (err != ESP_OK) fprintf(stderr, "usb_host_get_device_desc: 0x%x\n", err);
+
+ const usb_config_desc_t *config_desc;
+ err = usb_host_get_active_config_descriptor(Device_Handle_unknown, &config_desc);
+ if (err != ESP_OK) fprintf(stderr,"usb_host_get_config_desc: 0x%x\n", err);
+ // Finally, we get to inspect the new device and maybe connect to it.
+ new_enumeration_config_fn(config_desc);
+ break;
+
+ /**< A device opened by the client is now gone */
+ case USB_HOST_CLIENT_EVENT_DEV_GONE:
+ fprintf(stderr,"Device Gone handle: 0x%lx\n", (uint32_t)event_msg->dev_gone.dev_hdl);
+ // Mark everything de-initialized so it will re-initialized on another connect.
+ esp_err_t err;
+ if (midi_claimed && (uint32_t)Device_Handle_midi == (uint32_t)event_msg->dev_gone.dev_hdl) {
+ err = usb_host_interface_release(Client_Handle, Device_Handle_midi, Interface_Number_midi);
+ if (err != ESP_OK) fprintf(stderr,"usb_host_interface_release err: 0x%x\n", err);
+ midi_claimed = false;
+ midi_ready = false;
+ midi_has_in = false;
+ midi_has_out = false;
+ }
+ if (keyboard_claimed && (uint32_t)Device_Handle_kb == (uint32_t)event_msg->dev_gone.dev_hdl) {
+ err = usb_host_interface_release(Client_Handle, Device_Handle_kb, Interface_Number_kb);
+ if (err != ESP_OK) fprintf(stderr,"usb_host_interface_release err: 0x%x\n", err);
+ keyboard_claimed = false;
+ keyboard_ready = false;
+ }
+ if (mouse_claimed && (uint32_t)Device_Handle_mouse == (uint32_t)event_msg->dev_gone.dev_hdl) {
+ err = usb_host_interface_release(Client_Handle, Device_Handle_mouse, Interface_Number_mouse);
+ if (err != ESP_OK) fprintf(stderr,"usb_host_interface_release err: 0x%x\n", err);
+ mouse_claimed = false;
+ mouse_ready = false;
+ disable_mouse_pointer();
+ }
+ err = usb_host_device_close(Client_Handle, Device_Handle_unknown);
+ if (err != ESP_OK) fprintf(stderr,"usb_host_device_close err: 0x%x\n", err);
+ break;
+ default:
+ fprintf(stderr,"Unknown USB event: %d\n", event_msg->event);
+ break;
+ }
+}
+
+// Reference: esp-idf/examples/peripherals/usb/host/usb_host_lib/main/usb_host_lib_main.c
+
+void usbh_setup()
+{
+ const usb_host_config_t config = {
+ .intr_flags = ESP_INTR_FLAG_LEVEL1,
+ };
+ esp_err_t err = usb_host_install(&config);
+ (void)err;
+ DBGPRINTF1("usb_host_install: 0x%x\n", err);
+
+ const usb_host_client_config_t client_config = {
+ .is_synchronous = false,
+ .max_num_event_msg = 5,
+ .async = {
+ .client_event_callback = _client_event_callback,
+ .callback_arg = Client_Handle
+ }
+ };
+ err = usb_host_client_register(&client_config, &Client_Handle);
+ DBGPRINTF1("usb_host_client_register: 0x%x\n", err);
+}
+
+void usbh_task(void)
+{
+ uint32_t event_flags;
+
+ esp_err_t err = usb_host_lib_handle_events(HOST_EVENT_TIMEOUT, &event_flags);
+ if (err == ESP_OK) {
+ if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
+ DBGPRINTF("No more clients\n");
+ }
+ if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
+ DBGPRINTF("No more devices\n");
+ }
+ } else {
+ if (err != ESP_ERR_TIMEOUT) {
+ fprintf(stderr,"usb_host_lib_handle_events: 0x%x flags: %lx\n", err, event_flags);
+ }
+ }
+
+ err = usb_host_client_handle_events(Client_Handle, CLIENT_EVENT_TIMEOUT);
+ if ((err != ESP_OK) && (err != ESP_ERR_TIMEOUT)) {
+ fprintf(stderr,"usb_host_client_handle_events: 0x%x\n", err);
+ }
+}
+
+
+
+static char lvgl_kb_buf[KEYBOARD_BUFFER_SIZE];
+
+void lvgl_keyboard_read(lv_indev_t * indev_drv, lv_indev_data_t * data) {
+ (void) indev_drv; // unused
+ static bool dummy_read = false;
+ const size_t len = strlen(lvgl_kb_buf);
+
+ // Send a release manually
+ if (dummy_read) {
+ dummy_read = false;
+ data->state = LV_INDEV_STATE_RELEASED;
+ data->continue_reading = len > 0;
+ }
+ // Send the pressed character
+ else if (len > 0) {
+ dummy_read = true;
+ data->state = LV_INDEV_STATE_PRESSED;
+ data->key = lvgl_kb_buf[0];
+ memmove(lvgl_kb_buf, lvgl_kb_buf + 1, len);
+ data->continue_reading = true;
+ }
+}
+
+
+void decode_keyboard_report(uint8_t *p) {
+ // First byte, modifier mask
+ uint8_t modifier = p[0];
+ uint8_t new_key = 0;
+ uint8_t key_held_this_session = 0;
+ // Second byte, reserved
+ // next 6 bytes, scan codes (for rollover)
+
+ #ifdef DEBUG_USB
+ //fprintf(stderr,"decode report %d %d %d %d %d %d\n", p[2],p[3],p[4],p[5],p[6],p[7]);
+ #endif
+ for(uint8_t i=2;i<8;i++) {
+ if(p[i]!=0) {
+ key_held_this_session = 1;
+ uint8_t skip = 0;
+ for(uint8_t j=2;j<8;j++) {
+ if(last_scan[j] == p[i]) skip = 1;
+ }
+ if(!skip) { // only process new keys
+ uint16_t c = scan_ascii(p[i], modifier);
+ if(c) {
+ if(keycode_to_ctrl_key(c) != '\0') {
+ const size_t len = strlen(lvgl_kb_buf);
+ if (len < KEYBOARD_BUFFER_SIZE - 1) {
+ lvgl_kb_buf[len] = keycode_to_ctrl_key(c);
+ lvgl_kb_buf[len + 1] = '\0';
+ }
+ } else {
+ // put it in lvgl_kb_buf for lvgl
+ const size_t len = strlen(lvgl_kb_buf);
+ if (len < KEYBOARD_BUFFER_SIZE - 1) {
+ lvgl_kb_buf[len] = c;
+ lvgl_kb_buf[len+1] = '\0';
+ }
+ }
+ new_key = 1;
+ current_held_ms = esp_timer_get_time()/1000;
+ current_held = c;
+ send_key_to_micropython(c);
+ }
+ }
+ }
+ }
+ if(!new_key && !key_held_this_session) {
+ // we got a message but no new keys. so is a release
+ current_held_ms = 0;
+ current_held = 0;
+ last_inter_trigger_ms = 0;
+ }
+ for(uint8_t i=0;i<8;i++) last_scan[i] = p[i];
+}
+
+#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
+void keyboard_transfer_cb(usb_transfer_t *transfer)
+{
+ if (Device_Handle_kb == transfer->device_handle) {
+ isKeyboardPolling = false;
+ if (transfer->status == 0) {
+ #ifdef DEBUG_USB
+ //fprintf(stderr, "nb is %d\n", transfer->actual_num_bytes);
+ #endif
+ if (transfer->actual_num_bytes == 8 || transfer->actual_num_bytes == 16) {
+ uint8_t *const p = transfer->data_buffer;
+ decode_keyboard_report(p);
+ } else if (transfer->actual_num_bytes == 10) {
+ uint8_t *const p = transfer->data_buffer;
+ decode_keyboard_report(p+1);
+ } else if (transfer->actual_num_bytes == 17 || transfer->actual_num_bytes == 32) {
+ // This is a weird keyboard (8bitdo retro, custom 40 key ortho) that uses USB FS HID and sends keys as a bitmask.
+ // I found people talking about this here but no code, so here i am https://stackoverflow.com/questions/57793525/unusual-usb-hid-reports
+ uint8_t *const p = transfer->data_buffer;
+ // We treat each bit on position as a index into a scan code, and will add it to a new buffer for decode_report to deal with
+ uint8_t new_decode[8];
+ for(uint8_t i=0;i<8;i++) new_decode[i] = 0;
+ new_decode[0] = p[1]; // modifier goes here
+ uint8_t bit_count = 0;
+ uint8_t rollover_count = 2; // start writing as pos 2
+ // p[0] has the length (starting from the modifier)
+ for(uint8_t i=2;iactual_num_bytes);
+ }
+ }
+ else {
+ fprintf(stderr, "kbd transfer->status %d\n", transfer->status);
+ }
+ }
+}
+
+
+void mouse_transfer_cb(usb_transfer_t *transfer)
+{
+ //fprintf(stderr, "mouse nb is %d\n", transfer->actual_num_bytes);
+ //uint8_t *p = transfer->data_buffer;
+ //fprintf(stderr,"mouse decode report %d %d %d %d %d %d %d %d\n", p[0], p[1], p[2],p[3],p[4],p[5],p[6],p[7]);
+
+
+ if (Device_Handle_mouse == transfer->device_handle) {
+ isMousePolling = false;
+ if (transfer->status == 0) {
+ hid_mouse_input_report_boot_t *mouse_report = (hid_mouse_input_report_boot_t *)(transfer->data_buffer+1);
+ mouse_x_pos += mouse_report->x_displacement;
+ mouse_y_pos += mouse_report->y_displacement;
+ if(mouse_x_pos >= H_RES) mouse_x_pos = H_RES-1;
+ if(mouse_y_pos >= V_RES) mouse_y_pos = V_RES-1;
+ if(mouse_x_pos < 0) mouse_x_pos = 0;
+ if(mouse_y_pos < 0) mouse_y_pos = 0;
+ mouse_buttons[0] = mouse_report->buttons.button1;
+ mouse_buttons[1] = mouse_report->buttons.button2;
+ mouse_buttons[2] = mouse_report->buttons.button3;
+ last_touch_x[0] = mouse_x_pos;
+ last_touch_y[0] = mouse_y_pos;
+ enable_mouse_pointer();// this is a no-op if already installed
+ if(mouse_buttons[0]) {
+ send_touch_to_micropython(mouse_x_pos, mouse_y_pos, 0);
+ } else {
+ send_touch_to_micropython(mouse_x_pos, mouse_y_pos, 1);
+ }
+ }
+ else {
+ fprintf(stderr, "mouse transfer->status %d\n", transfer->status);
+ }
+ }
+}
+
+bool check_interface_desc_boot_keyboard(const void *p) {
+ const usb_intf_desc_t *intf = (const usb_intf_desc_t *)p;
+ if ((intf->bInterfaceClass == USB_CLASS_HID) &&
+ (intf->bInterfaceSubClass == 1) &&
+ (intf->bInterfaceProtocol == 1)) {
+ keyboard_claimed = true;
+ Interface_Number_kb = intf->bInterfaceNumber;
+ esp_err_t err = usb_host_interface_claim(Client_Handle, Device_Handle_unknown,
+ Interface_Number_kb, intf->bAlternateSetting);
+ if (err != ESP_OK) fprintf(stderr, "usb_host_interface_claim failed: 0x%x\n", err);
+ return true;
+ }
+ return false;
+}
+
+bool check_interface_desc_boot_mouse(const void *p) {
+ const usb_intf_desc_t *intf = (const usb_intf_desc_t *)p;
+ if ((intf->bInterfaceClass == USB_CLASS_HID) &&
+ (intf->bInterfaceSubClass == 1) &&
+ (intf->bInterfaceProtocol == 2)) {
+ mouse_claimed = true;
+ Interface_Number_mouse = intf->bInterfaceNumber;
+ esp_err_t err = usb_host_interface_claim(Client_Handle, Device_Handle_unknown,
+ Interface_Number_mouse, intf->bAlternateSetting);
+ if (err != ESP_OK) fprintf(stderr, "usb_host_interface_claim failed: 0x%x\n", err);
+ return true;
+ } else if ((intf->bInterfaceClass == USB_CLASS_HID) &&
+ (intf->bInterfaceSubClass == 0) &&
+ (intf->bInterfaceProtocol == 0)) {
+ fprintf(stderr, "We are using a different type of mouse claim\n");
+ mouse_claimed = true;
+ Interface_Number_mouse = intf->bInterfaceNumber;
+ esp_err_t err = usb_host_interface_claim(Client_Handle, Device_Handle_unknown,
+ Interface_Number_mouse, intf->bAlternateSetting);
+ if (err != ESP_OK) fprintf(stderr, "usb_host_interface_claim failed: 0x%x\n", err);
+ return true;
+ }
+ return false;
+}
+
+void prepare_endpoint_hid_kb(const void *p)
+{
+ const usb_ep_desc_t *endpoint = (const usb_ep_desc_t *)p;
+ esp_err_t err;
+ keyboard_bytes = usb_round_up_to_mps(KEYBOARD_BYTES, endpoint->wMaxPacketSize);
+ DBGPRINTF2("Setting KB to %d from MPS %d\n", keyboard_bytes, endpoint->wMaxPacketSize);
+
+ // must be interrupt for HID
+ if ((endpoint->bmAttributes & USB_BM_ATTRIBUTES_XFERTYPE_MASK) != USB_BM_ATTRIBUTES_XFER_INT) {
+ fprintf(stderr, "Kbd: Not interrupt endpoint: 0x%02x\n", endpoint->bmAttributes);
+ return;
+ }
+ if (endpoint->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) {
+ if (KeyboardIn == NULL) {
+ err = usb_host_transfer_alloc(keyboard_bytes, 0, &KeyboardIn);
+ if (err != ESP_OK) {
+ KeyboardIn = NULL;
+ fprintf(stderr, "kbd usb_host_transfer_alloc/In err: 0x%x\n", err);
+ return;
+ }
+ }
+ if (KeyboardIn != NULL) {
+ KeyboardIn->device_handle = Device_Handle_kb;
+ KeyboardIn->bEndpointAddress = endpoint->bEndpointAddress;
+ KeyboardIn->callback = keyboard_transfer_cb;
+ KeyboardIn->context = NULL;
+ keyboard_ready = true;
+ KeyboardInterval = endpoint->bInterval;
+ DBGPRINTF("USB boot keyboard ready\n");
+ }
+ } else {
+ DBGPRINTF("Ignoring kbd interrupt Out endpoint\n");
+ }
+}
+void prepare_endpoint_hid_mouse(const void *p)
+{
+ const usb_ep_desc_t *endpoint = (const usb_ep_desc_t *)p;
+ esp_err_t err;
+ mouse_bytes = usb_round_up_to_mps(MOUSE_BYTES, endpoint->wMaxPacketSize);
+ DBGPRINTF2("Setting mouse or 0x03/0/0 to %d from MPS %d\n", mouse_bytes, endpoint->wMaxPacketSize);
+ if(mouse_bytes==32) {
+ fprintf(stderr, "Redirecting this endpoint to KB (0x03/0/0)\n");
+ KeyboardIn = NULL;
+ MouseIn = NULL;
+ prepare_endpoint_hid_kb(p);
+ mouse_claimed = false;
+ } else {
+ // must be interrupt for HID
+ if ((endpoint->bmAttributes & USB_BM_ATTRIBUTES_XFERTYPE_MASK) != USB_BM_ATTRIBUTES_XFER_INT) {
+ fprintf(stderr, "Mouse: Not interrupt endpoint: 0x%02x\n", endpoint->bmAttributes);
+ return;
+ }
+ if (endpoint->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) {
+ if (MouseIn == NULL) {
+ err = usb_host_transfer_alloc(mouse_bytes, 0, &MouseIn);
+ if (err != ESP_OK) {
+ MouseIn = NULL;
+ fprintf(stderr, "mouse usb_host_transfer_alloc/In err: 0x%x\n", err);
+ return;
+ }
+ }
+ if (MouseIn != NULL) {
+ MouseIn->device_handle = Device_Handle_mouse;
+ MouseIn->bEndpointAddress = endpoint->bEndpointAddress;
+ MouseIn->callback = mouse_transfer_cb;
+ MouseIn->context = NULL;
+ mouse_ready = true;
+ mouse_x_pos = H_RES/2;
+ mouse_y_pos = V_RES/2;
+ MouseInterval = endpoint->bInterval;
+ DBGPRINTF("USB boot mouse ready\n");
+ }
+ } else {
+ DBGPRINTF("Ignoring mouse interrupt Out endpoint\n");
+ }
+ }
+}
+
+void new_enumeration_config_fn(const usb_config_desc_t *config_desc) {
+ // We just retrieved the config of a newly-connected device.
+ // Read through it and see if we can claim a recognized device.
+ //
+ // &config_desc->val[0] is the same as config_desc
+ // so the first "descriptor type" found is actually TYPE_CONFIGURATION
+ // and the call to show_config_desc(p) is equivalent to doing
+ // show_config_desc(config_desc) here.
+
+
+ const uint8_t *p = &config_desc->val[0];
+ uint8_t bLength;
+ int indent = 1;
+ int last_descriptor = -1;
+ for (int i = 0; i < config_desc->wTotalLength; i+=bLength, p+=bLength) {
+ bLength = *p;
+ if ((i + bLength) <= config_desc->wTotalLength) {
+ const uint8_t bDescriptorType = *(p + 1);
+ DBGPRINTF3("config_desc->val[%d]: type=%d length=%d\n", i, bDescriptorType, bLength);
+ switch (bDescriptorType) {
+ case USB_B_DESCRIPTOR_TYPE_CONFIGURATION:
+ // The first record in val[] is by definition the config description.
+ show_config_desc(p, indent++);
+ last_descriptor = bDescriptorType;
+ break;
+ case USB_B_DESCRIPTOR_TYPE_DEVICE:
+ DBGPRINTF("USB Device Descriptor should not appear in config\n");
+ break;
+ case USB_B_DESCRIPTOR_TYPE_STRING:
+ DBGPRINTF("USB string desc TBD\n");
+ break;
+ case USB_B_DESCRIPTOR_TYPE_INTERFACE:
+ if ((last_descriptor == USB_B_DESCRIPTOR_TYPE_INTERFACE)
+ || (last_descriptor == USB_B_DESCRIPTOR_TYPE_ENDPOINT)) --indent;
+ show_interface_desc(p, indent++);
+ if(!midi_claimed) { check_interface_desc_MIDI(p); if(midi_claimed) Device_Handle_midi = Device_Handle_unknown; }
+ if(!keyboard_claimed) { check_interface_desc_boot_keyboard(p);if(keyboard_claimed) Device_Handle_kb = Device_Handle_unknown;}
+ if(!mouse_claimed) { check_interface_desc_boot_mouse(p);if(mouse_claimed) Device_Handle_mouse = Device_Handle_unknown;}
+ last_descriptor = bDescriptorType;
+ break;
+ case USB_B_DESCRIPTOR_TYPE_ENDPOINT:
+ show_endpoint_desc(p, indent);
+ if (keyboard_claimed && !keyboard_ready) {
+ prepare_endpoint_hid_kb(p);
+ }
+ if (mouse_claimed && !mouse_ready) {
+ prepare_endpoint_hid_mouse(p);
+ }
+ if (midi_claimed && !midi_ready) {
+ prepare_endpoint_midi(p);
+ }
+ last_descriptor = bDescriptorType;
+ break;
+ case USB_B_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
+ DBGPRINTF("USB device qual desc TBD\n");
+ break;
+ case USB_B_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION:
+ DBGPRINTF("USB Other Speed TBD\n");
+ break;
+ case USB_B_DESCRIPTOR_TYPE_INTERFACE_POWER:
+ DBGPRINTF("USB Interface Power TBD\n");
+ break;
+ case 0x21:
+ // HID
+ break;
+ case 0x24:
+ // UAS PIPE mode - see this for MIDI keyboard.
+ break;
+ case 0x25:
+ // Also see this for MIDI keyboard.
+ break;
+ default:
+ fprintf(stderr, "Unknown USB Descriptor Type: 0x%x\n", bDescriptorType);
+ break;
+ }
+ }
+ else {
+ fprintf(stderr, "USB Descriptor invalid\n");
+ return;
+ }
+ }
+}
+
+
+void run_usb()
+{
+ // Reset key maps
+ for(uint8_t i=0;i 0) {
+ if(KeyRepeatTimer - current_held_ms > KEY_REPEAT_TRIGGER_MS) {
+ if(KeyRepeatTimer - last_inter_trigger_ms > KEY_REPEAT_INTER_MS) {
+ send_key_to_micropython(current_held);
+ last_inter_trigger_ms = KeyRepeatTimer;
+ }
+ }
+ }
+
+ if (keyboard_ready && !isKeyboardPolling && (KeyboardTimer > KeyboardInterval)) {
+ KeyboardIn->num_bytes = keyboard_bytes;
+ esp_err_t err = usb_host_transfer_submit(KeyboardIn);
+ if (err != ESP_OK) {
+ fprintf(stderr,"kbd usb_host_transfer_submit/In err: 0x%x\n", err);
+ }
+ isKeyboardPolling = true;
+ KeyboardTimer = 0;
+ }
+ if (mouse_ready && !isMousePolling && (MouseTimer > MouseInterval)) {
+ MouseIn->num_bytes = mouse_bytes;
+ esp_err_t err = usb_host_transfer_submit(MouseIn);
+ if (err != ESP_OK) {
+ fprintf(stderr, "mouse usb_host_transfer_submit/In err: 0x%x\n", err);
+ }
+ isMousePolling = true;
+ MouseTimer = 0;
+ }
+ }
+}
diff --git a/tulip/esp32s3/usb_keyboard.h b/tulip/esp32s3/usb_host.h
similarity index 56%
rename from tulip/esp32s3/usb_keyboard.h
rename to tulip/esp32s3/usb_host.h
index 52cd213d0..73c1a5ce3 100644
--- a/tulip/esp32s3/usb_keyboard.h
+++ b/tulip/esp32s3/usb_host.h
@@ -1,4 +1,4 @@
-// usb_keyboard.h
+// usb_host.h
#ifndef __USB_KEYBOARD_H__
#define __USB_KEYBOARD_H__
@@ -12,19 +12,8 @@
#include "keyscan.h"
#include "tulip_helpers.h"
#include "esp_timer.h"
+#include "display.h"
#include "midi.h" // from extmod/tulip/
-#include "lvgl.h"
-
-
-// vortex 8
-// keychron 16
-#define KEYBOARD_BYTES 8
-extern uint16_t keyboard_bytes;
-
-// How long you hold down a key before it starts repeating
-#define KEY_REPEAT_TRIGGER_MS 500
-// How often (in ms) to repeat a key once held
-#define KEY_REPEAT_INTER_MS 90
void usbh_setup();
void run_usb();
diff --git a/tulip/esp32s3/usb_keyboard.c b/tulip/esp32s3/usb_keyboard.c
deleted file mode 100644
index 738e52555..000000000
--- a/tulip/esp32s3/usb_keyboard.c
+++ /dev/null
@@ -1,689 +0,0 @@
-// usb_keyboard.c
-#include "usb_keyboard.h"
-
-#define KEYBOARD_BUFFER_SIZE 32
-
-uint16_t keyboard_bytes = KEYBOARD_BYTES;
-
-typedef union {
- struct {
- uint8_t bLength; /**< Size of the descriptor in bytes */
- uint8_t bDescriptorType; /**< Constant name specifying type of HID descriptor. */
- uint16_t bcdHID; /**< USB HID Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H) */
- uint8_t bCountryCode; /**< Numeric expression identifying country code of the localized hardware. */
- uint8_t bNumDescriptor; /**< Numeric expression specifying the number of class descriptors. */
- uint8_t bHIDDescriptorType; /**< Constant name identifying type of class descriptor. See Section 7.1.2: Set_Descriptor Request for a table of class descriptor constants. */
- uint16_t wHIDDescriptorLength; /**< Numeric expression that is the total size of the Report descriptor. */
- uint8_t bHIDDescriptorTypeOpt; /**< Optional constant name identifying type of class descriptor. See Section 7.1.2: Set_Descriptor Request for a table of class descriptor constants. */
- uint16_t wHIDDescriptorLengthOpt; /**< Optional numeric expression that is the total size of the Report descriptor. */
- } USB_DESC_ATTR;
- uint8_t val[9];
-} usb_hid_desc_t;
-
-//#define DEBUG_USB
-#ifdef DEBUG_USB
-// from show_desc.hpp
-// from https://github.com/touchgadget/esp32-usb-host-demos
-
-#define DBGPRINTF(s) printf(s)
-#define DBGPRINTF1(s, a) printf(s, a)
-#define DBGPRINTF2(s, a, b) printf(s, a, b)
-#define DBGPRINTF3(s, a, b, c) printf(s, a, b, c)
-#define DBGPRINTF4(s, a, b, c, d) printf(s, a, b, c, d)
-
-void show_config_desc(const void *p, int indent)
-{
- char prefix[8];
- for (int i=0; i < indent; ++i) prefix[i] = '*';
- prefix[indent] = '\0';
- const usb_config_desc_t *config_desc = (const usb_config_desc_t *)p;
- fprintf(stderr, "%s CONFIG_DESC(size=%d)\n", prefix, config_desc->bLength);
- //fprintf(stderr, "bDescriptorType(config): %d\n", config_desc->bDescriptorType);
- fprintf(stderr, "%s wTotalLength: %d\n", prefix, config_desc->wTotalLength);
- fprintf(stderr, "%s bNumInterfaces: %d\n", prefix, config_desc->bNumInterfaces);
- fprintf(stderr, "%s bConfigurationValue: %d\n", prefix, config_desc->bConfigurationValue);
- fprintf(stderr, "%s iConfiguration: %d\n", prefix, config_desc->iConfiguration);
- fprintf(stderr, "%s bmAttributes: 0x%02x (%s%s%s)\n", prefix,
- config_desc->bmAttributes,
- (config_desc->bmAttributes & USB_BM_ATTRIBUTES_SELFPOWER)?"Self Powered, ":"",
- (config_desc->bmAttributes & USB_BM_ATTRIBUTES_WAKEUP)?"Remote Wakeup, ":"",
- (config_desc->bmAttributes & USB_BM_ATTRIBUTES_BATTERY)?"Battery Powered":"");
- fprintf(stderr,"%s bMaxPower: %d (%d mA)\n", prefix, config_desc->bMaxPower, config_desc->bMaxPower*2);
-}
-
-uint8_t show_interface_desc(const void *p, int indent)
-{
- char prefix[8];
- for (int i=0; i < indent; ++i) prefix[i] = '*';
- prefix[indent] = '\0';
- const usb_intf_desc_t *intf = (const usb_intf_desc_t *)p;
-
- fprintf(stderr, "%s INTERFACE_DESC(size=%d)\n", prefix, intf->bLength);
- //fprintf(stderr, "%s bDescriptorType (interface): %d\n", intf->bDescriptorType);
- fprintf(stderr, "%s bInterfaceNumber: %d\n", prefix, intf->bInterfaceNumber);
- fprintf(stderr, "%s bAlternateSetting: %d\n", prefix, intf->bAlternateSetting);
- fprintf(stderr, "%s bNumEndpoints: %d\n", prefix, intf->bNumEndpoints);
- fprintf(stderr, "%s bInterfaceClass: 0x%02x\n", prefix, intf->bInterfaceClass);
- fprintf(stderr, "%s bInterfaceSubClass: 0x%02x\n", prefix, intf->bInterfaceSubClass);
- fprintf(stderr, "%s bInterfaceProtocol: 0x%02x\n", prefix, intf->bInterfaceProtocol);
- fprintf(stderr, "%s iInterface: %d\n", prefix, intf->iInterface);
- return intf->bInterfaceClass;
-}
-
-void show_endpoint_desc(const void *p, int indent)
-{
- char prefix[8];
- for (int i=0; i < indent; ++i) prefix[i] = '*';
- prefix[indent] = '\0';
- const usb_ep_desc_t *endpoint = (const usb_ep_desc_t *)p;
- const char *XFER_TYPE_NAMES[] = {
- "Control", "Isochronous", "Bulk", "Interrupt"
- };
- fprintf(stderr, "%s ENDPOINT_DESC(size=%d)\n", prefix, endpoint->bLength);
- //fprintf(stderr, "%s bDescriptorType (endpoint): %d\n", prefix, endpoint->bDescriptorType);
- fprintf(stderr, "%s bEndpointAddress: 0x%02x (%s)\n", prefix,
- endpoint->bEndpointAddress,
- (endpoint->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK)?"In":"Out");
- fprintf(stderr, "%s bmAttributes: 0x%02x (%s)\n", prefix,
- endpoint->bmAttributes,
- XFER_TYPE_NAMES[endpoint->bmAttributes & USB_BM_ATTRIBUTES_XFERTYPE_MASK]);
- fprintf(stderr, "%s wMaxPacketSize: %d\n", prefix, endpoint->wMaxPacketSize);
- fprintf(stderr, "%s bInterval: %d\n", prefix, endpoint->bInterval);
-}
-
-// end of show_desc.hpp
-#else // !DEBUG_USB
-
-#define DBGPRINTF(s) /* nothing */
-#define DBGPRINTF1(s, a) /* nothing */
-#define DBGPRINTF2(s, a, b) /* nothing */
-#define DBGPRINTF3(s, a, b, c) /* nothing */
-#define DBGPRINTF4(s, a, b, c, d) /* nothing */
-
-#define show_config_desc(p, i) /* nothing */
-#define show_interface_desc(p, i) /* nothing */
-#define show_endpoint_desc(p, i) /* nothing */
-
-#endif // DEBUG_USB
-
-const TickType_t HOST_EVENT_TIMEOUT = 1;
-const TickType_t CLIENT_EVENT_TIMEOUT = 1;
-
-const size_t USB_HID_DESC_SIZE = 9;
-
-usb_host_client_handle_t Client_Handle;
-usb_device_handle_t Device_Handle;
-uint8_t Interface_Number;
-
-bool isKeyboard = false;
-bool isKeyboardReady = false;
-uint8_t KeyboardInterval;
-bool isKeyboardPolling = false;
-int64_t KeyboardTimer=0;
-int64_t KeyRepeatTimer=0;
-
-
-
-//const size_t KEYBOARD_IN_BUFFER_SIZE = KEYBOARD_BYTES;
-usb_transfer_t *KeyboardIn = NULL;
-
-// ---------------------------------
-// from usbhmidi.ino
-bool isMIDI = false;
-bool haveMIDIin = false;
-bool haveMIDIout = false;
-bool isMIDIReady = false;
-
-//const size_t MIDI_IN_BUFFERS = 8;
-//const size_t MIDI_OUT_BUFFERS = 8;
-#define MIDI_IN_BUFFERS 8
-//#define MIDI_OUT_BUFFERS 8
-usb_transfer_t *MIDIOut = NULL;
-usb_transfer_t *MIDIIn[MIDI_IN_BUFFERS] = { NULL };
-
-
-// USB MIDI Event Packet Format (always 4 bytes)
-//
-// Byte 0 |Byte 1 |Byte 2 |Byte 3
-// -------|-------|-------|------
-// CN+CIN |MIDI_0 |MIDI_1 |MIDI_2
-//
-// CN = Cable Number ((0x0..0xf)<<4) specifies virtual MIDI jack/cable
-// CIN = Code Index Number (0x0..0xf) classifies the 3 MIDI bytes.
-// See Table 4-1 in the MIDI 1.0 spec at usb.org.
-//
-
-static void midi_transfer_cb(usb_transfer_t *transfer) {
- //printf("**midi_transfer_cb context: %p\n", transfer->context);
- if (Device_Handle == transfer->device_handle) {
- int in_xfer = transfer->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK;
- if ((transfer->status == 0) && in_xfer) {
- uint8_t *const p = transfer->data_buffer;
- for (int i = 0; i < transfer->actual_num_bytes; i += 4) {
- if ((p[i] + p[i + 1] + p[i + 2] + p[i + 3]) == 0) break;
- DBGPRINTF4("midi: %02x %02x %02x %02x\n",
- p[i], p[i + 1], p[i + 2], p[i + 3]);
- // Strip the first byte which is the USB-MIDI virtual wire ID,
- // rest is MIDI message (at least for 3-byte messages).
- convert_midi_bytes_to_messages(p + i + 1, 3, 1);
- }
- esp_err_t err = usb_host_transfer_submit(transfer);
- if (err != ESP_OK) {
- printf("midi usb_host_transfer_submit err: 0x%x\n", err);
- }
- } else {
- printf("midi transfer->status %d\n", transfer->status);
- }
- }
-}
-
-bool check_interface_desc_MIDI(const void *p) {
- const usb_intf_desc_t *intf = (const usb_intf_desc_t *)p;
-
- // USB MIDI
- if ((intf->bInterfaceClass == USB_CLASS_AUDIO) &&
- (intf->bInterfaceSubClass == 3) &&
- (intf->bInterfaceProtocol == 0)) {
- isMIDI = true;
- printf("Claiming a MIDI device!\n");
- Interface_Number = intf->bInterfaceNumber;
- esp_err_t err = usb_host_interface_claim(Client_Handle, Device_Handle,
- Interface_Number, intf->bAlternateSetting);
- if (err != ESP_OK) printf("midi usb_host_interface_claim failed: %x\n", err);
- return true;
- }
- return false;
-}
-
-void prepare_endpoint_midi(const void *p) {
- const usb_ep_desc_t *endpoint = (const usb_ep_desc_t *)p;
- esp_err_t err;
-
- // must be bulk for MIDI
- if ((endpoint->bmAttributes & USB_BM_ATTRIBUTES_XFERTYPE_MASK) != USB_BM_ATTRIBUTES_XFER_BULK) {
- printf("MIDI: Not bulk endpoint: 0x%02x\n", endpoint->bmAttributes);
- return;
- }
- if (endpoint->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) {
- // MIDI-IN endpoint.
- for (int i = 0; i < MIDI_IN_BUFFERS; i++) {
- if (MIDIIn[i] == NULL) {
- err = usb_host_transfer_alloc(endpoint->wMaxPacketSize, 0, &MIDIIn[i]);
- if (err != ESP_OK) {
- MIDIIn[i] = NULL;
- printf("midi usb_host_transfer_alloc/In err: 0x%x\n", err);
- haveMIDIout = false;
- return;
- }
- }
- if (MIDIIn[i] != NULL) {
- MIDIIn[i]->device_handle = Device_Handle;
- MIDIIn[i]->bEndpointAddress = endpoint->bEndpointAddress;
- MIDIIn[i]->callback = midi_transfer_cb;
- MIDIIn[i]->context = (void *)i;
- MIDIIn[i]->num_bytes = endpoint->wMaxPacketSize;
- esp_err_t err = usb_host_transfer_submit(MIDIIn[i]);
- if (err != ESP_OK) {
- printf("midi usb_host_transfer_submit/In err: 0x%x\n", err);
- }
- haveMIDIout = true;
- }
- }
- } else {
- // MIDI-OUT endpoint
- if (MIDIOut == NULL) {
- err = usb_host_transfer_alloc(endpoint->wMaxPacketSize, 0, &MIDIOut);
- if (err != ESP_OK) {
- MIDIOut = NULL;
- printf("midi usb_host_transfer_alloc/Out err: 0x%x\n", err);
- haveMIDIin = false;
- return;
- }
- }
- if (MIDIOut != NULL) {
- DBGPRINTF1("Out data_buffer_size: %d\n", MIDIOut->data_buffer_size);
- MIDIOut->device_handle = Device_Handle;
- MIDIOut->bEndpointAddress = endpoint->bEndpointAddress;
- MIDIOut->callback = midi_transfer_cb;
- MIDIOut->context = NULL;
- // MIDIOut->flags |= USB_TRANSFER_FLAG_ZERO_PACK;
- haveMIDIin = true;
- }
- }
- // MIDI is ready when both input and output endpoints are initialized.
- //isMIDIReady = ((MIDIOut != NULL) && (MIDIIn[0] != NULL));
- isMIDIReady = haveMIDIin && haveMIDIout;
-}
-
-// end of usbhmidi.ino
-// ---------------------------------
-
-void new_enumeration_config_fn(const usb_config_desc_t *config_desc);
-
-
-void _client_event_callback(const usb_host_client_event_msg_t *event_msg, void *arg)
-{
- esp_err_t err;
- switch (event_msg->event)
- {
- /**< A new device has been enumerated and added to the USB Host Library */
- case USB_HOST_CLIENT_EVENT_NEW_DEV:
- DBGPRINTF1("New device address: %d\n", event_msg->new_dev.address);
- err = usb_host_device_open(Client_Handle, event_msg->new_dev.address, &Device_Handle);
- if (err != ESP_OK) printf("usb_host_device_open: 0x%x\n", err);
-
- usb_device_info_t dev_info;
- err = usb_host_device_info(Device_Handle, &dev_info);
- if (err != ESP_OK) printf("usb_host_device_info: 0x%x\n", err);
- //printf("speed: %d dev_addr %d vMaxPacketSize0 %d bConfigurationValue %d\n",
- // dev_info.speed, dev_info.dev_addr, dev_info.bMaxPacketSize0,
- // dev_info.bConfigurationValue);
-
- const usb_device_desc_t *dev_desc;
- err = usb_host_get_device_descriptor(Device_Handle, &dev_desc);
- if (err != ESP_OK) printf("usb_host_get_device_desc: 0x%x\n", err);
-
- const usb_config_desc_t *config_desc;
- err = usb_host_get_active_config_descriptor(Device_Handle, &config_desc);
- if (err != ESP_OK) printf("usb_host_get_config_desc: 0x%x\n", err);
- // Finally, we get to inspect the new device and maybe connect to it.
- new_enumeration_config_fn(config_desc);
- break;
- /**< A device opened by the client is now gone */
- case USB_HOST_CLIENT_EVENT_DEV_GONE:
- printf("Device Gone handle: 0x%lx\n", (uint32_t)event_msg->dev_gone.dev_hdl);
- // Mark everything de-initialized so it will re-initialized on another connect.
- esp_err_t err;
- if (isMIDI || isKeyboard) {
- err = usb_host_interface_release(Client_Handle, Device_Handle, Interface_Number);
- if (err != ESP_OK) printf("usb_host_interface_release err: 0x%x\n", err);
- isMIDI = false;
- isKeyboard = false;
- }
- err = usb_host_device_close(Client_Handle, Device_Handle);
- if (err != ESP_OK) printf("usb_host_device_close err: 0x%x\n", err);
- isMIDIReady = false;
- haveMIDIin = false;
- haveMIDIout = false;
- isKeyboardReady = false;
- break;
- default:
- printf("Unknown USB event: %d\n", event_msg->event);
- break;
- }
-}
-
-// Reference: esp-idf/examples/peripherals/usb/host/usb_host_lib/main/usb_host_lib_main.c
-
-void usbh_setup()
-{
- const usb_host_config_t config = {
- .intr_flags = ESP_INTR_FLAG_LEVEL1,
- };
- esp_err_t err = usb_host_install(&config);
- (void)err;
- DBGPRINTF1("usb_host_install: 0x%x\n", err);
-
- const usb_host_client_config_t client_config = {
- .is_synchronous = false,
- .max_num_event_msg = 5,
- .async = {
- .client_event_callback = _client_event_callback,
- .callback_arg = Client_Handle
- }
- };
- err = usb_host_client_register(&client_config, &Client_Handle);
- DBGPRINTF1("usb_host_client_register: 0x%x\n", err);
-}
-
-void usbh_task(void)
-{
- uint32_t event_flags;
-
- esp_err_t err = usb_host_lib_handle_events(HOST_EVENT_TIMEOUT, &event_flags);
- if (err == ESP_OK) {
- if (event_flags & USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS) {
- DBGPRINTF("No more clients\n");
- }
- if (event_flags & USB_HOST_LIB_EVENT_FLAGS_ALL_FREE) {
- DBGPRINTF("No more devices\n");
- }
- } else {
- if (err != ESP_ERR_TIMEOUT) {
- printf("usb_host_lib_handle_events: 0x%x flags: %lx\n", err, event_flags);
- }
- }
-
- err = usb_host_client_handle_events(Client_Handle, CLIENT_EVENT_TIMEOUT);
- if ((err != ESP_OK) && (err != ESP_ERR_TIMEOUT)) {
- printf("usb_host_client_handle_events: 0x%x\n", err);
- }
-}
-
-// Keep track of which keys / scan codes are being held
-uint16_t current_held = 0;
-int64_t current_held_ms = 0;
-int64_t last_inter_trigger_ms = 0;
-
-
-
-uint32_t keycode_to_ctrl_key(uint16_t key)
-{
- switch(key) {
- case 261:
- return LV_KEY_RIGHT;
-
- case 260:
- return LV_KEY_LEFT;
-
- case 259:
- return LV_KEY_UP;
-
- case 258:
- return LV_KEY_DOWN;
-
- case 27:
- return LV_KEY_ESC;
-
- case 8:
- return LV_KEY_BACKSPACE;
-
- //case SDLK_DELETE:
- // return LV_KEY_DEL;
-
- case 13:
- return LV_KEY_ENTER;
-
- // We could feed in shift here, TODO
- case 9:
- return LV_KEY_NEXT;
-
- case 22:
- return LV_KEY_NEXT;
-
- case 25:
- return LV_KEY_PREV;
-
- default:
- return '\0';
- }
-}
-
-
-static char lvgl_kb_buf[KEYBOARD_BUFFER_SIZE];
-
-
-void lvgl_keyboard_read(lv_indev_t * indev_drv, lv_indev_data_t * data) {
- (void) indev_drv; // unused
-
- static bool dummy_read = false;
- const size_t len = strlen(lvgl_kb_buf);
-
- // Send a release manually
- if (dummy_read) {
- dummy_read = false;
- data->state = LV_INDEV_STATE_RELEASED;
- data->continue_reading = len > 0;
- }
- // Send the pressed character
- else if (len > 0) {
- dummy_read = true;
- data->state = LV_INDEV_STATE_PRESSED;
- data->key = lvgl_kb_buf[0];
- memmove(lvgl_kb_buf, lvgl_kb_buf + 1, len);
- data->continue_reading = true;
- }
-}
-
-
-
-void decode_report(uint8_t *p) {
- // First byte, modifier mask
- uint8_t modifier = p[0];
- uint8_t new_key = 0;
- uint8_t key_held_this_session = 0;
- // Second byte, reserved
- // next 6 bytes, scan codes (for rollover)
- //fprintf(stderr,"decode report %d %d %d %d %d %d\n", p[2],p[3],p[4],p[5],p[6],p[7]);
- for(uint8_t i=2;i<8;i++) {
- if(p[i]!=0) {
- key_held_this_session = 1;
- uint8_t skip = 0;
- for(uint8_t j=2;j<8;j++) {
- if(last_scan[j] == p[i]) skip = 1;
- }
- if(!skip) { // only process new keys
- uint16_t c = scan_ascii(p[i], modifier);
- if(c) {
-
- if(keycode_to_ctrl_key(c) != '\0') {
- const size_t len = strlen(lvgl_kb_buf);
- if (len < KEYBOARD_BUFFER_SIZE - 1) {
- lvgl_kb_buf[len] = keycode_to_ctrl_key(c);
- lvgl_kb_buf[len + 1] = '\0';
- }
- } else {
- // put it in lvgl_kb_buf for lvgl
- const size_t len = strlen(lvgl_kb_buf);
- if (len < KEYBOARD_BUFFER_SIZE - 1) {
- lvgl_kb_buf[len] = c;
- lvgl_kb_buf[len+1] = '\0';
- }
- }
-
- new_key = 1;
- current_held_ms = esp_timer_get_time()/1000;
- current_held = c;
- //fprintf(stderr, "sending new key %d to MP at time %lld\n", c, current_held_ms);
- send_key_to_micropython(c);
- }
- }
- }
- }
- if(!new_key && !key_held_this_session) {
- // we got a message but no new keys. so is a release
- //fprintf(stderr, "turning off key\n");
- current_held_ms = 0;
- current_held = 0;
- last_inter_trigger_ms = 0;
- }
- for(uint8_t i=0;i<8;i++) last_scan[i] = p[i];
-}
-
-void keyboard_transfer_cb(usb_transfer_t *transfer)
-{
- if (Device_Handle == transfer->device_handle) {
- isKeyboardPolling = false;
- if (transfer->status == 0) {
- //fprintf(stderr, "nb is %d\n", transfer->actual_num_bytes);
- //if(transfer->actual_num_bytes > 7 && transfer->actual_num_bytes < 17) {
- if (transfer->actual_num_bytes == 8 || transfer->actual_num_bytes == 16) {
- uint8_t *const p = transfer->data_buffer;
- decode_report(p);
- } else if (transfer->actual_num_bytes == 10) {
- uint8_t *const p = transfer->data_buffer;
- decode_report(p+1);
- } else {
- printf("Keyboard boot hid transfer (%d bytes) too short or long\n",
- transfer->actual_num_bytes);
- }
- }
- else {
- printf("kbd transfer->status %d\n", transfer->status);
- }
- }
-}
-
-bool check_interface_desc_boot_keyboard(const void *p) {
- const usb_intf_desc_t *intf = (const usb_intf_desc_t *)p;
-
- // HID Keyboard
- if ((intf->bInterfaceClass == USB_CLASS_HID) &&
- (intf->bInterfaceSubClass == 1) &&
- (intf->bInterfaceProtocol == 1)) {
- isKeyboard = true;
- Interface_Number = intf->bInterfaceNumber;
-
-
- esp_err_t err = usb_host_interface_claim(Client_Handle, Device_Handle,
- Interface_Number, intf->bAlternateSetting);
- if (err != ESP_OK) printf("usb_host_interface_claim failed: 0x%x\n", err);
- return true;
- }
- return false;
-}
-
-void prepare_endpoint_hid(const void *p)
-{
- const usb_ep_desc_t *endpoint = (const usb_ep_desc_t *)p;
- esp_err_t err;
- keyboard_bytes = usb_round_up_to_mps(KEYBOARD_BYTES, endpoint->wMaxPacketSize);
- DBGPRINTF2("Setting KB to %d from MPS %d\n", keyboard_bytes, endpoint->wMaxPacketSize);
-
- // must be interrupt for HID
- if ((endpoint->bmAttributes & USB_BM_ATTRIBUTES_XFERTYPE_MASK) != USB_BM_ATTRIBUTES_XFER_INT) {
- printf("Kbd: Not interrupt endpoint: 0x%02x\n", endpoint->bmAttributes);
- return;
- }
- if (endpoint->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) {
- if (KeyboardIn == NULL) {
- err = usb_host_transfer_alloc(keyboard_bytes, 0, &KeyboardIn);
- if (err != ESP_OK) {
- KeyboardIn = NULL;
- printf("kbd usb_host_transfer_alloc/In err: 0x%x\n", err);
- return;
- }
- }
- if (KeyboardIn != NULL) {
- KeyboardIn->device_handle = Device_Handle;
- KeyboardIn->bEndpointAddress = endpoint->bEndpointAddress;
- KeyboardIn->callback = keyboard_transfer_cb;
- KeyboardIn->context = NULL;
- isKeyboardReady = true;
- KeyboardInterval = endpoint->bInterval;
- DBGPRINTF("USB boot keyboard ready\n");
- }
- } else {
- DBGPRINTF("Ignoring kbd interrupt Out endpoint\n");
- }
-}
-
-void new_enumeration_config_fn(const usb_config_desc_t *config_desc) {
- // We just retrieved the config of a newly-connected device.
- // Read through it and see if we can claim a recognized device.
- //
- // &config_desc->val[0] is the same as config_desc
- // so the first "descriptor type" found is actually TYPE_CONFIGURATION
- // and the call to show_config_desc(p) is equivalent to doing
- // show_config_desc(config_desc) here.
-
-
- const uint8_t *p = &config_desc->val[0];
- uint8_t bLength;
- int indent = 1;
- int last_descriptor = -1;
- for (int i = 0; i < config_desc->wTotalLength; i+=bLength, p+=bLength) {
- bLength = *p;
- if ((i + bLength) <= config_desc->wTotalLength) {
- const uint8_t bDescriptorType = *(p + 1);
- DBGPRINTF3("config_desc->val[%d]: type=%d length=%d\n", i, bDescriptorType, bLength);
- switch (bDescriptorType) {
- case USB_B_DESCRIPTOR_TYPE_CONFIGURATION:
- // The first record in val[] is by definition the config description.
- show_config_desc(p, indent++);
- last_descriptor = bDescriptorType;
- break;
- case USB_B_DESCRIPTOR_TYPE_DEVICE:
- DBGPRINTF("USB Device Descriptor should not appear in config\n");
- break;
- case USB_B_DESCRIPTOR_TYPE_STRING:
- DBGPRINTF("USB string desc TBD\n");
- break;
- case USB_B_DESCRIPTOR_TYPE_INTERFACE:
- if ((last_descriptor == USB_B_DESCRIPTOR_TYPE_INTERFACE)
- || (last_descriptor == USB_B_DESCRIPTOR_TYPE_ENDPOINT)) --indent;
- show_interface_desc(p, indent++);
- if (!isMIDI && !isKeyboard) {
- if (!check_interface_desc_MIDI(p)) {
- check_interface_desc_boot_keyboard(p);
- }
- }
- if (!isMIDI && !isKeyboard) {
- DBGPRINTF("Interface was neither keyboard nor midi.\n");
- }
- last_descriptor = bDescriptorType;
- break;
- case USB_B_DESCRIPTOR_TYPE_ENDPOINT:
- show_endpoint_desc(p, indent);
- if (isKeyboard && !isKeyboardReady) {
- prepare_endpoint_hid(p);
- } else if (isMIDI && !isMIDIReady) {
- prepare_endpoint_midi(p);
- }
- last_descriptor = bDescriptorType;
- break;
- case USB_B_DESCRIPTOR_TYPE_DEVICE_QUALIFIER:
- DBGPRINTF("USB device qual desc TBD\n");
- break;
- case USB_B_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION:
- DBGPRINTF("USB Other Speed TBD\n");
- break;
- case USB_B_DESCRIPTOR_TYPE_INTERFACE_POWER:
- DBGPRINTF("USB Interface Power TBD\n");
- break;
- case 0x21:
- // HID
- break;
- case 0x24:
- // UAS PIPE mode - see this for MIDI keyboard.
- break;
- case 0x25:
- // Also see this for MIDI keyboard.
- break;
- default:
- printf("Unknown USB Descriptor Type: 0x%x\n", bDescriptorType);
- break;
- }
- }
- else {
- printf("USB Descriptor invalid\n");
- return;
- }
- }
-}
-
-void run_usb()
-{
- // Reset key maps
- for(uint8_t i=0;i 0) {
- if(KeyRepeatTimer - current_held_ms > KEY_REPEAT_TRIGGER_MS) {
- if(KeyRepeatTimer - last_inter_trigger_ms > KEY_REPEAT_INTER_MS) {
- send_key_to_micropython(current_held);
- last_inter_trigger_ms = KeyRepeatTimer;
- }
- }
- }
- if (isKeyboardReady && !isKeyboardPolling && (KeyboardTimer > KeyboardInterval)) {
- KeyboardIn->num_bytes = keyboard_bytes;
- esp_err_t err = usb_host_transfer_submit(KeyboardIn);
- if (err != ESP_OK) {
- printf("kbd usb_host_transfer_submit/In err: 0x%x\n", err);
- }
- isKeyboardPolling = true;
- KeyboardTimer = 0;
- }
- }
-}
diff --git a/tulip/esp32s3/usb_serial_jtag.c b/tulip/esp32s3/usb_serial_jtag.c
deleted file mode 100644
index 3289a1b5c..000000000
--- a/tulip/esp32s3/usb_serial_jtag.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2021 Patrick Van Oosterwijck
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "py/runtime.h"
-#include "py/mphal.h"
-#include "usb_serial_jtag.h"
-
-#if CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
-
-#include "hal/usb_serial_jtag_ll.h"
-#include "esp_intr_alloc.h"
-#include "soc/periph_defs.h"
-
-#define USB_SERIAL_JTAG_BUF_SIZE (64)
-
-static uint8_t rx_buf[USB_SERIAL_JTAG_BUF_SIZE];
-static volatile bool terminal_connected = false;
-
-static void usb_serial_jtag_isr_handler(void *arg) {
- uint32_t flags = usb_serial_jtag_ll_get_intsts_mask();
-
- if (flags & USB_SERIAL_JTAG_INTR_SOF) {
- usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SOF);
- }
-
- if (flags & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT) {
- usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT);
- size_t req_len = ringbuf_free(&stdin_ringbuf);
- if (req_len > USB_SERIAL_JTAG_BUF_SIZE) {
- req_len = USB_SERIAL_JTAG_BUF_SIZE;
- }
- size_t len = usb_serial_jtag_ll_read_rxfifo(rx_buf, req_len);
- for (size_t i = 0; i < len; ++i) {
- if (rx_buf[i] == mp_interrupt_char) {
- mp_sched_keyboard_interrupt();
- } else {
- ringbuf_put(&stdin_ringbuf, rx_buf[i]);
- }
- }
- mp_hal_wake_main_task_from_isr();
- }
-}
-
-void usb_serial_jtag_init(void) {
- usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT |
- USB_SERIAL_JTAG_INTR_SOF);
- usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT |
- USB_SERIAL_JTAG_INTR_SOF);
- ESP_ERROR_CHECK(esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1,
- usb_serial_jtag_isr_handler, NULL, NULL));
-}
-
-void usb_serial_jtag_tx_strn(const char *str, size_t len) {
- while (len) {
- size_t l = len;
- if (l > USB_SERIAL_JTAG_PACKET_SZ_BYTES) {
- l = USB_SERIAL_JTAG_PACKET_SZ_BYTES;
- }
- TickType_t start_tick = xTaskGetTickCount();
- while (!usb_serial_jtag_ll_txfifo_writable()) {
- TickType_t now_tick = xTaskGetTickCount();
- if (!terminal_connected || now_tick > (start_tick + pdMS_TO_TICKS(200))) {
- terminal_connected = false;
- return;
- }
- }
- terminal_connected = true;
- l = usb_serial_jtag_ll_write_txfifo((const uint8_t *)str, l);
- usb_serial_jtag_ll_txfifo_flush();
- str += l;
- len -= l;
- }
-}
-
-#endif // CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG
diff --git a/tulip/esp32s3/usb_serial_jtag.h b/tulip/esp32s3/usb_serial_jtag.h
deleted file mode 100644
index 4eebb19e4..000000000
--- a/tulip/esp32s3/usb_serial_jtag.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2021 Patrick Van Oosterwijck
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#ifndef MICROPY_INCLUDED_ESP32_USB_SERIAL_JTAG_H
-#define MICROPY_INCLUDED_ESP32_USB_SERIAL_JTAG_H
-
-void usb_serial_jtag_init(void);
-void usb_serial_jtag_tx_strn(const char *str, size_t len);
-
-#endif // MICROPY_INCLUDED_ESP32_USB_SERIAL_JTAG_H
diff --git a/tulip/linux/Makefile b/tulip/linux/Makefile
index 3e912a645..859d9c475 100644
--- a/tulip/linux/Makefile
+++ b/tulip/linux/Makefile
@@ -1,3 +1,7 @@
+# Tulip linux, based on unix port makefile
+
+DEBUG=1
+
# Select the variant to build for.
VARIANT ?= standard
MAKEFLAGS += --jobs=4
@@ -9,12 +13,15 @@ TOP = ../../micropython
VARIANT_DIR ?= ../../micropython/ports/unix/variants/$(VARIANT)
+# If the build directory is not given, make it reflect the variant name.
+BUILD ?= build-$(VARIANT)
+
include $(TOP)/py/mkenv.mk
-include ../shared/desktop/mpconfigport.mk
-include $(VARIANT_DIR)/mpconfigvariant.mk
+include mpconfigport.mk
+#include $(VARIANT_DIR)/mpconfigvariant.mk
# Use the default frozen manifest, variants may override this.
-FROZEN_MANIFEST ?= manifest.py
+FROZEN_MANIFEST ?= variants/manifest.py
# This should be configured by the mpconfigvariant.mk
PROG = tulip
@@ -30,6 +37,7 @@ UNAME_S := $(shell uname -s)
include $(TOP)/py/py.mk
include $(TOP)/extmod/extmod.mk
+
# LVGL stuff
LVGL_BINDING_DIR = $(TOP)/../lv_binding_micropython_tulip
LVGL_DIR = $(LVGL_BINDING_DIR)/lvgl
@@ -42,7 +50,10 @@ LVGL_MPY_METADATA = $(BUILD)/lvgl/lv_mpy.json
QSTR_GLOBAL_DEPENDENCIES += $(LVGL_MPY)
CFLAGS_MOD += $(LV_CFLAGS)
SRC_C += $(shell find $(LVGL_DIR)/src -type f -name '*.c')
-CFLAGS += -DLV_CONF_INCLUDE_SIMPLE
+CFLAGS += -DLV_CONF_INCLUDE_SIMPLE
+
+# This is for the lvgl stuff that uses STATIC
+CFLAGS += -DSTATIC=static
$(LVGL_MPY): $(ALL_LVGL_SRC) $(LVGL_BINDING_DIR)/gen/gen_mpy.py
$(ECHO) "LVGL-GEN $@"
@@ -60,30 +71,40 @@ INC += -I$(TOP)/ports/unix
INC += -I../shared/
INC += -I../../amy/src/
INC += -I$(TOP)/lib/mbedtls/include
-INC += -I/usr/include/SDL2
INC += -I$(TOP)/../lv_binding_micropython_tulip/lvgl/src
INC += -I$(TOP)/../lv_binding_micropython_tulip/lvgl/src/libs/lodepng
+INC += -I/usr/include/SDL2
+
+
+GIT_SUBMODULES += lib/berkeley-db-1.xx
+
+INC += -I.
+INC += -I$(TOP)
+INC += -I$(BUILD)
# compiler settings
-CWARN = -Wall
-CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion
-CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA)
-CFLAGS += -DTULIP_DESKTOP
+# compiler settings
+CWARN = -Wall -Werror
+CWARN += -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-old-style-declaration -Wno-unused-but-set-parameter -Wpointer-arith -Wdouble-promotion -Wno-float-conversion -Wno-missing-declarations -Wno-unused-but-set-variable -Wno-sign-compare -Wno-gnu-variable-sized-type-not-at-end -Wno-undefined-internal
+CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA)
+CFLAGS += -DTULIP_DESKTOP
CFLAGS += $(ARCHFLAGS)
+
# Debugging/Optimization
ifdef DEBUG
-COPT ?= -Og
+#COPT ?= -Og
else
-COPT ?= -Os
+#COPT ?= -Os
COPT += -DNDEBUG
endif
# Remove unused sections.
-COPT += -fdata-sections -ffunction-sections
+COPT += -fdata-sections -ffunction-sections -O0
+
-# Always enable symbols -- They're occasionally useful, and don't make it into the
-# final .bin/.hex/.dfu so the extra size doesn't matter.
+# Note: Symbols and debug information will still be stripped from the final binary
+# unless "DEBUG=1" or "STRIP=" is passed to make, see README.md for details.
CFLAGS += -g
ifndef DEBUG
@@ -111,17 +132,11 @@ ifndef DEBUG
# https://gcc.gnu.org/ml/gcc-patches/2004-09/msg02055.html .
#
# Turning off _FORTIFY_SOURCE is only required when compiling with -O1 or greater
-CFLAGS += -U _FORTIFY_SOURCE -fPIC
+CFLAGS += -U _FORTIFY_SOURCE
endif
-# On OSX, 'gcc' is a symlink to clang unless a real gcc is installed.
-# The unix port of MicroPython on OSX must be compiled with clang,
-# while cross-compile ports require gcc, so we test here for OSX and
-# if necessary override the value of 'CC' set in py/mkenv.mk
-
-LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref -Wl,--gc-sections
+LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref -Wl,--gc-sections
LDFLAGS += $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA)
-#LDFLAGS += -lstdc++ $(ARCHFLAGS)
# Flags to link with pthread library
LIBPTHREAD = -lpthread
@@ -131,75 +146,102 @@ ifeq ($(MICROPY_FORCE_32BIT),1)
# starting with linux-libc-dev:i386
ifeq ($(MICROPY_PY_FFI),1)
ifeq ($(UNAME_S),Linux)
-CFLAGS_MOD += -I/usr/include/i686-linux-gnu
+CFLAGS += -I/usr/include/i686-linux-gnu
endif
endif
endif
ifeq ($(MICROPY_USE_READLINE),1)
INC += -I$(TOP)/shared/readline
-CFLAGS_MOD += -DMICROPY_USE_READLINE=1
+CFLAGS += -DMICROPY_USE_READLINE=1
SHARED_SRC_C_EXTRA += readline/readline.c
endif
ifeq ($(MICROPY_PY_TERMIOS),1)
-CFLAGS_MOD += -DMICROPY_PY_TERMIOS=1
-SRC_MOD += $(MICROPY_PORT_DIR)/modtermios.c
+CFLAGS += -DMICROPY_PY_TERMIOS=1
endif
ifeq ($(MICROPY_PY_SOCKET),1)
-CFLAGS_MOD += -DMICROPY_PY_SOCKET=1
+CFLAGS += -DMICROPY_PY_SOCKET=1
SRC_MOD += $(MICROPY_PORT_DIR)/modsocket.c
endif
ifeq ($(MICROPY_PY_THREAD),1)
-CFLAGS_MOD += -DMICROPY_PY_THREAD=1 -DMICROPY_PY_THREAD_GIL=0
-LDFLAGS_MOD += $(LIBPTHREAD)
+CFLAGS += -DMICROPY_PY_THREAD=1 -DMICROPY_PY_THREAD_GIL=0
+LDFLAGS += $(LIBPTHREAD)
endif
+
include ../shared/tulip.mk
MICROPY_PORT_DIR=../../micropython/ports/unix
+ifeq ($(MICROPY_PY_SSL),1)
+ifeq ($(MICROPY_SSL_AXTLS),1)
+
+endif
+endif
+
+# If the variant enables it, enable modbluetooth.
+ifeq ($(MICROPY_PY_BLUETOOTH),1)
+ifeq ($(MICROPY_BLUETOOTH_BTSTACK),1)
+HAVE_LIBUSB := $(shell (which pkg-config > /dev/null && pkg-config --exists libusb-1.0) 2>/dev/null && echo '1')
+
+# Figure out which BTstack transport to use.
+ifeq ($(HAVE_LIBUSB),1)
+# Default to btstack-over-usb.
+MICROPY_BLUETOOTH_BTSTACK_USB ?= 1
+else
+# Fallback to HCI controller via a H4 UART (e.g. Zephyr on nRF) over a /dev/tty serial port.
+MICROPY_BLUETOOTH_BTSTACK_H4 ?= 1
+endif
+
+SRC_BTSTACK_C += lib/btstack/platform/embedded/btstack_run_loop_embedded.c
+endif
+endif
+
ifeq ($(MICROPY_PY_FFI),1)
ifeq ($(MICROPY_STANDALONE),1)
-LIBFFI_CFLAGS_MOD := -I$(shell ls -1d $(BUILD)/lib/libffi/out/lib/libffi-*/include)
+# Build libffi from source.
+GIT_SUBMODULES += lib/libffi
+DEPLIBS += libffi
+LIBFFI_CFLAGS := -I$(shell ls -1d $(BUILD)/lib/libffi/include)
ifeq ($(MICROPY_FORCE_32BIT),1)
- LIBFFI_LDFLAGS_MOD = $(BUILD)/lib/libffi/out/lib32/libffi.a
+ LIBFFI_LDFLAGS = $(BUILD)/lib/libffi/out/lib32/libffi.a
else
- LIBFFI_LDFLAGS_MOD = $(BUILD)/lib/libffi/out/lib/libffi.a
+ LIBFFI_LDFLAGS = $(BUILD)/lib/libffi/out/lib/libffi.a
endif
else
-LIBFFI_CFLAGS_MOD := $(shell pkg-config --cflags libffi)
-LIBFFI_LDFLAGS_MOD := $(shell pkg-config --libs libffi)
+# Use system version of libffi.
+LIBFFI_CFLAGS := $(shell pkg-config --cflags libffi)
+LIBFFI_LDFLAGS := $(shell pkg-config --libs libffi)
endif
-ifeq ($(UNAME_S),Linux)
-LIBFFI_LDFLAGS_MOD += -ldl -lSDL2
-endif
-CFLAGS_MOD += $(LIBFFI_CFLAGS_MOD) -DMICROPY_PY_FFI=1
-LDFLAGS_MOD += $(LIBFFI_LDFLAGS_MOD)
-SRC_MOD += $(MICROPY_PORT_DIR)/modffi.c
+CFLAGS += $(LIBFFI_CFLAGS) -DMICROPY_PY_FFI=1
+LDFLAGS += $(LIBFFI_LDFLAGS)
endif
ifeq ($(MICROPY_PY_JNI),1)
# Path for 64-bit OpenJDK, should be adjusted for other JDKs
-CFLAGS_MOD += -I/usr/lib/jvm/java-7-openjdk-amd64/include -DMICROPY_PY_JNI=1
-SRC_MOD += $(MICROPY_PORT_DIR)/modjni.c
+CFLAGS += -I/usr/lib/jvm/java-7-openjdk-amd64/include -DMICROPY_PY_JNI=1
+endif
+
+
+ifeq ($(UNAME_S),Linux)
+LDFLAGS += -ldl -lSDL2
endif
# source files
SRC_C += \
main.c \
- ../shared/desktop/unix_mphal.c \
../shared/desktop/unix_display.c \
../shared/desktop/multicast.c \
- ../shared/desktop/mpthreadport.c \
+ ../shared/desktop/unix_mphal.c \
../../amy/src/libminiaudio-audio.c \
+ $(MICROPY_PORT_DIR)/mpthreadport.c \
$(MICROPY_PORT_DIR)/gccollect.c \
$(MICROPY_PORT_DIR)/input.c \
- $(MICROPY_PORT_DIR)/modmachine.c \
$(MICROPY_PORT_DIR)/alloc.c \
$(MICROPY_PORT_DIR)/fatfs_port.c \
$(MICROPY_PORT_DIR)/mpbthciport.c \
@@ -210,8 +252,11 @@ SRC_C += \
$(SRC_MOD) \
$(wildcard $(VARIANT_DIR)/*.c)
+
+#SRC_C += $(LVGL_PP)
SRC_C += $(LVGL_MPY)
+
SHARED_SRC_C += $(addprefix ../../micropython/shared/,\
runtime/gchelper_generic.c \
runtime/interrupt_char.c \
@@ -223,35 +268,29 @@ SHARED_SRC_C += $(addprefix ../../micropython/shared/,\
SRC_CXX += \
$(SRC_MOD_CXX)
-
OBJ = $(PY_O)
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
-OBJ += $(addprefix $(BUILD)/, $(SRC_M:.m=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_CXX:.cpp=.o))
OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
+
+
# List of sources for qstr extraction
SRC_QSTR += $(SRC_C) $(SRC_CXX) $(SHARED_SRC_C) $(EXTMOD_SRC_C)
-# Append any auto-generated sources that are needed by sources listed in
-# SRC_QSTR
-SRC_QSTR_AUTO_DEPS +=
ifneq ($(FROZEN_MANIFEST),)
-# To use frozen code create a manifest.py file with a description of files to
-# freeze, then invoke make with FROZEN_MANIFEST=manifest.py (be sure to build from scratch).
-CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
-CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs
-CFLAGS += -DMICROPY_MODULE_FROZEN_STR
endif
+
CPU_BRAND_NAME=linux
CFLAGS += -DMICROPY_HW_MCU_NAME="\"$(CPU_BRAND_NAME)\""
CFLAGS += -Wno-double-promotion -Wno-unused-function
CXXFLAGS += $(filter-out -Wno-double-promotion -Wmissing-prototypes -Wold-style-definition -std=gnu99,$(CFLAGS) $(CXXFLAGS_MOD))
+
ifeq ($(MICROPY_FORCE_32BIT),1)
RUN_TESTS_MPY_CROSS_FLAGS = --mpy-cross-flags='-march=x86'
endif
@@ -269,23 +308,25 @@ endif
include $(TOP)/py/mkrules.mk
-#undefine compile_c
+.PHONY: test test_full
+
+test: $(BUILD)/$(PROG) $(TOP)/tests/run-tests.py
+ $(eval DIRNAME=ports/$(notdir $(CURDIR)))
+ cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py
+
+test_full: $(BUILD)/$(PROG) $(TOP)/tests/run-tests.py
+ $(eval DIRNAME=ports/$(notdir $(CURDIR)))
+ cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py
+ cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py -d thread
+ cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py --emit native
+ cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py --via-mpy $(RUN_TESTS_MPY_CROSS_FLAGS) -d basics float micropython
+ cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py --via-mpy $(RUN_TESTS_MPY_CROSS_FLAGS) --emit native -d basics float micropython
+ cat $(TOP)/tests/basics/0prelim.py | ./$(BUILD)/$(PROG) | grep -q 'abc'
-define compile_c
-$(ECHO) "CC $<"
-$(Q)$(CC) $(CFLAGS) -c -MD -o $@ $< || (echo -e $(HELP_BUILD_ERROR); false)
-@# The following fixes the dependency file.
-@# See http://make.paulandlesley.org/autodep.html for details.
-@# Regex adjusted from the above to play better with Windows paths, etc.
-@$(CP) $(@:.o=.d) $(@:.o=.P); \
- $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \
- -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \
- $(RM) -f $(@:.o=.d)
-endef
+test_gcov: test_full
+ gcov -o $(BUILD)/py $(TOP)/py/*.c
+ gcov -o $(BUILD)/extmod $(TOP)/extmod/*.c
-$(BUILD)/%.o: %.m
- $(ECHO) "M $<"
- clang -I$(INC) $(CFLAGS) -c -o $@ $<
# Value of configure's --host= option (required for cross-compilation).
# Deduce it from CROSS_COMPILE by default, but can be overridden.
@@ -295,7 +336,7 @@ else
CROSS_COMPILE_HOST =
endif
-deplibs: libffi axtls
+deplibs: $(DEPLIBS)
libffi: $(BUILD)/lib/libffi/include/ffi.h
@@ -306,15 +347,15 @@ $(TOP)/lib/libffi/configure: $(TOP)/lib/libffi/autogen.sh
# docs and depending on makeinfo
$(BUILD)/lib/libffi/include/ffi.h: $(TOP)/lib/libffi/configure
mkdir -p $(BUILD)/lib/libffi; cd $(BUILD)/lib/libffi; \
- $(abspath $(TOP))/lib/libffi/configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out --disable-structs CC="$(CC)" CXX="$(CXX)" LD="$(LD)" CFLAGS="-Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions"; \
+ $(abspath $(TOP))/lib/libffi/configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out --disable-shared --disable-structs CC="$(CC)" CXX="$(CXX)" LD="$(LD)" CFLAGS="-Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions"; \
$(MAKE) install-exec-recursive; $(MAKE) -C include install-data-am
PREFIX = /usr/local
BINDIR = $(DESTDIR)$(PREFIX)/bin
-install: $(PROG)
+install: $(BUILD)/$(PROG)
install -d $(BINDIR)
- install $(PROG) $(BINDIR)/$(PROG)
+ install $(BUILD)/$(PROG) $(BINDIR)/$(PROG)
uninstall:
-rm $(BINDIR)/$(PROG)
diff --git a/tulip/linux/main.c b/tulip/linux/main.c
index 97343a6a5..b8abd091b 100644
--- a/tulip/linux/main.c
+++ b/tulip/linux/main.c
@@ -44,7 +44,7 @@
#include "py/repl.h"
#include "py/gc.h"
#include "py/objstr.h"
-#include "py/stackctrl.h"
+#include "py/cstack.h"
#include "py/mphal.h"
#include "py/mpthread.h"
#include "extmod/misc.h"
@@ -53,23 +53,22 @@
#include "extmod/vfs_posix.h"
#include "genhdr/mpversion.h"
#include "input.h"
-#include "shared/runtime/pyexec.h"
#include "mpthreadport.h"
#include "display.h"
#include "alles.h"
#include "midi.h"
#include "sequencer.h"
+#include "shared/runtime/pyexec.h"
+
// Command line options, with their defaults
-STATIC bool compile_only = false;
-STATIC uint emit_opt = MP_EMIT_OPT_NONE;
+static bool compile_only = false;
+static uint emit_opt = MP_EMIT_OPT_NONE;
#if MICROPY_ENABLE_GC
// Heap size of GC heap (if enabled)
// Make it larger on a 64 bit machine, because pointers are larger.
-
-// TODO - make this equivalent always with Tulip CC
long heap_size = 4 * 1024 * 1024 * (sizeof(mp_uint_t) / 4);
#endif
@@ -78,7 +77,6 @@ long heap_size = 4 * 1024 * 1024 * (sizeof(mp_uint_t) / 4);
#define MICROPY_GC_SPLIT_HEAP_N_HEAPS (1)
#endif
-
#if !MICROPY_PY_SYS_PATH
#error "The unix port requires MICROPY_PY_SYS_PATH=1"
#endif
@@ -87,12 +85,13 @@ long heap_size = 4 * 1024 * 1024 * (sizeof(mp_uint_t) / 4);
#error "The unix port requires MICROPY_PY_SYS_ARGV=1"
#endif
-
-
extern int unix_display_draw();
extern void unix_display_init();
-STATIC void stderr_print_strn(void *env, const char *str, size_t len) {
+
+
+
+static void stderr_print_strn(void *env, const char *str, size_t len) {
(void)env;
ssize_t ret;
MP_HAL_RETRY_SYSCALL(ret, write(STDERR_FILENO, str, len), {});
@@ -104,12 +103,11 @@ STATIC void stderr_print_strn(void *env, const char *str, size_t len) {
const mp_print_t mp_stderr_print = {NULL, stderr_print_strn};
-
#define FORCED_EXIT (0x100)
// If exc is SystemExit, return value where FORCED_EXIT bit set,
// and lower 8 bits are SystemExit value. For all other exceptions,
// return 1.
-STATIC int handle_uncaught_exception(mp_obj_base_t *exc) {
+static int handle_uncaught_exception(mp_obj_base_t *exc) {
// check for SystemExit
if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {
// None is an exit value of 0; an int is its value; anything else is 1
@@ -134,7 +132,7 @@ STATIC int handle_uncaught_exception(mp_obj_base_t *exc) {
// Returns standard error codes: 0 for success, 1 for all other errors,
// except if FORCED_EXIT bit is set then script raised SystemExit and the
// value of the exit is in the lower 8 bits of the return value
-STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_input_kind_t input_kind, bool is_repl) {
+static int execute_from_lexer(int source_kind, const void *source, mp_parse_input_kind_t input_kind, bool is_repl) {
mp_hal_set_interrupt_char(CHAR_CTRL_C);
nlr_buf_t nlr;
@@ -148,7 +146,8 @@ STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu
const vstr_t *vstr = source;
lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, false);
} else if (source_kind == LEX_SRC_FILENAME) {
- lex = mp_lexer_new_from_file((const char *)source);
+ const char *filename = (const char *)source;
+ lex = mp_lexer_new_from_file(qstr_from_str(filename));
} else { // LEX_SRC_STDIN
lex = mp_lexer_new_from_fd(MP_QSTR__lt_stdin_gt_, 0, false);
}
@@ -195,7 +194,7 @@ STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu
#if MICROPY_USE_READLINE == 1
#include "shared/readline/readline.h"
#else
-STATIC char *strjoin(const char *s1, int sep_char, const char *s2) {
+static char *strjoin(const char *s1, int sep_char, const char *s2) {
int l1 = strlen(s1);
int l2 = strlen(s2);
char *s = malloc(l1 + l2 + 2);
@@ -210,11 +209,11 @@ STATIC char *strjoin(const char *s1, int sep_char, const char *s2) {
}
#endif
-STATIC int do_repl(void) {
+static int do_repl(void) {
mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION);
mp_hal_stdout_tx_str("; " MICROPY_BANNER_MACHINE);
- mp_hal_stdout_tx_str("\nType \"help()\" for more information.\n");
-
+ mp_hal_stdout_tx_str("\n");
+
#if MICROPY_USE_READLINE == 1
// use MicroPython supplied readline
@@ -315,24 +314,24 @@ STATIC int do_repl(void) {
}
int ret = execute_from_lexer(LEX_SRC_STR, line, MP_PARSE_SINGLE_INPUT, true);
+ free(line);
if (ret & FORCED_EXIT) {
return ret;
}
- free(line);
}
#endif
}
-STATIC int do_file(const char *file) {
+static int do_file(const char *file) {
return execute_from_lexer(LEX_SRC_FILENAME, file, MP_PARSE_FILE_INPUT, false);
}
-STATIC int do_str(const char *str) {
+static int do_str(const char *str) {
return execute_from_lexer(LEX_SRC_STR, str, MP_PARSE_FILE_INPUT, false);
}
-STATIC void print_help(char **argv) {
+static void print_help(char **argv) {
printf(
"usage: %s [] [-X ] [-c | -m | ]\n"
"Options:\n"
@@ -371,13 +370,13 @@ STATIC void print_help(char **argv) {
}
}
-STATIC int invalid_args(void) {
+static int invalid_args(void) {
fprintf(stderr, "Invalid command line arguments. Use -h option for help.\n");
return 1;
}
// Process options which set interpreter init options
-STATIC void pre_process_options(int argc, char **argv) {
+static void pre_process_options(int argc, char **argv) {
for (int a = 1; a < argc; a++) {
if (argv[a][0] == '-') {
if (strcmp(argv[a], "-c") == 0 || strcmp(argv[a], "-m") == 0) {
@@ -457,7 +456,7 @@ STATIC void pre_process_options(int argc, char **argv) {
}
}
-STATIC void set_sys_argv(char *argv[], int argc, int start_arg) {
+static void set_sys_argv(char *argv[], int argc, int start_arg) {
for (int i = start_arg; i < argc; i++) {
mp_obj_list_append(mp_sys_argv, MP_OBJ_NEW_QSTR(qstr_from_str(argv[i])));
}
@@ -465,9 +464,9 @@ STATIC void set_sys_argv(char *argv[], int argc, int start_arg) {
#if MICROPY_PY_SYS_EXECUTABLE
extern mp_obj_str_t mp_sys_executable_obj;
-STATIC char executable_path[MICROPY_ALLOC_PATH_MAX];
+static char executable_path[MICROPY_ALLOC_PATH_MAX];
-STATIC void sys_set_excecutable(char *argv0) {
+static void sys_set_excecutable(char *argv0) {
if (realpath(argv0, executable_path)) {
mp_obj_str_set_data(&mp_sys_executable_obj, (byte *)executable_path, strlen(executable_path));
}
@@ -481,10 +480,10 @@ STATIC void sys_set_excecutable(char *argv0) {
#endif
-extern int16_t amy_device_id;
-extern void setup_lvgl();
+extern int16_t amy_device_id;
+
/*
MP_NOINLINE int main_(int argc, char **argv);
@@ -492,27 +491,45 @@ int main(int argc, char **argv) {
#if MICROPY_PY_THREAD
mp_thread_init();
#endif
+
+ // Define a reasonable stack limit to detect stack overflow.
+ mp_uint_t stack_size = 40000 * (sizeof(void *) / 4);
+ #if defined(__arm__) && !defined(__thumb2__)
+ // ARM (non-Thumb) architectures require more stack.
+ stack_size *= 2;
+ #endif
+
// We should capture stack top ASAP after start, and it should be
// captured guaranteedly before any other stack variables are allocated.
// For this, actual main (renamed main_) should not be inlined into
// this function. main_() itself may have other functions inlined (with
// their own stack variables), that's why we need this main/main_ split.
- mp_stack_ctrl_init();
+ mp_cstack_init_with_sp_here(stack_size);
return main_(argc, argv);
}
*/
+extern void setup_lvgl();
MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
-#if MICROPY_PY_THREAD
+
+ #if MICROPY_PY_THREAD
mp_thread_init();
#endif
+
+ // Define a reasonable stack limit to detect stack overflow.
+ mp_uint_t stack_size = 40000 * (sizeof(void *) / 4);
+ #if defined(__arm__) && !defined(__thumb2__)
+ // ARM (non-Thumb) architectures require more stack.
+ stack_size *= 2;
+ #endif
+
// We should capture stack top ASAP after start, and it should be
// captured guaranteedly before any other stack variables are allocated.
// For this, actual main (renamed main_) should not be inlined into
// this function. main_() itself may have other functions inlined (with
// their own stack variables), that's why we need this main/main_ split.
- mp_stack_ctrl_init();
+ mp_cstack_init_with_sp_here(stack_size);
#ifdef SIGPIPE
@@ -529,17 +546,8 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);
#endif
- // Define a reasonable stack limit to detect stack overflow.
- mp_uint_t stack_limit = 40000 * (sizeof(void *) / 4);
- #if defined(__arm__) && !defined(__thumb2__)
- // ARM (non-Thumb) architectures require more stack.
- stack_limit *= 2;
- #endif
- mp_stack_set_limit(stack_limit);
-
-
- // pre_process_options(argc, argv);
+ //pre_process_options(argc, argv);
#if MICROPY_ENABLE_GC
#if !MICROPY_GC_SPLIT_HEAP
@@ -565,18 +573,15 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
mp_pystack_init(pystack, &pystack[MP_ARRAY_SIZE(pystack)]);
#endif
-
mp_init();
-
-
#if MICROPY_EMIT_NATIVE
// Set default emitter options
MP_STATE_VM(default_emit_opt) = emit_opt;
#else
(void)emit_opt;
#endif
-
+
setup_lvgl();
#if MICROPY_VFS_POSIX
@@ -590,6 +595,7 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
MP_STATE_VM(vfs_cur) = MP_STATE_VM(vfs_mount_table);
}
#endif
+
{
// sys.path starts as [""]
mp_sys_path = mp_obj_new_list(0, NULL);
@@ -605,7 +611,12 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
// First entry is empty. We've already added an empty entry to sys.path, so skip it.
++path;
}
- bool path_remaining = *path;
+ // GCC targeting RISC-V 64 reports a warning about `path_remaining` being clobbered by
+ // either setjmp or vfork if that variable it is allocated on the stack. This may
+ // probably be a compiler error as it occurs on a few recent GCC releases (up to 14.1.0)
+ // but LLVM doesn't report any warnings.
+ static bool path_remaining;
+ path_remaining = *path;
while (path_remaining) {
char *path_entry_end = strchr(path, PATHLIST_SEP_CHAR);
if (path_entry_end == NULL) {
@@ -626,7 +637,7 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
path = path_entry_end + 1;
}
}
-
+
mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
#if defined(MICROPY_UNIX_COVERAGE)
@@ -658,9 +669,11 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
printf(" peak %d\n", m_get_peak_bytes_allocated());
*/
- //#if MICROPY_PY_SYS_EXECUTABLE
- //sys_set_excecutable(argv[0]);
- //#endif
+ /*
+ #if MICROPY_PY_SYS_EXECUTABLE
+ sys_set_excecutable(argv[0]);
+ #endif
+ */
const int NOTHING_EXECUTED = -2;
int ret = NOTHING_EXECUTED;
@@ -683,7 +696,7 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
return invalid_args();
}
mp_obj_t import_args[4];
- import_args[0] = mp_obj_new_str(argv[a + 1], strlen(argv[a + 1]));
+ import_args[0] = mp_obj_new_str_from_cstr(argv[a + 1]);
import_args[1] = import_args[2] = mp_const_none;
// Ask __import__ to handle imported module specially - set its __name__
// to __main__, and also return this leaf module, not top-level package
@@ -713,7 +726,10 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
return handle_uncaught_exception(nlr.ret_val) & 0xff;
}
- if (mp_obj_is_package(mod) && !subpkg_tried) {
+ // If this module is a package, see if it has a `__main__.py`.
+ mp_obj_t dest[2];
+ mp_load_method_protected(mod, MP_QSTR___path__, dest, true);
+ if (dest[0] != MP_OBJ_NULL && !subpkg_tried) {
subpkg_tried = true;
vstr_t vstr;
int len = strlen(argv[a + 1]);
@@ -733,7 +749,7 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
mp_verbose_flag++;
#endif
} else if (strncmp(argv[a], "-O", 2) == 0) {
- if (mp_unichar_mp_isdigit(argv[a][2])) {
+ if (unichar_isdigit(argv[a][2])) {
MP_STATE_VM(mp_optimise_value) = argv[a][2] & 0xf;
} else {
MP_STATE_VM(mp_optimise_value) = 0;
@@ -756,7 +772,7 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
// Set base dir of the script as first entry in sys.path.
char *p = strrchr(basedir, '/');
- path_items[0] = mp_obj_new_str_via_qstr(basedir, p - basedir);
+ mp_obj_list_store(mp_sys_path, MP_OBJ_NEW_SMALL_INT(0), mp_obj_new_str_via_qstr(basedir, p - basedir));
free(pathbuf);
set_sys_argv(argv, argc, a);
@@ -764,11 +780,13 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
break;
}
}
+
+ const char *inspect_env = getenv("MICROPYINSPECT");
+ if (inspect_env && inspect_env[0] != '\0') {
+ inspect = true;
+ }
*/
- //const char *inspect_env = getenv("MICROPYINSPECT");
- //if (inspect_env && inspect_env[0] != '\0') {
- // inspect = true;
- //}
+
inspect = true;
pyexec_frozen_module("_boot.py", false);
pyexec_file_if_exists("boot.py");
@@ -840,6 +858,12 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
return 0;
}
+
+
+extern int8_t unix_display_flag;
+
+#include "lvgl.h"
+
int main(int argc, char **argv) {
// Get the resources folder loc
// So thread out alles and then micropython tasks
@@ -877,13 +901,12 @@ int main(int argc, char **argv) {
unix_display_init();
pthread_t alles_thread_id;
pthread_create(&alles_thread_id, NULL, alles_start, NULL);
-
- //pthread_t midi_thread_id;
- ///pthread_create(&midi_thread_id, NULL, run_midi, NULL);
-
+ /*
+ pthread_t midi_thread_id;
+ pthread_create(&midi_thread_id, NULL, run_midi, NULL);
+ */
pthread_t mp_thread_id;
pthread_create(&mp_thread_id, NULL, main_, NULL);
- int c = 0;
sequencer_init();
pthread_t sequencer_thread_id;
@@ -891,30 +914,30 @@ int main(int argc, char **argv) {
delay_ms(100);
// Schedule a "turning on" sound
- bleep();
-
-
-display_jump:
- while(c>=0) {
- // unix_display_draw returns -1 if the window was quit
- c = unix_display_draw();
- if(c>=0) {
- // Figure out how long to sleep. ticks has the amount of time already spent for this frame
- // so let's fill in the rest with a usleep.
- int sleep_ms_for_frame = (int) ((1000.0/TARGET_DESKTOP_FPS) - c);
- if(sleep_ms_for_frame > 0) usleep(1000*sleep_ms_for_frame);
- }
+
+
+display_jump:
+
+ while(unix_display_flag>=0) {
+ int ticks = unix_display_draw();
+ // Figure out how long to sleep. ticks has the amount of time already spent for this frame
+ // so let's fill in the rest with a usleep.
+ int sleep_ms_for_frame = (int) ((1000.0/TARGET_DESKTOP_FPS) - ticks);
+ if(sleep_ms_for_frame > 0) usleep(1000*sleep_ms_for_frame);
}
- if(c==-2) {
+ if(unix_display_flag==-2) {
+ fprintf(stderr,"restarting display\n");
// signal to restart display after a timing change
+
unix_display_init();
- c=0;
+ unix_display_flag = 0;
goto display_jump;
}
+
// We're done. join the threads?
+ return 0;
}
-
void nlr_jump_fail(void *val) {
#if MICROPY_USE_READLINE == 1
mp_hal_stdio_mode_orig();
diff --git a/tulip/linux/mpconfigport.h b/tulip/linux/mpconfigport.h
index 2de064871..165278606 100644
--- a/tulip/linux/mpconfigport.h
+++ b/tulip/linux/mpconfigport.h
@@ -34,8 +34,15 @@
// Variant-specific definitions.
#include "mpconfigvariant.h"
+
+
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "tulip"
+#undef MICROPY_MALLOC_USES_ALLOCATED_SIZE
+#undef MICROPY_MEM_STATS
+#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (0)
+#define MICROPY_MEM_STATS (0)
+
// Tulip stuff -- move to mpconfigtulip.h ?
#define MICROPY_PY_IO (1)
#define MICROPY_PY_SYS_STDFILES (0)
@@ -43,7 +50,6 @@
#define MICROPY_HW_BOARD_NAME "Tulip4"
-
#ifndef MICROPY_CONFIG_ROM_LEVEL
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES)
#endif
@@ -79,25 +85,6 @@
#define MICROPY_EMIT_ARM (1)
#endif
-
-#ifdef MICROPY_MALLOC_USES_ALLOCATED_SIZE
-#undef MICROPY_MALLOC_USES_ALLOCATED_SIZE
-#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (0)
-#undef MICROPY_MEM_STATS
-#define MICROPY_MEM_STATS (0)
-#endif
-
-// If enabled, configure how to seed random on init.
-#ifdef MICROPY_PY_RANDOM_SEED_INIT_FUNC
-#include
-void mp_hal_get_random(size_t n, void *buf);
-static inline unsigned long mp_random_seed_init(void) {
- unsigned long r;
- mp_hal_get_random(sizeof(r), &r);
- return r;
-}
-#endif
-
// Type definitions for the specific machine based on the word size.
#ifndef MICROPY_OBJ_REPR
#ifdef __LP64__
@@ -133,7 +120,7 @@ typedef long mp_off_t;
// Always enable GC.
#define MICROPY_ENABLE_GC (1)
-#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
+#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__) || (defined(__riscv) && (__riscv_xlen == 64)))
// Fall back to setjmp() implementation for discovery of GC pointers in registers.
#define MICROPY_GCREGS_SETJMP (1)
#endif
@@ -145,8 +132,8 @@ typedef long mp_off_t;
#define MICROPY_HELPER_LEXER_UNIX (1)
#define MICROPY_VFS_POSIX (1)
#define MICROPY_READER_POSIX (1)
-#ifndef MICROPY_TRACKED_ALLOC
-#define MICROPY_TRACKED_ALLOC (MICROPY_BLUETOOTH_BTSTACK)
+#if MICROPY_PY_FFI || MICROPY_BLUETOOTH_BTSTACK
+#define MICROPY_TRACKED_ALLOC (1)
#endif
// VFS stat functions should return time values relative to 1970/1/1
@@ -162,12 +149,8 @@ typedef long mp_off_t;
#define MICROPY_STACKLESS_STRICT (0)
#endif
-// If settrace is enabled then we need code saving.
-#if MICROPY_PY_SYS_SETTRACE
-#define MICROPY_PERSISTENT_CODE_SAVE (1)
-#define MICROPY_COMP_CONST (0)
-#endif
-
+// Implementation of the machine module.
+#define MICROPY_PY_MACHINE_INCLUDEFILE "../../micropython/ports/unix/modmachine.c"
// Unix-specific configuration of machine.mem*.
#define MICROPY_MACHINE_MEM_GET_READ_ADDR mod_machine_mem_get_addr
@@ -183,13 +166,13 @@ typedef long mp_off_t;
// Ensure builtinimport.c works with -m.
#define MICROPY_MODULE_OVERRIDE_MAIN_IMPORT (1)
-// Don't default sys.argv because we do that in main.
+// Don't default sys.argv and sys.path because we do that in main.
#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (0)
// Enable sys.executable.
#define MICROPY_PY_SYS_EXECUTABLE (1)
-#define MICROPY_PY_USOCKET_LISTEN_BACKLOG_DEFAULT (SOMAXCONN < 128 ? SOMAXCONN : 128)
+#define MICROPY_PY_SOCKET_LISTEN_BACKLOG_DEFAULT (SOMAXCONN < 128 ? SOMAXCONN : 128)
// Bare-metal ports don't have stderr. Printing debug to stderr may give tests
// which check stdout a chance to pass, etc.
@@ -200,20 +183,14 @@ extern const struct _mp_print_t mp_stderr_print;
// For the native emitter configure how to mark a region as executable.
void mp_unix_alloc_exec(size_t min_size, void **ptr, size_t *size);
void mp_unix_free_exec(void *ptr, size_t size);
-void mp_unix_mark_exec(void);
#define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) mp_unix_alloc_exec(min_size, ptr, size)
#define MP_PLAT_FREE_EXEC(ptr, size) mp_unix_free_exec(ptr, size)
-#ifndef MICROPY_FORCE_PLAT_ALLOC_EXEC
-// Use MP_PLAT_ALLOC_EXEC for any executable memory allocation, including for FFI
-// (overriding libffi own implementation)
-#define MICROPY_FORCE_PLAT_ALLOC_EXEC (1)
-#endif
// If enabled, configure how to seed random on init.
-#ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC
+#ifdef MICROPY_PY_RANDOM_SEED_INIT_FUNC
#include
void mp_hal_get_random(size_t n, void *buf);
-static inline unsigned long mp_urandom_seed_init(void) {
+static inline unsigned long mp_random_seed_init(void) {
unsigned long r;
mp_hal_get_random(sizeof(r), &r);
return r;
@@ -253,6 +230,7 @@ static inline unsigned long mp_urandom_seed_init(void) {
#include
#endif
+
// If threading is enabled, configure the atomic section.
#if MICROPY_PY_THREAD
#define MICROPY_BEGIN_ATOMIC_SECTION() (mp_thread_unix_begin_atomic_section(), 0xffffffff)
diff --git a/tulip/linux/mpconfigport.mk b/tulip/linux/mpconfigport.mk
new file mode 100644
index 000000000..b0695760b
--- /dev/null
+++ b/tulip/linux/mpconfigport.mk
@@ -0,0 +1,46 @@
+# Enable/disable modules and 3rd-party libs to be included in interpreter
+
+# Build 32-bit binaries on a 64-bit host
+MICROPY_FORCE_32BIT = 0
+
+# This variable can take the following values:
+# 0 - no readline, just simple stdin input
+# 1 - use MicroPython version of readline
+MICROPY_USE_READLINE = 1
+
+# btree module using Berkeley DB 1.xx
+MICROPY_PY_BTREE = 1
+
+# _thread module using pthreads
+MICROPY_PY_THREAD = 1
+
+# Subset of CPython termios module
+MICROPY_PY_TERMIOS = 1
+
+# Subset of CPython socket module
+MICROPY_PY_SOCKET = 1
+
+# ffi module requires libffi (libffi-dev Debian package)
+MICROPY_PY_FFI = 0
+
+# ssl module requires one of the TLS libraries below
+MICROPY_PY_SSL = 1
+# axTLS has minimal size but implements only a subset of modern TLS
+# functionality, so may have problems with some servers.
+MICROPY_SSL_AXTLS = 0
+# mbedTLS is more up to date and complete implementation, but also
+# more bloated.
+MICROPY_SSL_MBEDTLS = 1
+
+# jni module requires JVM/JNI
+MICROPY_PY_JNI = 0
+
+# Avoid using system libraries, use copies bundled with MicroPython
+# as submodules (currently affects only libffi).
+MICROPY_STANDALONE ?= 0
+
+MICROPY_ROM_TEXT_COMPRESSION = 1
+
+MICROPY_VFS_FAT = 1
+MICROPY_VFS_LFS1 = 1
+MICROPY_VFS_LFS2 = 1
diff --git a/tulip/macos/Makefile b/tulip/macos/Makefile
index 4569a6279..cea92c985 100644
--- a/tulip/macos/Makefile
+++ b/tulip/macos/Makefile
@@ -1,20 +1,14 @@
+# Tulip macos makefile, based on Micropython unix port makefile
+
WHICH_ARCH ?= $(shell arch)
+DEBUG=1
ifeq ($(WHICH_ARCH), arm64)
ARCHFLAGS = -target arm64-macos11
HOMEBREW = /opt/homebrew
else
ARCHFLAGS = -target x86_64-apple-macos10.15
- # On x86, homebrew FFI seems to have two locations
- # /usr/local/homebrew/opt/libffi/include/ffi.h
- # /usr/local/opt/libffi/include/ffi.h
- # Check which it is
- ifneq ("$(wildcard /usr/local/opt/libffi/include/ffi.h)","")
- HOMEBREW = /usr/local
- else
- HOMEBREW = /usr/local/homebrew
- endif
endif
# Select the variant to build for.
@@ -31,12 +25,15 @@ TOP = ../../micropython
VARIANT_DIR ?= ../../micropython/ports/unix/variants/$(VARIANT)
+# If the build directory is not given, make it reflect the variant name.
+BUILD ?= build-$(VARIANT)
+
include $(TOP)/py/mkenv.mk
-include ../shared/desktop/mpconfigport.mk
-include $(VARIANT_DIR)/mpconfigvariant.mk
+include mpconfigport.mk
+#include $(VARIANT_DIR)/mpconfigvariant.mk
# Use the default frozen manifest, variants may override this.
-FROZEN_MANIFEST ?= manifest.py
+FROZEN_MANIFEST ?= variants/manifest.py
# This should be configured by the mpconfigvariant.mk
PROG = tulip.$(WHICH_ARCH)
@@ -65,7 +62,10 @@ LVGL_MPY_METADATA = $(BUILD)/lvgl/lv_mpy.json
QSTR_GLOBAL_DEPENDENCIES += $(LVGL_MPY)
CFLAGS_MOD += $(LV_CFLAGS)
SRC_C += $(shell find $(LVGL_DIR)/src -type f -name '*.c')
-CFLAGS += -DLV_CONF_INCLUDE_SIMPLE
+CFLAGS += -DLV_CONF_INCLUDE_SIMPLE
+
+# This is for the lvgl stuff that uses STATIC
+CFLAGS += -DSTATIC=static
$(LVGL_MPY): $(ALL_LVGL_SRC) $(LVGL_BINDING_DIR)/gen/gen_mpy.py
$(ECHO) "LVGL-GEN $@"
@@ -88,14 +88,22 @@ INC += -I$(TOP)/../lv_binding_micropython_tulip/lvgl/src/libs/lodepng
INC += -I./SDL2.framework/Headers
+
+GIT_SUBMODULES += lib/berkeley-db-1.xx
+
+INC += -I.
+INC += -I$(TOP)
+INC += -I$(BUILD)
+
+# compiler settings
+
# compiler settings
CWARN = -Wall -Werror
CWARN += -Wextra -Wno-unused-parameter -Wno-unused-but-set-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion -Wno-missing-declarations -Wno-unused-but-set-variable -Wno-sign-compare -Wno-gnu-variable-sized-type-not-at-end -Wno-undefined-internal
CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA)
CFLAGS += -DTULIP_DESKTOP -DMACOS
-#CFLAGS += -DAMY_DEBUG
-
CFLAGS += $(ARCHFLAGS)
+
# Debugging/Optimization
ifdef DEBUG
#COPT ?= -Og
@@ -107,8 +115,9 @@ endif
# Remove unused sections.
COPT += -fdata-sections -ffunction-sections -O0
-# Always enable symbols -- They're occasionally useful, and don't make it into the
-# final .bin/.hex/.dfu so the extra size doesn't matter.
+
+# Note: Symbols and debug information will still be stripped from the final binary
+# unless "DEBUG=1" or "STRIP=" is passed to make, see README.md for details.
CFLAGS += -g
ifndef DEBUG
@@ -153,7 +162,7 @@ endif
LDFLAGS_ARCH = -Wl,-map,$@.map -Wl,-dead_strip
else
# Use gcc syntax for map file
-LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref -Wl,--gc-sections
+LDFLAGS_ARCH = -Wl,-Map=$@.map,--cref -Wl,--gc-sections
endif
LDFLAGS += $(LDFLAGS_MOD) $(LDFLAGS_ARCH) -lm $(LDFLAGS_EXTRA)
LDFLAGS += -F. -framework SDL2 -framework CoreFoundation -framework CoreMIDI -framework AudioToolbox -framework CoreAudio -framework Cocoa -lstdc++ $(ARCHFLAGS)
@@ -167,80 +176,101 @@ ifeq ($(MICROPY_FORCE_32BIT),1)
# starting with linux-libc-dev:i386
ifeq ($(MICROPY_PY_FFI),1)
ifeq ($(UNAME_S),Linux)
-CFLAGS_MOD += -I/usr/include/i686-linux-gnu
+CFLAGS += -I/usr/include/i686-linux-gnu
endif
endif
endif
ifeq ($(MICROPY_USE_READLINE),1)
INC += -I$(TOP)/shared/readline
-CFLAGS_MOD += -DMICROPY_USE_READLINE=1
+CFLAGS += -DMICROPY_USE_READLINE=1
SHARED_SRC_C_EXTRA += readline/readline.c
endif
ifeq ($(MICROPY_PY_TERMIOS),1)
-CFLAGS_MOD += -DMICROPY_PY_TERMIOS=1
-SRC_MOD += $(MICROPY_PORT_DIR)/modtermios.c
+CFLAGS += -DMICROPY_PY_TERMIOS=1
endif
ifeq ($(MICROPY_PY_SOCKET),1)
-CFLAGS_MOD += -DMICROPY_PY_SOCKET=1
+CFLAGS += -DMICROPY_PY_SOCKET=1
SRC_MOD += $(MICROPY_PORT_DIR)/modsocket.c
endif
ifeq ($(MICROPY_PY_THREAD),1)
-CFLAGS_MOD += -DMICROPY_PY_THREAD=1 -DMICROPY_PY_THREAD_GIL=0
-LDFLAGS_MOD += $(LIBPTHREAD)
+CFLAGS += -DMICROPY_PY_THREAD=1 -DMICROPY_PY_THREAD_GIL=0
+LDFLAGS += $(LIBPTHREAD)
endif
+
include ../shared/tulip.mk
MICROPY_PORT_DIR=../../micropython/ports/unix
+ifeq ($(MICROPY_PY_SSL),1)
+ifeq ($(MICROPY_SSL_AXTLS),1)
+
+endif
+endif
+
+# If the variant enables it, enable modbluetooth.
+ifeq ($(MICROPY_PY_BLUETOOTH),1)
+ifeq ($(MICROPY_BLUETOOTH_BTSTACK),1)
+HAVE_LIBUSB := $(shell (which pkg-config > /dev/null && pkg-config --exists libusb-1.0) 2>/dev/null && echo '1')
+
+# Figure out which BTstack transport to use.
+ifeq ($(HAVE_LIBUSB),1)
+# Default to btstack-over-usb.
+MICROPY_BLUETOOTH_BTSTACK_USB ?= 1
+else
+# Fallback to HCI controller via a H4 UART (e.g. Zephyr on nRF) over a /dev/tty serial port.
+MICROPY_BLUETOOTH_BTSTACK_H4 ?= 1
+endif
+
+SRC_BTSTACK_C += lib/btstack/platform/embedded/btstack_run_loop_embedded.c
+endif
+endif
+
ifeq ($(MICROPY_PY_FFI),1)
ifeq ($(MICROPY_STANDALONE),1)
-LIBFFI_CFLAGS_MOD := -I$(shell ls -1d $(BUILD)/lib/libffi/out/lib/libffi-*/include)
+# Build libffi from source.
+GIT_SUBMODULES += lib/libffi
+DEPLIBS += libffi
+LIBFFI_CFLAGS := -I$(shell ls -1d $(BUILD)/lib/libffi/include)
ifeq ($(MICROPY_FORCE_32BIT),1)
- LIBFFI_LDFLAGS_MOD = $(BUILD)/lib/libffi/out/lib32/libffi.a
+ LIBFFI_LDFLAGS = $(BUILD)/lib/libffi/out/lib32/libffi.a
else
- LIBFFI_LDFLAGS_MOD = $(BUILD)/lib/libffi/out/lib/libffi.a
+ LIBFFI_LDFLAGS = $(BUILD)/lib/libffi/out/lib/libffi.a
endif
else
-LIBFFI_CFLAGS_MOD := $(shell pkg-config --cflags libffi)
-LIBFFI_LDFLAGS_MOD := $(shell pkg-config --libs libffi)
+# Use system version of libffi.
+LIBFFI_CFLAGS := $(shell pkg-config --cflags libffi)
+LIBFFI_LDFLAGS := $(shell pkg-config --libs libffi)
endif
-
-# libffi is installed in system on 10.12, so force use of homebrew version
-LIBFFI_LDFLAGS_MOD = $(HOMEBREW)/opt/libffi/lib/libffi.a
-LIBFFI_CFLAGS_MOD := -I$(HOMEBREW)/opt/libffi/include
-
-
ifeq ($(UNAME_S),Linux)
-LIBFFI_LDFLAGS_MOD += -ldl
+LIBFFI_LDFLAGS += -ldl
endif
-CFLAGS_MOD += $(LIBFFI_CFLAGS_MOD) -DMICROPY_PY_FFI=1
-LDFLAGS_MOD += $(LIBFFI_LDFLAGS_MOD)
-SRC_MOD += $(MICROPY_PORT_DIR)/modffi.c
+CFLAGS += $(LIBFFI_CFLAGS) -DMICROPY_PY_FFI=1
+LDFLAGS += $(LIBFFI_LDFLAGS)
endif
ifeq ($(MICROPY_PY_JNI),1)
# Path for 64-bit OpenJDK, should be adjusted for other JDKs
-CFLAGS_MOD += -I/usr/lib/jvm/java-7-openjdk-amd64/include -DMICROPY_PY_JNI=1
-SRC_MOD += $(MICROPY_PORT_DIR)/modjni.c
+CFLAGS += -I/usr/lib/jvm/java-7-openjdk-amd64/include -DMICROPY_PY_JNI=1
endif
+
+
# source files
SRC_C += \
main.c \
- ../shared/desktop/unix_mphal.c \
../shared/desktop/unix_display.c \
../shared/desktop/multicast.c \
- ../shared/desktop/mpthreadport.c \
+ ../shared/desktop/unix_mphal.c \
../../amy/src/libminiaudio-audio.c \
+ $(MICROPY_PORT_DIR)/mpthreadport.c \
$(MICROPY_PORT_DIR)/gccollect.c \
$(MICROPY_PORT_DIR)/input.c \
- $(MICROPY_PORT_DIR)/modselect.c \
$(MICROPY_PORT_DIR)/alloc.c \
$(MICROPY_PORT_DIR)/fatfs_port.c \
$(MICROPY_PORT_DIR)/mpbthciport.c \
@@ -277,21 +307,16 @@ OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(EXTMOD_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
+
+
# List of sources for qstr extraction
SRC_QSTR += $(SRC_C) $(SRC_CXX) $(SHARED_SRC_C) $(EXTMOD_SRC_C)
-# Append any auto-generated sources that are needed by sources listed in
-# SRC_QSTR
-SRC_QSTR_AUTO_DEPS +=
ifneq ($(FROZEN_MANIFEST),)
-# To use frozen code create a manifest.py file with a description of files to
-# freeze, then invoke make with FROZEN_MANIFEST=manifest.py (be sure to build from scratch).
-CFLAGS += -DMICROPY_QSTR_EXTRA_POOL=mp_qstr_frozen_const_pool
-CFLAGS += -DMICROPY_MODULE_FROZEN_MPY
CFLAGS += -DMPZ_DIG_SIZE=16 # force 16 bits to work on both 32 and 64 bit archs
-CFLAGS += -DMICROPY_MODULE_FROZEN_STR
endif
+
CPU_BRAND_NAME=`sysctl -n machdep.cpu.brand_string`
CFLAGS += -DMICROPY_HW_MCU_NAME="\"$(CPU_BRAND_NAME)\""
CFLAGS += -Wno-double-promotion -Wno-unused-function -Wno-unused-variable
@@ -314,19 +339,24 @@ endif
include $(TOP)/py/mkrules.mk
-#undefine compile_c
+.PHONY: test test_full
+
+test: $(BUILD)/$(PROG) $(TOP)/tests/run-tests.py
+ $(eval DIRNAME=ports/$(notdir $(CURDIR)))
+ cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py
+
+test_full: $(BUILD)/$(PROG) $(TOP)/tests/run-tests.py
+ $(eval DIRNAME=ports/$(notdir $(CURDIR)))
+ cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py
+ cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py -d thread
+ cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py --emit native
+ cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py --via-mpy $(RUN_TESTS_MPY_CROSS_FLAGS) -d basics float micropython
+ cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py --via-mpy $(RUN_TESTS_MPY_CROSS_FLAGS) --emit native -d basics float micropython
+ cat $(TOP)/tests/basics/0prelim.py | ./$(BUILD)/$(PROG) | grep -q 'abc'
-define compile_c
-$(ECHO) "CC $<"
-$(Q)$(CC) $(CFLAGS) -c -MD -o $@ $< || (echo -e $(HELP_BUILD_ERROR); false)
-@# The following fixes the dependency file.
-@# See http://make.paulandlesley.org/autodep.html for details.
-@# Regex adjusted from the above to play better with Windows paths, etc.
-@$(CP) $(@:.o=.d) $(@:.o=.P); \
- $(SED) -e 's/#.*//' -e 's/^.*: *//' -e 's/ *\\$$//' \
- -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \
- $(RM) -f $(@:.o=.d)
-endef
+test_gcov: test_full
+ gcov -o $(BUILD)/py $(TOP)/py/*.c
+ gcov -o $(BUILD)/extmod $(TOP)/extmod/*.c
$(BUILD)/%.o: %.m
$(ECHO) "M $<"
@@ -340,7 +370,7 @@ else
CROSS_COMPILE_HOST =
endif
-deplibs: libffi axtls
+deplibs: $(DEPLIBS)
libffi: $(BUILD)/lib/libffi/include/ffi.h
@@ -351,15 +381,15 @@ $(TOP)/lib/libffi/configure: $(TOP)/lib/libffi/autogen.sh
# docs and depending on makeinfo
$(BUILD)/lib/libffi/include/ffi.h: $(TOP)/lib/libffi/configure
mkdir -p $(BUILD)/lib/libffi; cd $(BUILD)/lib/libffi; \
- $(abspath $(TOP))/lib/libffi/configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out --disable-structs CC="$(CC)" CXX="$(CXX)" LD="$(LD)" CFLAGS="-Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions"; \
+ $(abspath $(TOP))/lib/libffi/configure $(CROSS_COMPILE_HOST) --prefix=$$PWD/out --disable-shared --disable-structs CC="$(CC)" CXX="$(CXX)" LD="$(LD)" CFLAGS="-Os -fomit-frame-pointer -fstrict-aliasing -ffast-math -fno-exceptions"; \
$(MAKE) install-exec-recursive; $(MAKE) -C include install-data-am
PREFIX = /usr/local
BINDIR = $(DESTDIR)$(PREFIX)/bin
-install: $(PROG)
+install: $(BUILD)/$(PROG)
install -d $(BINDIR)
- install $(PROG) $(BINDIR)/$(PROG)
+ install $(BUILD)/$(PROG) $(BINDIR)/$(PROG)
uninstall:
-rm $(BINDIR)/$(PROG)
diff --git a/tulip/macos/main.c b/tulip/macos/main.c
index f8e01360a..343f05f90 100644
--- a/tulip/macos/main.c
+++ b/tulip/macos/main.c
@@ -44,7 +44,7 @@
#include "py/repl.h"
#include "py/gc.h"
#include "py/objstr.h"
-#include "py/stackctrl.h"
+#include "py/cstack.h"
#include "py/mphal.h"
#include "py/mpthread.h"
#include "extmod/misc.h"
@@ -53,22 +53,22 @@
#include "extmod/vfs_posix.h"
#include "genhdr/mpversion.h"
#include "input.h"
-#include "shared/runtime/pyexec.h"
#include "mpthreadport.h"
#include "display.h"
#include "alles.h"
#include "midi.h"
#include "sequencer.h"
+#include "shared/runtime/pyexec.h"
+
+
// Command line options, with their defaults
-STATIC bool compile_only = false;
-STATIC uint emit_opt = MP_EMIT_OPT_NONE;
+static bool compile_only = false;
+static uint emit_opt = MP_EMIT_OPT_NONE;
#if MICROPY_ENABLE_GC
// Heap size of GC heap (if enabled)
// Make it larger on a 64 bit machine, because pointers are larger.
-
-// TODO - make this equivalent always with Tulip CC
long heap_size = 4 * 1024 * 1024 * (sizeof(mp_uint_t) / 4);
#endif
@@ -77,7 +77,6 @@ long heap_size = 4 * 1024 * 1024 * (sizeof(mp_uint_t) / 4);
#define MICROPY_GC_SPLIT_HEAP_N_HEAPS (1)
#endif
-
#if !MICROPY_PY_SYS_PATH
#error "The unix port requires MICROPY_PY_SYS_PATH=1"
#endif
@@ -86,32 +85,13 @@ long heap_size = 4 * 1024 * 1024 * (sizeof(mp_uint_t) / 4);
#error "The unix port requires MICROPY_PY_SYS_ARGV=1"
#endif
-
-
extern int unix_display_draw();
extern void unix_display_init();
-/*
-extern void mp_uos_dupterm_tx_strn(const char *str, size_t len);
-void display_print_strn(void *env, const char *str, size_t len) {
- (void)env;
- if(len) {
- display_tfb_str((unsigned char*)str, len, 0, tfb_fg_pal_color, tfb_bg_pal_color);
- }
-}
-STATIC void stderr_print_strn(void *env, const char *str, size_t len) {
- (void)env;
- ssize_t ret;
- MP_HAL_RETRY_SYSCALL(ret, write(STDERR_FILENO, str, len), {});
- mp_uos_dupterm_tx_strn(str, len);
-}
-*/
-
-
-STATIC void stderr_print_strn(void *env, const char *str, size_t len) {
+static void stderr_print_strn(void *env, const char *str, size_t len) {
(void)env;
ssize_t ret;
MP_HAL_RETRY_SYSCALL(ret, write(STDERR_FILENO, str, len), {});
@@ -123,18 +103,11 @@ STATIC void stderr_print_strn(void *env, const char *str, size_t len) {
const mp_print_t mp_stderr_print = {NULL, stderr_print_strn};
-/*
-const mp_print_t mp_stderr_print = {NULL, display_print_strn};
-const mp_print_t mp_stdout_print = {NULL, display_print_strn};
-const mp_print_t mp_sys_stdout_print = {NULL, display_print_strn};
-const mp_print_t mp_display_print = {NULL, display_print_strn};
-*/
-
#define FORCED_EXIT (0x100)
// If exc is SystemExit, return value where FORCED_EXIT bit set,
// and lower 8 bits are SystemExit value. For all other exceptions,
// return 1.
-STATIC int handle_uncaught_exception(mp_obj_base_t *exc) {
+static int handle_uncaught_exception(mp_obj_base_t *exc) {
// check for SystemExit
if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {
// None is an exit value of 0; an int is its value; anything else is 1
@@ -159,7 +132,7 @@ STATIC int handle_uncaught_exception(mp_obj_base_t *exc) {
// Returns standard error codes: 0 for success, 1 for all other errors,
// except if FORCED_EXIT bit is set then script raised SystemExit and the
// value of the exit is in the lower 8 bits of the return value
-STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_input_kind_t input_kind, bool is_repl) {
+static int execute_from_lexer(int source_kind, const void *source, mp_parse_input_kind_t input_kind, bool is_repl) {
mp_hal_set_interrupt_char(CHAR_CTRL_C);
nlr_buf_t nlr;
@@ -173,7 +146,8 @@ STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu
const vstr_t *vstr = source;
lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, false);
} else if (source_kind == LEX_SRC_FILENAME) {
- lex = mp_lexer_new_from_file((const char *)source);
+ const char *filename = (const char *)source;
+ lex = mp_lexer_new_from_file(qstr_from_str(filename));
} else { // LEX_SRC_STDIN
lex = mp_lexer_new_from_fd(MP_QSTR__lt_stdin_gt_, 0, false);
}
@@ -220,7 +194,7 @@ STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu
#if MICROPY_USE_READLINE == 1
#include "shared/readline/readline.h"
#else
-STATIC char *strjoin(const char *s1, int sep_char, const char *s2) {
+static char *strjoin(const char *s1, int sep_char, const char *s2) {
int l1 = strlen(s1);
int l2 = strlen(s2);
char *s = malloc(l1 + l2 + 2);
@@ -235,11 +209,11 @@ STATIC char *strjoin(const char *s1, int sep_char, const char *s2) {
}
#endif
-STATIC int do_repl(void) {
+static int do_repl(void) {
mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION);
mp_hal_stdout_tx_str("; " MICROPY_BANNER_MACHINE);
- mp_hal_stdout_tx_str("\nType \"help()\" for more information.\n");
-
+ mp_hal_stdout_tx_str("\n");
+
#if MICROPY_USE_READLINE == 1
// use MicroPython supplied readline
@@ -340,24 +314,24 @@ STATIC int do_repl(void) {
}
int ret = execute_from_lexer(LEX_SRC_STR, line, MP_PARSE_SINGLE_INPUT, true);
+ free(line);
if (ret & FORCED_EXIT) {
return ret;
}
- free(line);
}
#endif
}
-STATIC int do_file(const char *file) {
+static int do_file(const char *file) {
return execute_from_lexer(LEX_SRC_FILENAME, file, MP_PARSE_FILE_INPUT, false);
}
-STATIC int do_str(const char *str) {
+static int do_str(const char *str) {
return execute_from_lexer(LEX_SRC_STR, str, MP_PARSE_FILE_INPUT, false);
}
-STATIC void print_help(char **argv) {
+static void print_help(char **argv) {
printf(
"usage: %s [] [-X ] [-c | -m | ]\n"
"Options:\n"
@@ -396,13 +370,13 @@ STATIC void print_help(char **argv) {
}
}
-STATIC int invalid_args(void) {
+static int invalid_args(void) {
fprintf(stderr, "Invalid command line arguments. Use -h option for help.\n");
return 1;
}
// Process options which set interpreter init options
-STATIC void pre_process_options(int argc, char **argv) {
+static void pre_process_options(int argc, char **argv) {
for (int a = 1; a < argc; a++) {
if (argv[a][0] == '-') {
if (strcmp(argv[a], "-c") == 0 || strcmp(argv[a], "-m") == 0) {
@@ -482,7 +456,7 @@ STATIC void pre_process_options(int argc, char **argv) {
}
}
-STATIC void set_sys_argv(char *argv[], int argc, int start_arg) {
+static void set_sys_argv(char *argv[], int argc, int start_arg) {
for (int i = start_arg; i < argc; i++) {
mp_obj_list_append(mp_sys_argv, MP_OBJ_NEW_QSTR(qstr_from_str(argv[i])));
}
@@ -490,9 +464,9 @@ STATIC void set_sys_argv(char *argv[], int argc, int start_arg) {
#if MICROPY_PY_SYS_EXECUTABLE
extern mp_obj_str_t mp_sys_executable_obj;
-STATIC char executable_path[MICROPY_ALLOC_PATH_MAX];
+static char executable_path[MICROPY_ALLOC_PATH_MAX];
-STATIC void sys_set_excecutable(char *argv0) {
+static void sys_set_excecutable(char *argv0) {
if (realpath(argv0, executable_path)) {
mp_obj_str_set_data(&mp_sys_executable_obj, (byte *)executable_path, strlen(executable_path));
}
@@ -542,7 +516,6 @@ char * get_tulip_home_path() {
extern int16_t amy_device_id;
-
/*
MP_NOINLINE int main_(int argc, char **argv);
@@ -550,12 +523,20 @@ int main(int argc, char **argv) {
#if MICROPY_PY_THREAD
mp_thread_init();
#endif
+
+ // Define a reasonable stack limit to detect stack overflow.
+ mp_uint_t stack_size = 40000 * (sizeof(void *) / 4);
+ #if defined(__arm__) && !defined(__thumb2__)
+ // ARM (non-Thumb) architectures require more stack.
+ stack_size *= 2;
+ #endif
+
// We should capture stack top ASAP after start, and it should be
// captured guaranteedly before any other stack variables are allocated.
// For this, actual main (renamed main_) should not be inlined into
// this function. main_() itself may have other functions inlined (with
// their own stack variables), that's why we need this main/main_ split.
- mp_stack_ctrl_init();
+ mp_cstack_init_with_sp_here(stack_size);
return main_(argc, argv);
}
*/
@@ -567,12 +548,20 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
#if MICROPY_PY_THREAD
mp_thread_init();
#endif
+
+ // Define a reasonable stack limit to detect stack overflow.
+ mp_uint_t stack_size = 40000 * (sizeof(void *) / 4);
+ #if defined(__arm__) && !defined(__thumb2__)
+ // ARM (non-Thumb) architectures require more stack.
+ stack_size *= 2;
+ #endif
+
// We should capture stack top ASAP after start, and it should be
// captured guaranteedly before any other stack variables are allocated.
// For this, actual main (renamed main_) should not be inlined into
// this function. main_() itself may have other functions inlined (with
// their own stack variables), that's why we need this main/main_ split.
- mp_stack_ctrl_init();
+ mp_cstack_init_with_sp_here(stack_size);
#ifdef SIGPIPE
@@ -589,17 +578,8 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
signal(SIGPIPE, SIG_IGN);
#endif
- // Define a reasonable stack limit to detect stack overflow.
- mp_uint_t stack_limit = 40000 * (sizeof(void *) / 4);
- #if defined(__arm__) && !defined(__thumb2__)
- // ARM (non-Thumb) architectures require more stack.
- stack_limit *= 2;
- #endif
- mp_stack_set_limit(stack_limit);
-
-
- // pre_process_options(argc, argv);
+ //pre_process_options(argc, argv);
#if MICROPY_ENABLE_GC
#if !MICROPY_GC_SPLIT_HEAP
@@ -625,11 +605,8 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
mp_pystack_init(pystack, &pystack[MP_ARRAY_SIZE(pystack)]);
#endif
-
mp_init();
-
-
#if MICROPY_EMIT_NATIVE
// Set default emitter options
MP_STATE_VM(default_emit_opt) = emit_opt;
@@ -638,7 +615,7 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
#endif
setup_lvgl();
-
+
#if MICROPY_VFS_POSIX
{
// Mount the host FS at the root of our internal VFS
@@ -650,6 +627,7 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
MP_STATE_VM(vfs_cur) = MP_STATE_VM(vfs_mount_table);
}
#endif
+
{
// sys.path starts as [""]
mp_sys_path = mp_obj_new_list(0, NULL);
@@ -665,7 +643,12 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
// First entry is empty. We've already added an empty entry to sys.path, so skip it.
++path;
}
- bool path_remaining = *path;
+ // GCC targeting RISC-V 64 reports a warning about `path_remaining` being clobbered by
+ // either setjmp or vfork if that variable it is allocated on the stack. This may
+ // probably be a compiler error as it occurs on a few recent GCC releases (up to 14.1.0)
+ // but LLVM doesn't report any warnings.
+ static bool path_remaining;
+ path_remaining = *path;
while (path_remaining) {
char *path_entry_end = strchr(path, PATHLIST_SEP_CHAR);
if (path_entry_end == NULL) {
@@ -686,7 +669,7 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
path = path_entry_end + 1;
}
}
-
+
mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
#if defined(MICROPY_UNIX_COVERAGE)
@@ -718,9 +701,11 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
printf(" peak %d\n", m_get_peak_bytes_allocated());
*/
- //#if MICROPY_PY_SYS_EXECUTABLE
- //sys_set_excecutable(argv[0]);
- //#endif
+ /*
+ #if MICROPY_PY_SYS_EXECUTABLE
+ sys_set_excecutable(argv[0]);
+ #endif
+ */
const int NOTHING_EXECUTED = -2;
int ret = NOTHING_EXECUTED;
@@ -743,7 +728,7 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
return invalid_args();
}
mp_obj_t import_args[4];
- import_args[0] = mp_obj_new_str(argv[a + 1], strlen(argv[a + 1]));
+ import_args[0] = mp_obj_new_str_from_cstr(argv[a + 1]);
import_args[1] = import_args[2] = mp_const_none;
// Ask __import__ to handle imported module specially - set its __name__
// to __main__, and also return this leaf module, not top-level package
@@ -773,7 +758,10 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
return handle_uncaught_exception(nlr.ret_val) & 0xff;
}
- if (mp_obj_is_package(mod) && !subpkg_tried) {
+ // If this module is a package, see if it has a `__main__.py`.
+ mp_obj_t dest[2];
+ mp_load_method_protected(mod, MP_QSTR___path__, dest, true);
+ if (dest[0] != MP_OBJ_NULL && !subpkg_tried) {
subpkg_tried = true;
vstr_t vstr;
int len = strlen(argv[a + 1]);
@@ -793,7 +781,7 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
mp_verbose_flag++;
#endif
} else if (strncmp(argv[a], "-O", 2) == 0) {
- if (mp_unichar_mp_isdigit(argv[a][2])) {
+ if (unichar_isdigit(argv[a][2])) {
MP_STATE_VM(mp_optimise_value) = argv[a][2] & 0xf;
} else {
MP_STATE_VM(mp_optimise_value) = 0;
@@ -816,7 +804,7 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
// Set base dir of the script as first entry in sys.path.
char *p = strrchr(basedir, '/');
- path_items[0] = mp_obj_new_str_via_qstr(basedir, p - basedir);
+ mp_obj_list_store(mp_sys_path, MP_OBJ_NEW_SMALL_INT(0), mp_obj_new_str_via_qstr(basedir, p - basedir));
free(pathbuf);
set_sys_argv(argv, argc, a);
@@ -824,11 +812,13 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
break;
}
}
+
+ const char *inspect_env = getenv("MICROPYINSPECT");
+ if (inspect_env && inspect_env[0] != '\0') {
+ inspect = true;
+ }
*/
- //const char *inspect_env = getenv("MICROPYINSPECT");
- //if (inspect_env && inspect_env[0] != '\0') {
- // inspect = true;
- //}
+
inspect = true;
pyexec_frozen_module("_boot.py", false);
pyexec_file_if_exists("boot.py");
@@ -899,6 +889,9 @@ MP_NOINLINE void * main_(void *vargs) { //int argc, char **argv) {
//return ret & 0xff;
return 0;
}
+
+
+
extern int8_t unix_display_flag;
#include "lvgl.h"
@@ -977,7 +970,6 @@ int main(int argc, char **argv) {
return 0;
}
-
void nlr_jump_fail(void *val) {
#if MICROPY_USE_READLINE == 1
mp_hal_stdio_mode_orig();
diff --git a/tulip/macos/mpconfigport.h b/tulip/macos/mpconfigport.h
index bb866fcab..165278606 100644
--- a/tulip/macos/mpconfigport.h
+++ b/tulip/macos/mpconfigport.h
@@ -34,6 +34,8 @@
// Variant-specific definitions.
#include "mpconfigvariant.h"
+
+
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "tulip"
#undef MICROPY_MALLOC_USES_ALLOCATED_SIZE
@@ -47,17 +49,6 @@
#define MICROPY_PY_BUILTINS_HELP_TEXT tulip_desktop_help_text
#define MICROPY_HW_BOARD_NAME "Tulip4"
-/*
-#define MICROPY_ROOT_POINTERS \
- LV_ROOTS \
- void *mp_lv_user_data; \
- const char *readline_hist[50]; \
- void *mmap_region_head; \
-*/
-
-
-// Unclear how this works -- unicode (in strings) seems fine. maybe this is files
-//#define MICROPY_PY_BUILTINS_STR_UNICODE (1)
#ifndef MICROPY_CONFIG_ROM_LEVEL
#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_CORE_FEATURES)
@@ -94,18 +85,6 @@
#define MICROPY_EMIT_ARM (1)
#endif
-
-// If enabled, configure how to seed random on init.
-#ifdef MICROPY_PY_RANDOM_SEED_INIT_FUNC
-#include
-void mp_hal_get_random(size_t n, void *buf);
-static inline unsigned long mp_random_seed_init(void) {
- unsigned long r;
- mp_hal_get_random(sizeof(r), &r);
- return r;
-}
-#endif
-
// Type definitions for the specific machine based on the word size.
#ifndef MICROPY_OBJ_REPR
#ifdef __LP64__
@@ -141,7 +120,7 @@ typedef long mp_off_t;
// Always enable GC.
#define MICROPY_ENABLE_GC (1)
-#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
+#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__) || (defined(__riscv) && (__riscv_xlen == 64)))
// Fall back to setjmp() implementation for discovery of GC pointers in registers.
#define MICROPY_GCREGS_SETJMP (1)
#endif
@@ -153,8 +132,8 @@ typedef long mp_off_t;
#define MICROPY_HELPER_LEXER_UNIX (1)
#define MICROPY_VFS_POSIX (1)
#define MICROPY_READER_POSIX (1)
-#ifndef MICROPY_TRACKED_ALLOC
-#define MICROPY_TRACKED_ALLOC (MICROPY_BLUETOOTH_BTSTACK)
+#if MICROPY_PY_FFI || MICROPY_BLUETOOTH_BTSTACK
+#define MICROPY_TRACKED_ALLOC (1)
#endif
// VFS stat functions should return time values relative to 1970/1/1
@@ -170,12 +149,8 @@ typedef long mp_off_t;
#define MICROPY_STACKLESS_STRICT (0)
#endif
-// If settrace is enabled then we need code saving.
-#if MICROPY_PY_SYS_SETTRACE
-#define MICROPY_PERSISTENT_CODE_SAVE (1)
-#define MICROPY_COMP_CONST (0)
-#endif
-
+// Implementation of the machine module.
+#define MICROPY_PY_MACHINE_INCLUDEFILE "../../micropython/ports/unix/modmachine.c"
// Unix-specific configuration of machine.mem*.
#define MICROPY_MACHINE_MEM_GET_READ_ADDR mod_machine_mem_get_addr
@@ -191,13 +166,13 @@ typedef long mp_off_t;
// Ensure builtinimport.c works with -m.
#define MICROPY_MODULE_OVERRIDE_MAIN_IMPORT (1)
-// Don't default sys.argv because we do that in main.
+// Don't default sys.argv and sys.path because we do that in main.
#define MICROPY_PY_SYS_PATH_ARGV_DEFAULTS (0)
// Enable sys.executable.
#define MICROPY_PY_SYS_EXECUTABLE (1)
-#define MICROPY_PY_USOCKET_LISTEN_BACKLOG_DEFAULT (SOMAXCONN < 128 ? SOMAXCONN : 128)
+#define MICROPY_PY_SOCKET_LISTEN_BACKLOG_DEFAULT (SOMAXCONN < 128 ? SOMAXCONN : 128)
// Bare-metal ports don't have stderr. Printing debug to stderr may give tests
// which check stdout a chance to pass, etc.
@@ -208,20 +183,14 @@ extern const struct _mp_print_t mp_stderr_print;
// For the native emitter configure how to mark a region as executable.
void mp_unix_alloc_exec(size_t min_size, void **ptr, size_t *size);
void mp_unix_free_exec(void *ptr, size_t size);
-void mp_unix_mark_exec(void);
#define MP_PLAT_ALLOC_EXEC(min_size, ptr, size) mp_unix_alloc_exec(min_size, ptr, size)
#define MP_PLAT_FREE_EXEC(ptr, size) mp_unix_free_exec(ptr, size)
-#ifndef MICROPY_FORCE_PLAT_ALLOC_EXEC
-// Use MP_PLAT_ALLOC_EXEC for any executable memory allocation, including for FFI
-// (overriding libffi own implementation)
-#define MICROPY_FORCE_PLAT_ALLOC_EXEC (1)
-#endif
// If enabled, configure how to seed random on init.
-#ifdef MICROPY_PY_URANDOM_SEED_INIT_FUNC
+#ifdef MICROPY_PY_RANDOM_SEED_INIT_FUNC
#include
void mp_hal_get_random(size_t n, void *buf);
-static inline unsigned long mp_urandom_seed_init(void) {
+static inline unsigned long mp_random_seed_init(void) {
unsigned long r;
mp_hal_get_random(sizeof(r), &r);
return r;
@@ -261,6 +230,7 @@ static inline unsigned long mp_urandom_seed_init(void) {
#include
#endif
+
// If threading is enabled, configure the atomic section.
#if MICROPY_PY_THREAD
#define MICROPY_BEGIN_ATOMIC_SECTION() (mp_thread_unix_begin_atomic_section(), 0xffffffff)
diff --git a/tulip/macos/mpconfigport.mk b/tulip/macos/mpconfigport.mk
new file mode 100644
index 000000000..b0695760b
--- /dev/null
+++ b/tulip/macos/mpconfigport.mk
@@ -0,0 +1,46 @@
+# Enable/disable modules and 3rd-party libs to be included in interpreter
+
+# Build 32-bit binaries on a 64-bit host
+MICROPY_FORCE_32BIT = 0
+
+# This variable can take the following values:
+# 0 - no readline, just simple stdin input
+# 1 - use MicroPython version of readline
+MICROPY_USE_READLINE = 1
+
+# btree module using Berkeley DB 1.xx
+MICROPY_PY_BTREE = 1
+
+# _thread module using pthreads
+MICROPY_PY_THREAD = 1
+
+# Subset of CPython termios module
+MICROPY_PY_TERMIOS = 1
+
+# Subset of CPython socket module
+MICROPY_PY_SOCKET = 1
+
+# ffi module requires libffi (libffi-dev Debian package)
+MICROPY_PY_FFI = 0
+
+# ssl module requires one of the TLS libraries below
+MICROPY_PY_SSL = 1
+# axTLS has minimal size but implements only a subset of modern TLS
+# functionality, so may have problems with some servers.
+MICROPY_SSL_AXTLS = 0
+# mbedTLS is more up to date and complete implementation, but also
+# more bloated.
+MICROPY_SSL_MBEDTLS = 1
+
+# jni module requires JVM/JNI
+MICROPY_PY_JNI = 0
+
+# Avoid using system libraries, use copies bundled with MicroPython
+# as submodules (currently affects only libffi).
+MICROPY_STANDALONE ?= 0
+
+MICROPY_ROM_TEXT_COMPRESSION = 1
+
+MICROPY_VFS_FAT = 1
+MICROPY_VFS_LFS1 = 1
+MICROPY_VFS_LFS2 = 1
diff --git a/tulip/release.sh b/tulip/release.sh
index 1ee1dd17d..8b2b26e6f 100755
--- a/tulip/release.sh
+++ b/tulip/release.sh
@@ -29,7 +29,7 @@ cp shared/py/voices.py fs/ex/my_voices.py
cd esp32s3
-source ~/esp/esp-idf-v5.2/export.sh
+source ~/esp/esp-idf/export.sh
# If sys, just create/upload the last sys and exit
if [ "$TYPE" == "sys" ]; then
python tulip_fs_create.py
diff --git a/tulip/shared/desktop/unix_display.c b/tulip/shared/desktop/unix_display.c
index cec317108..442156b15 100644
--- a/tulip/shared/desktop/unix_display.c
+++ b/tulip/shared/desktop/unix_display.c
@@ -69,7 +69,7 @@ void lvgl_keyboard_read(lv_indev_t * indev_drv, lv_indev_data_t * data)
* @param sdl_key the key code
* @return LV_KEY_* control character or '\0'
*/
-uint32_t keycode_to_ctrl_key(SDL_Keycode sdl_key)
+uint32_t sdl_keycode_to_ctrl_key(SDL_Keycode sdl_key)
{
/*Remap some key to LV_KEY_... to manage groups*/
@@ -282,7 +282,7 @@ void check_key() {
} else if(e.type == SDL_KEYDOWN) {
// do LVGL stuff first
- const uint32_t ctrl_key = keycode_to_ctrl_key(e.key.keysym.sym);
+ const uint32_t ctrl_key = sdl_keycode_to_ctrl_key(e.key.keysym.sym);
if (ctrl_key == '\0') {
// do nothing?
} else {
diff --git a/tulip/shared/desktop/unix_mphal.c b/tulip/shared/desktop/unix_mphal.c
index 20776dce0..9d26c3ce8 100644
--- a/tulip/shared/desktop/unix_mphal.c
+++ b/tulip/shared/desktop/unix_mphal.c
@@ -48,7 +48,7 @@
#ifndef _WIN32
#include
-STATIC void sighandler(int signum) {
+static void sighandler(int signum) {
if (signum == SIGINT) {
#if MICROPY_ASYNC_KBD_INTR
#if MICROPY_PY_THREAD_GIL
@@ -217,7 +217,7 @@ void mp_hal_stdout_tx_strn(const char *str, size_t len) {
//extern void mp_uos_dupterm_tx_strn(const char *str, size_t len);
-void mp_hal_stdout_tx_strn(const char *str, size_t len) {
+mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
// TFB log
for(uint16_t i=0;i=0) {
+ //fprintf(stderr, "check and fill %" PRIu32"\n", amy_sysclock());
while(amy_sysclock() >= (next_amy_tick_us/1000)) {
sequencer_tick_count++;
- uint32_t lag = amy_sysclock() - (next_amy_tick_us/1000);
// Check defers
for(uint8_t i=0;i defer_sysclock[i]) {