From 64c9baa6aa6203e21ff0420ce5a9889f44422334 Mon Sep 17 00:00:00 2001 From: Margaret Matocha Date: Fri, 7 Aug 2020 15:46:00 -0500 Subject: Added bitmap.insert function for slice copy into a bitmap from another bitmap --- shared-module/displayio/Bitmap.c | 71 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'shared-module') diff --git a/shared-module/displayio/Bitmap.c b/shared-module/displayio/Bitmap.c index 8bcda6086..ab6e4f5dd 100644 --- a/shared-module/displayio/Bitmap.c +++ b/shared-module/displayio/Bitmap.c @@ -105,6 +105,77 @@ uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *self, int16_t return 0; } +void common_hal_displayio_bitmap_insert(displayio_bitmap_t *self, int16_t x, int16_t y, displayio_bitmap_t *source, + int16_t x1, int16_t y1, int16_t x2, int16_t y2) { + // Copy complete "source" bitmap into "self" bitmap at location x,y in the "self" + // Add a boolean to determine if all values are copied, or only if non-zero + // Default is copy all values, but for text glyphs this should copy only non-zero values + + if (self->read_only) { + mp_raise_RuntimeError(translate("Read-only object")); + } + + //// check for zero width, this would be a single pixel + // if (x1_source == x2_source) || (y1_source == y2_source) { + // return 0 + // } + + // Dirty area update is unnecessary with simplest version. + // int16_t x_max=x+(x2_source-x1_source); + // int16_t y_max=y+(y2_source-y1_source); + // + // + // // Update the dirty area. + // if (x < self->dirty_area.x1) { + // self->dirty_area.x1 = x; + // } else if (x_max >= self->dirty_area.x2) { + // self->dirty_area.x2 = x_max); + // } + // if (y < self->dirty_area.y1) { + // self->dirty_area.y1 = y; + // } else if (y_max >= self->dirty_area.y2) { + // self->dirty_area.y2 = y_max; + // } + + // simplest version - use internal functions for get/set pixels + for (uint16_t i=0; i<= (x2-x1) ; i++) { + for (uint16_t j=0; j<= (y2-y1) ; j++){ + uint16_t value = common_hal_displayio_bitmap_get_pixel(source, x1+i, y1+j); + if ( (x+i >= 0) && (y+j >= 0) && (x+i <= self->width-1) && (y+j <= self->height-1) ){ + common_hal_displayio_bitmap_set_pixel(self, x+i, y+j, value); + } + } + } + + // Would be faster if copying a full word at a time. + /// Hard work here!!!! + // index into the original row + // figure out how to shift the bits into the right location + // check the boolean and don't update any zero's + + // // Update our data + // int32_t row_start = y * self->stride; + // uint32_t bytes_per_value = self->bits_per_value / 8; + // if (bytes_per_value < 1) { + // uint32_t bit_position = (sizeof(size_t) * 8 - ((x & self->x_mask) + 1) * self->bits_per_value); + // uint32_t index = row_start + (x >> self->x_shift); + // uint32_t word = self->data[index]; + // word &= ~(self->bitmask << bit_position); + // word |= (value & self->bitmask) << bit_position; + // self->data[index] = word; + // } else { + // size_t* row = self->data + row_start; + // if (bytes_per_value == 1) { + // ((uint8_t*) row)[x] = value; + // } else if (bytes_per_value == 2) { + // ((uint16_t*) row)[x] = value; + // } else if (bytes_per_value == 4) { + // ((uint32_t*) row)[x] = value; + // } + // } +} + + void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *self, int16_t x, int16_t y, uint32_t value) { if (self->read_only) { mp_raise_RuntimeError(translate("Read-only object")); -- cgit v1.2.3 From b6008d0032a49e6b5c332576fa2f141d353b9fd3 Mon Sep 17 00:00:00 2001 From: Margaret Matocha Date: Fri, 7 Aug 2020 15:59:42 -0500 Subject: Adding bitmap.insert to copy a slice of a source bitmap into another bitmap --- shared-module/displayio/Bitmap.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Bitmap.c b/shared-module/displayio/Bitmap.c index ab6e4f5dd..75f352b30 100644 --- a/shared-module/displayio/Bitmap.c +++ b/shared-module/displayio/Bitmap.c @@ -115,6 +115,10 @@ void common_hal_displayio_bitmap_insert(displayio_bitmap_t *self, int16_t x, int mp_raise_RuntimeError(translate("Read-only object")); } + // If this value is encountered in the source bitmap, it will not be copied (for text glyphs) + // This should be added as an optional parameter, and if it is `None`, then all pixels are copied + uint32_t skip_value=0; + //// check for zero width, this would be a single pixel // if (x1_source == x2_source) || (y1_source == y2_source) { // return 0 @@ -140,9 +144,11 @@ void common_hal_displayio_bitmap_insert(displayio_bitmap_t *self, int16_t x, int // simplest version - use internal functions for get/set pixels for (uint16_t i=0; i<= (x2-x1) ; i++) { for (uint16_t j=0; j<= (y2-y1) ; j++){ - uint16_t value = common_hal_displayio_bitmap_get_pixel(source, x1+i, y1+j); - if ( (x+i >= 0) && (y+j >= 0) && (x+i <= self->width-1) && (y+j <= self->height-1) ){ - common_hal_displayio_bitmap_set_pixel(self, x+i, y+j, value); + uint32_t value = common_hal_displayio_bitmap_get_pixel(source, x1+i, y1+j); + if (value != skip_value) { + if ( (x+i >= 0) && (y+j >= 0) && (x+i <= self->width-1) && (y+j <= self->height-1) ){ + common_hal_displayio_bitmap_set_pixel(self, x+i, y+j, value); + } } } } -- cgit v1.2.3 From e73dba21d26b93ce1140faecb4820ae46ce4c742 Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Fri, 7 Aug 2020 18:42:06 -0400 Subject: make pixelbuf handle floats and iterables --- shared-bindings/_pixelbuf/PixelBuf.c | 30 ++++++++-------------- shared-bindings/_pixelbuf/PixelBuf.h | 2 +- shared-module/_pixelbuf/PixelBuf.c | 49 +++++++++++++++++++++++++++++------- 3 files changed, 52 insertions(+), 29 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/_pixelbuf/PixelBuf.c b/shared-bindings/_pixelbuf/PixelBuf.c index 4fc6f7cbf..ee7dac4b3 100644 --- a/shared-bindings/_pixelbuf/PixelBuf.c +++ b/shared-bindings/_pixelbuf/PixelBuf.c @@ -40,6 +40,10 @@ #include "shared-module/_pixelbuf/PixelBuf.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#ifdef CIRCUITPY_ULAB +#include "extmod/ulab/code/ndarray.h" +#endif + extern const int32_t colorwheel(float pos); static void parse_byteorder(mp_obj_t byteorder_obj, pixelbuf_byteorder_details_t* parsed); @@ -326,27 +330,15 @@ STATIC mp_obj_t pixelbuf_pixelbuf_subscr(mp_obj_t self_in, mp_obj_t index_in, mp } else { // Set #if MICROPY_PY_ARRAY_SLICE_ASSIGN - if (!(MP_OBJ_IS_TYPE(value, &mp_type_list) || MP_OBJ_IS_TYPE(value, &mp_type_tuple))) { - mp_raise_ValueError(translate("tuple/list required on RHS")); - } - - mp_obj_t *src_objs; - size_t num_items; - if (MP_OBJ_IS_TYPE(value, &mp_type_list)) { - mp_obj_list_t *t = MP_OBJ_TO_PTR(value); - num_items = t->len; - src_objs = t->items; - } else { - mp_obj_tuple_t *l = MP_OBJ_TO_PTR(value); - num_items = l->len; - src_objs = l->items; - } - if (num_items != slice_len) { - mp_raise_ValueError_varg(translate("Unmatched number of items on RHS (expected %d, got %d)."), - slice_len, num_items); + size_t num_items = mp_obj_get_int(mp_obj_len(value)); + + if (num_items != slice_len && num_items != (slice_len * common_hal__pixelbuf_pixelbuf_get_bpp(self_in))) { + mp_raise_ValueError_varg(translate("Unmatched number of items on RHS (expected %d or %d, got %d)."), + slice_len, slice_len * common_hal__pixelbuf_pixelbuf_get_bpp(self_in), + num_items); } - common_hal__pixelbuf_pixelbuf_set_pixels(self_in, slice.start, slice.step, slice_len, src_objs); + common_hal__pixelbuf_pixelbuf_set_pixels(self_in, slice.start, slice.step, slice_len, value, num_items != slice_len); return mp_const_none; #else return MP_OBJ_NULL; // op not supported diff --git a/shared-bindings/_pixelbuf/PixelBuf.h b/shared-bindings/_pixelbuf/PixelBuf.h index 0b09a5771..111223be0 100644 --- a/shared-bindings/_pixelbuf/PixelBuf.h +++ b/shared-bindings/_pixelbuf/PixelBuf.h @@ -47,6 +47,6 @@ void common_hal__pixelbuf_pixelbuf_fill(mp_obj_t self, mp_obj_t item); void common_hal__pixelbuf_pixelbuf_show(mp_obj_t self); mp_obj_t common_hal__pixelbuf_pixelbuf_get_pixel(mp_obj_t self, size_t index); void common_hal__pixelbuf_pixelbuf_set_pixel(mp_obj_t self, size_t index, mp_obj_t item); -void common_hal__pixelbuf_pixelbuf_set_pixels(mp_obj_t self_in, size_t start, mp_int_t step, size_t slice_len, mp_obj_t* values); +void common_hal__pixelbuf_pixelbuf_set_pixels(mp_obj_t self_in, size_t start, mp_int_t step, size_t slice_len, mp_obj_t* values, bool flattened); #endif // CP_SHARED_BINDINGS_PIXELBUF_PIXELBUF_H diff --git a/shared-module/_pixelbuf/PixelBuf.c b/shared-module/_pixelbuf/PixelBuf.c index 9d671e454..50906fcc1 100644 --- a/shared-module/_pixelbuf/PixelBuf.c +++ b/shared-module/_pixelbuf/PixelBuf.c @@ -132,6 +132,18 @@ void common_hal__pixelbuf_pixelbuf_set_brightness(mp_obj_t self_in, mp_float_t b } } +uint8_t _pixelbuf_get_as_uint8(mp_obj_t obj) { + if (MP_OBJ_IS_SMALL_INT(obj)) { + return MP_OBJ_SMALL_INT_VALUE(obj); + } else if (MP_OBJ_IS_INT(obj)) { + return mp_obj_get_int_truncated(obj); + } else if (mp_obj_is_float(obj)) { + return (uint8_t)mp_obj_get_float(obj); + } + mp_raise_TypeError_varg( + translate("can't convert %q to %q"), mp_obj_get_type_qstr(obj), MP_QSTR_int); +} + void _pixelbuf_parse_color(pixelbuf_pixelbuf_obj_t* self, mp_obj_t color, uint8_t* r, uint8_t* g, uint8_t* b, uint8_t* w) { pixelbuf_byteorder_details_t *byteorder = &self->byteorder; // w is shared between white in NeoPixels and brightness in dotstars (so that DotStars can have @@ -142,8 +154,8 @@ void _pixelbuf_parse_color(pixelbuf_pixelbuf_obj_t* self, mp_obj_t color, uint8_ *w = 0; } - if (MP_OBJ_IS_INT(color)) { - mp_int_t value = mp_obj_get_int_truncated(color); + if (MP_OBJ_IS_INT(color) || mp_obj_is_float(color)) { + mp_int_t value = MP_OBJ_IS_INT(color) ? mp_obj_get_int_truncated(color) : mp_obj_get_float(color); *r = value >> 16 & 0xff; *g = (value >> 8) & 0xff; *b = value & 0xff; @@ -155,9 +167,9 @@ void _pixelbuf_parse_color(pixelbuf_pixelbuf_obj_t* self, mp_obj_t color, uint8_ mp_raise_ValueError_varg(translate("Expected tuple of length %d, got %d"), byteorder->bpp, len); } - *r = mp_obj_get_int_truncated(items[PIXEL_R]); - *g = mp_obj_get_int_truncated(items[PIXEL_G]); - *b = mp_obj_get_int_truncated(items[PIXEL_B]); + *r = _pixelbuf_get_as_uint8(items[PIXEL_R]); + *g = _pixelbuf_get_as_uint8(items[PIXEL_G]); + *b = _pixelbuf_get_as_uint8(items[PIXEL_B]); if (len > 3) { if (mp_obj_is_float(items[PIXEL_W])) { *w = 255 * mp_obj_get_float(items[PIXEL_W]); @@ -218,17 +230,36 @@ void _pixelbuf_set_pixel(pixelbuf_pixelbuf_obj_t* self, size_t index, mp_obj_t v _pixelbuf_set_pixel_color(self, index, r, g, b, w); } -void common_hal__pixelbuf_pixelbuf_set_pixels(mp_obj_t self_in, size_t start, mp_int_t step, size_t slice_len, mp_obj_t* values) { +void common_hal__pixelbuf_pixelbuf_set_pixels(mp_obj_t self_in, size_t start, mp_int_t step, size_t slice_len, mp_obj_t* values, bool flattened) { pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in); - for (size_t i = 0; i < slice_len; i++) { - _pixelbuf_set_pixel(self, start, values[i]); - start+=step; + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(values, &iter_buf); + mp_obj_t item; + size_t i = 0; + mp_obj_tuple_t *tuple; + uint bpp = self->bytes_per_pixel; + if (flattened) { + tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(bpp, NULL)); + } + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if (flattened) { + tuple->items[i % bpp] = item; + if (++i % bpp == 0) { + _pixelbuf_set_pixel(self, start, tuple); + start+=step; + } + } else { + _pixelbuf_set_pixel(self, start, item); + start+=step; + } } if (self->auto_write) { common_hal__pixelbuf_pixelbuf_show(self_in); } } + + void common_hal__pixelbuf_pixelbuf_set_pixel(mp_obj_t self_in, size_t index, mp_obj_t value) { pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in); _pixelbuf_set_pixel(self, index, value); -- cgit v1.2.3 From 0f4b969d62b5eb933a674a23a338d9d420cf61b4 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 8 Aug 2020 00:29:37 -0400 Subject: discovery of Nordic UART service working --- devices/ble_hci/common-hal/_bleio/Attribute.c | 49 +-- devices/ble_hci/common-hal/_bleio/Attribute.h | 26 +- devices/ble_hci/common-hal/_bleio/Characteristic.c | 2 +- devices/ble_hci/common-hal/_bleio/Service.c | 32 +- devices/ble_hci/common-hal/_bleio/UUID.c | 2 +- devices/ble_hci/common-hal/_bleio/__init__.c | 8 + devices/ble_hci/common-hal/_bleio/__init__.h | 5 + devices/ble_hci/common-hal/_bleio/att.c | 454 +++++++++++++-------- ports/nrf/common-hal/_bleio/UUID.c | 2 +- shared-bindings/_bleio/UUID.c | 2 +- shared-bindings/_bleio/UUID.h | 2 +- shared-module/_bleio/Characteristic.h | 13 + 12 files changed, 368 insertions(+), 229 deletions(-) (limited to 'shared-module') diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.c b/devices/ble_hci/common-hal/_bleio/Attribute.c index d32ed1167..26fabed09 100644 --- a/devices/ble_hci/common-hal/_bleio/Attribute.c +++ b/devices/ble_hci/common-hal/_bleio/Attribute.c @@ -24,55 +24,26 @@ * THE SOFTWARE. */ +#include "py/runtime.h" + #include "shared-bindings/_bleio/Attribute.h" #include "shared-bindings/_bleio/Characteristic.h" #include "shared-bindings/_bleio/Descriptor.h" #include "shared-bindings/_bleio/Service.h" -// Return the type of the attribute. -ble_attribute_type_uuid bleio_attribute_type_uuid(mp_obj_t *attribute) { + +bleio_uuid_obj_t *bleio_attribute_get_uuid(mp_obj_t *attribute) { if (MP_OBJ_IS_TYPE(attribute, &bleio_characteristic_type)) { - return BLE_TYPE_CHARACTERISTIC; + bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute); + return characteristic->uuid; } if (MP_OBJ_IS_TYPE(attribute, &bleio_descriptor_type)) { - return BLE_TYPE_DESCRIPTOR; + bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute); + return descriptor->uuid; } if (MP_OBJ_IS_TYPE(attribute, &bleio_service_type)) { bleio_service_obj_t *service = MP_OBJ_TO_PTR(attribute); - return service->is_secondary ? BLE_TYPE_SECONDARY_SERVICE : BLE_TYPE_PRIMARY_SERVICE; + return service->uuid; } - return BLE_TYPE_UNKNOWN; + mp_raise_RuntimeError(translate("Invalid BLE attribute")); } - -// Convert a _bleio security mode to a ble_gap_conn_sec_mode_t setting. -// void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode) { -// switch (security_mode) { -// case SECURITY_MODE_NO_ACCESS: -// BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(perm); -// break; - -// case SECURITY_MODE_OPEN: -// BLE_GAP_CONN_SEC_MODE_SET_OPEN(perm); -// break; - -// case SECURITY_MODE_ENC_NO_MITM: -// BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(perm); -// break; - -// case SECURITY_MODE_ENC_WITH_MITM: -// BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(perm); -// break; - -// case SECURITY_MODE_LESC_ENC_WITH_MITM: -// BLE_GAP_CONN_SEC_MODE_SET_LESC_ENC_WITH_MITM(perm); -// break; - -// case SECURITY_MODE_SIGNED_NO_MITM: -// BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(perm); -// break; - -// case SECURITY_MODE_SIGNED_WITH_MITM: -// BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(perm); -// break; -// } -// } diff --git a/devices/ble_hci/common-hal/_bleio/Attribute.h b/devices/ble_hci/common-hal/_bleio/Attribute.h index 47327437b..f4b0b7dbb 100644 --- a/devices/ble_hci/common-hal/_bleio/Attribute.h +++ b/devices/ble_hci/common-hal/_bleio/Attribute.h @@ -28,23 +28,23 @@ #define MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ATTRIBUTE_H #include "shared-module/_bleio/Attribute.h" +#include "shared-bindings/_bleio/UUID.h" // Types returned by attribute table lookups. These are UUIDs. typedef enum { - BLE_TYPE_UNKNOWN = 0x0000, - BLE_TYPE_PRIMARY_SERVICE = 0x2800, - BLE_TYPE_SECONDARY_SERVICE = 0x2801, - BLE_TYPE_CHARACTERISTIC = 0x2803, - BLE_TYPE_DESCRIPTOR = 0x2900 + BLE_TYPE_UNKNOWN = 0x0000, + BLE_TYPE_SERVICE_PRIMARY = 0x2800, + BLE_TYPE_SERVICE_SECONDARY = 0x2801, + BLE_TYPE_SERVICE_INCLUDE = 0x2802, // not yet implemented by us + BLE_TYPE_CHARACTERISTIC = 0x2803, + BLE_TYPE_CHAR_EXTENDED_PROPS = 0x2900, // not yet implemented by us + BLE_TYPE_CHAR_USER_DESC = 0x2901, // not yet implemented by us + BLE_TYPE_CCCD = 0x2902, + BLE_TYPE_SCCD = 0x2903, // not yet implemented by us + BLE_TYPE_CHAR_PRESENTATION_FMT = 0x2904, // not yet implemented by us + BLE_TYPE_CHAR_AGGREGATE_FMT = 0x2905, // not yet implemented by us } ble_attribute_type_uuid; -// typedef struct -// { -// uint8_t sm : 4; /**< Security Mode (1 or 2), 0 for no permissions at all. */ -// uint8_t lv : 4; /**< Level (1, 2, 3 or 4), 0 for no permissions at all. */ - -// } ble_gap_conn_sec_mode_t; - -ble_attribute_type_uuid bleio_attribute_type_uuid(mp_obj_t *attribute); +bleio_uuid_obj_t *bleio_attribute_get_uuid(mp_obj_t *attribute); #endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_ATTRIBUTE_H diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.c b/devices/ble_hci/common-hal/_bleio/Characteristic.c index 2f4a81f9a..b62957ea6 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.c +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.c @@ -149,7 +149,7 @@ void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t * } descriptor->handle = bleio_adapter_add_attribute(&common_hal_bleio_adapter_obj, MP_OBJ_TO_PTR(descriptor)); - // Include this desriptor in the service handles range. + // Include this descriptor in the service handle's range. self->service->end_handle = descriptor->handle; // Link together all the descriptors for this characteristic. diff --git a/devices/ble_hci/common-hal/_bleio/Service.c b/devices/ble_hci/common-hal/_bleio/Service.c index abccfd5c4..b6963b7a4 100644 --- a/devices/ble_hci/common-hal/_bleio/Service.c +++ b/devices/ble_hci/common-hal/_bleio/Service.c @@ -99,20 +99,30 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, self->end_handle = characteristic->handle; if (characteristic->props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) { - // We need a CCCD. + // We need a CCCD if this characteristic is doing notify or indicate. bleio_descriptor_obj_t *cccd = m_new_obj(bleio_descriptor_obj_t); cccd->base.type = &bleio_descriptor_type; - cccd->read_perm = SECURITY_MODE_OPEN; - // Make CCCD write permission match characteristic read permission. - cccd->write_perm = characteristic->read_perm; - - const uint16_t cccd_handle = bleio_adapter_add_attribute( - &common_hal_bleio_adapter_obj, MP_OBJ_TO_PTR(cccd)); - cccd->handle = cccd_handle; - characteristic->cccd_handle = cccd_handle; - common_hal_bleio_characteristic_add_descriptor(characteristic, cccd); - self->end_handle = cccd_handle; + uint16_t zero = 0; + mp_buffer_info_t zero_cccd = { + .buf = &zero, + .len = sizeof(zero), + }; + + common_hal_bleio_descriptor_construct( + cccd, + characteristic, + &cccd_uuid, // 0x2902 + SECURITY_MODE_OPEN, // CCCD read perm + characteristic->read_perm, // Make CCCD write perm match characteristic read perm. + 2, // 2 bytes + true, // fixed length + &zero_cccd // Initial value is 0. + ); + + // Adds CCCD to attribute table, and also extends self->end_handle to include the CCCD. + common_hal_bleio_characteristic_add_descriptor(characteristic, cccd); + characteristic->cccd_handle = cccd->handle; } // #if CIRCUITPY_VERBOSE_BLE diff --git a/devices/ble_hci/common-hal/_bleio/UUID.c b/devices/ble_hci/common-hal/_bleio/UUID.c index d86878e47..fd8d8bfe9 100644 --- a/devices/ble_hci/common-hal/_bleio/UUID.c +++ b/devices/ble_hci/common-hal/_bleio/UUID.c @@ -36,7 +36,7 @@ // If uuid128 is NULL, this is a Bluetooth SIG 16-bit UUID. // If uuid128 is not NULL, it's a 128-bit (16-byte) UUID, with bytes 12 and 13 zero'd out, where // the 16-bit part goes. Those 16 bits are passed in uuid16. -void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, uint32_t uuid16, const uint8_t uuid128[16]) { +void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, const uint8_t uuid128[16]) { self->size = uuid128 == NULL ? 16 : 128; self->uuid16 = uuid16; if (uuid128) { diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index ee953cfeb..16b4a26e2 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -38,6 +38,9 @@ #include "shared-bindings/_bleio/UUID.h" #include "supervisor/shared/bluetooth.h" +// UUID shared by all cccd's. +bleio_uuid_obj_t cccd_uuid; + bool vm_used_ble; void check_hci_error(hci_result_t result) { @@ -112,6 +115,10 @@ void check_hci_error(hci_result_t result) { // Turn off BLE on a reset or reload. void bleio_reset() { + // Create a UUID object for all CCCD's. + cccd_uuid.base.type = &bleio_uuid_type; + common_hal_bleio_uuid_construct(&cccd_uuid, BLE_TYPE_CCCD, NULL); + bleio_hci_reset(); if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { @@ -123,6 +130,7 @@ void bleio_reset() { return; } common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false); + //FIX bonding_reset(); supervisor_start_bluetooth(); } diff --git a/devices/ble_hci/common-hal/_bleio/__init__.h b/devices/ble_hci/common-hal/_bleio/__init__.h index 5873675af..e84320e30 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.h +++ b/devices/ble_hci/common-hal/_bleio/__init__.h @@ -29,6 +29,8 @@ #include +#include "shared-bindings/_bleio/UUID.h" + #include "hci.h" void bleio_background(void); @@ -59,4 +61,7 @@ void check_sec_status(uint8_t sec_status); // Track if the user code modified the BLE state to know if we need to undo it on reload. extern bool vm_used_ble; +// UUID shared by all CCCD's. +extern bleio_uuid_obj_t cccd_uuid; + #endif // MICROPY_INCLUDED_BLE_HCI_COMMON_HAL_INIT_H diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c index ba6c7c3d0..8daddd3a9 100644 --- a/devices/ble_hci/common-hal/_bleio/att.c +++ b/devices/ble_hci/common-hal/_bleio/att.c @@ -33,6 +33,8 @@ #include "common-hal/_bleio/Attribute.h" #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Service.h" #include "shared-bindings/_bleio/UUID.h" #include "supervisor/shared/tick.h" @@ -54,8 +56,63 @@ STATIC struct { uint8_t length; // Length of response packet. } expected_rsp; +// A characteristic declaration has this data, in this order: +// See Bluetooth v5.1 spec, section 3.3.1 Characteristic declaration. +typedef struct __packed { + uint8_t properties; + uint16_t value_handle; + uint8_t uuid[0]; // 2 or 16 bytes +} characteristic_declaration_t; + //FIX BLEDeviceEventHandler event_handlers[2]; +STATIC uint8_t bleio_properties_to_ble_spec_properties(uint8_t bleio_properties) { + uint8_t ble_spec_properties = 0; + if (bleio_properties & CHAR_PROP_BROADCAST) { + ble_spec_properties |= BT_GATT_CHRC_BROADCAST; + } + if (bleio_properties & CHAR_PROP_INDICATE) { + ble_spec_properties |= BT_GATT_CHRC_INDICATE; + } + if (bleio_properties & CHAR_PROP_NOTIFY) { + ble_spec_properties |= BT_GATT_CHRC_NOTIFY; + } + if (bleio_properties & CHAR_PROP_READ) { + ble_spec_properties |= BT_GATT_CHRC_READ; + } + if (bleio_properties & CHAR_PROP_WRITE) { + ble_spec_properties |= BT_GATT_CHRC_WRITE; + } + if (bleio_properties & CHAR_PROP_WRITE_NO_RESPONSE) { + ble_spec_properties |= BT_GATT_CHRC_WRITE_WITHOUT_RESP; + } + + return ble_spec_properties; +} + +// STATIC uint8_t ble_spec_properties_to_bleio_properties(uint8_t ble_spec_properties) { +// uint8_t bleio_properties = 0; +// if (ble_spec_properties & BT_GATT_CHRC_BROADCAST) { +// bleio_properties |= CHAR_PROP_BROADCAST; +// } +// if (ble_spec_properties & BT_GATT_CHRC_INDICATE) { +// bleio_properties |= CHAR_PROP_INDICATE; +// } +// if (ble_spec_properties & BT_GATT_CHRC_NOTIFY) { +// bleio_properties |= CHAR_PROP_NOTIFY; +// } +// if (ble_spec_properties & BT_GATT_CHRC_READ) { +// bleio_properties |= CHAR_PROP_READ; +// } +// if (ble_spec_properties & BT_GATT_CHRC_WRITE) { +// bleio_properties |= CHAR_PROP_WRITE; +// } +// if (ble_spec_properties & BT_GATT_CHRC_WRITE_WITHOUT_RESP) { +// bleio_properties |= CHAR_PROP_WRITE_NO_RESPONSE; +// } + +// return bleio_properties; +// } STATIC void send_error(uint16_t conn_handle, uint8_t opcode, uint16_t handle, uint8_t code) { struct __packed { @@ -187,13 +244,13 @@ bool att_disconnect_from_address(bt_addr_le_t *addr) { // BLEUuid serviceUuid(serviceUuidFilter); // while (reqEnd_handle == 0xffff) { -// int respLength = readByGroupReq(conn_handle, reqStart_handle, reqEnd_handle, BLE_TYPE_PRIMARY_SERVICE, response_buffer); +// int respLength = readByGroupReq(conn_handle, reqStart_handle, reqEnd_handle, BLE_TYPE_SERVICE_PRIMARY, response_buffer); // if (respLength == 0) { // return false; // } -// if (response_buffer[0] == BT_ATT_OP_READ_BY_GROUP_RSP) { +// if (response_buffer[0] == BT_ATT_OP_READ_GROUP_RSP) { // uint16_t lengthPerService = response_buffer[1]; // uint8_t uuidLen = lengthPerService - 4; @@ -254,7 +311,7 @@ bool att_disconnect_from_address(bt_addr_le_t *addr) { // return false; // } -// if (response_buffer[0] == BT_ATT_OP_READ_BY_TYPE_RSP) { +// if (response_buffer[0] == BT_ATT_OP_READ_TYPE_RSP) { // uint16_t lengthPerCharacteristic = response_buffer[1]; // uint8_t uuidLen = lengthPerCharacteristic - 5; @@ -759,56 +816,88 @@ STATIC void process_find_info_req(uint16_t conn_handle, uint16_t mtu, uint8_t dl return; } - //FIX - // uint8_t response[mtu]; - // uint16_t response_length; + typedef struct __packed { + struct bt_att_hdr h; + struct bt_att_find_info_rsp r; + } rsp_t; - // response[0] = BT_ATT_OP_FIND_INFO_RSP; - // response[1] = 0x00; - // response_length = 2; + uint8_t rsp_bytes[mtu]; + rsp_t *rsp = (rsp_t *) rsp_bytes; + rsp->h.code = BT_ATT_OP_FIND_INFO_RSP; - // for (uint16_t i = (req->start_handle - 1); i < GATT.attributeCount() && i <= (req->end_handle - 1); i++) { - // BLELocalAttribute* attribute = GATT.attribute(i); - // uint16_t handle = (i + 1); - // bool is_value_handle = (attribute->type() == BLE_TYPE_CHARACTERISTIC) && (((BLELocalCharacteristic*)attribute)->valueHandle() == handle); - // int uuid_len = is_value_handle ? 2 : attribute->uuid_length(); - // size_t info_type = (uuidLen == 2) ? 0x01 : 0x02; + // Keeps track of total length of the response. + size_t rsp_length = sizeof(rsp_t); - // if (response[1] == 0) { - // response[1] = info_type; - // } + bool no_data = true; - // if (response[1] != info_type) { - // // different type - // break; - // } + // All the data chunks must have uuid's that are the same size. + // Keep track of the first one to make sure. + size_t sizeof_first_uuid = 0; - // // add the handle - // memcpy(&response[response_length], &handle, sizeof(handle)); - // response_length += sizeof(handle); + const uint16_t max_attribute_handle = bleio_adapter_max_attribute_handle(&common_hal_bleio_adapter_obj); + for (uint16_t handle = req->start_handle; + handle <= max_attribute_handle && handle <= req->end_handle; + handle++) { - // if (is_value_handle || attribute->type() == BLE_TYPE_DESCRIPTOR) { - // // add the UUID - // memcpy(&response[response_length], attribute->uuid_data(), uuid_len); - // response_length += uuidLen; - // } else { - // // add the type - // uint16_t type = attribute->type(); + mp_obj_t *attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); - // memcpy(&response[response_length], &type, sizeof(type)); - // response_length += sizeof(type); - // } + // Fetch the uuid for the given attribute, which might be a characteristic or a descriptor. + bleio_uuid_obj_t *uuid; - // if ((response_length + (2 + uuidLen)) > mtu) { - // break; - // } - // } + if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { + bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); + if (characteristic->handle != handle) { + // If the handles don't match, this is the characteristic definition attribute. + // Skip it. We want the characteristic value attribute. + continue; + } + uuid = characteristic->uuid; - // if (response_length == 2) { - // send_error(conn_handle, BT_ATT_OP_FIND_INFO_REQ, findInfoReq->start_handle, BT_ATT_ERR_ATTR_NOT_FOUND); - // } else { - // hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response); - // } + } else { + uuid = bleio_attribute_get_uuid(attribute_obj); + } + + const uint32_t sizeof_uuid = common_hal_bleio_uuid_get_size(uuid) / 8; + if (sizeof_first_uuid == 0) { + sizeof_first_uuid = sizeof_uuid; + // All the uuids in the response will be the same size. + rsp->r.format = sizeof_uuid == 2 ? BT_ATT_INFO_16 : BT_ATT_INFO_128; + } + + if (sizeof_uuid != sizeof_first_uuid) { + // Previous UUID was a different size. We can't mix sizes. + // Stop and send what we have so far. + break; + } + + if (rsp_length + sizeof_uuid > mtu) { + // No remaining room in response for this uuid. + break; + } + + if (sizeof_uuid == 2) { + struct bt_att_info_16 *info_16 = (struct bt_att_info_16 *) &rsp_bytes[rsp_length]; + info_16->handle = handle; + info_16->uuid = common_hal_bleio_uuid_get_uuid16(uuid); + + rsp_length += sizeof(struct bt_att_info_16); + } else { + struct bt_att_info_128 *info_128 = (struct bt_att_info_128 *) &rsp_bytes[rsp_length]; + info_128->handle = handle; + common_hal_bleio_uuid_get_uuid128(uuid, info_128->uuid); + + rsp_length += sizeof(struct bt_att_info_128); + } + + no_data =false; + } // end for + + + if (no_data) { + send_error(conn_handle, BT_ATT_OP_FIND_INFO_REQ, req->start_handle, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND); + } else { + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, rsp_length, rsp_bytes); + } } int att_find_info_req(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, uint8_t response_buffer[]) { @@ -834,7 +923,7 @@ STATIC void process_find_info_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t da check_and_save_expected_rsp(conn_handle, BT_ATT_OP_FIND_INFO_RSP, dlen, data); } -STATIC void process_find_by_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { +STATIC void process_find_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { struct bt_att_find_type_req *req = (struct bt_att_find_type_req *) data; if (dlen < sizeof(struct bt_att_find_type_req)) { @@ -849,11 +938,11 @@ STATIC void process_find_by_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t response_length = 1; //FIX - // if (find_by_type_req->type == BLE_TYPE_PRIMARY_SERVICE) { - // for (uint16_t i = (find_by_type_req->start_handle - 1); i < GATT.attributeCount() && i <= (find_by_type_req->end_handle - 1); i++) { + // if (find_type_req->type == BLE_TYPE_SERVICE_PRIMARY) { + // for (uint16_t i = (find_type_req->start_handle - 1); i < GATT.attributeCount() && i <= (find_type_req->end_handle - 1); i++) { // BLELocalAttribute* attribute = GATT.attribute(i); - // if ((attribute->type() == find_by_type_req->type) && (attribute->uuidLength() == value_length) && memcmp(attribute->uuidData(), value, value_length) == 0) { + // if ((attribute->type() == find_type_req->type) && (attribute->uuidLength() == value_length) && memcmp(attribute->uuidData(), value, value_length) == 0) { // BLELocalService* service = (BLELocalService*)attribute; // // add the start handle @@ -880,15 +969,15 @@ STATIC void process_find_by_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t } } -void process_read_by_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { +void process_read_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { struct bt_att_read_group_req *req = (struct bt_att_read_group_req *) data; uint16_t type_uuid = req->uuid[0] | (req->uuid[1] << 8); // We only support returning services for BT_ATT_OP_READ_GROUP_REQ, which is typically used // for service discovery. if (dlen != sizeof(struct bt_att_read_group_req) + sizeof(type_uuid) || - (type_uuid != BLE_TYPE_PRIMARY_SERVICE && - type_uuid != BLE_TYPE_SECONDARY_SERVICE)) { + (type_uuid != BLE_TYPE_SERVICE_PRIMARY && + type_uuid != BLE_TYPE_SERVICE_SECONDARY)) { send_error(conn_handle, BT_ATT_OP_READ_GROUP_REQ, req->start_handle, BT_ATT_ERR_UNSUPPORTED_GROUP_TYPE); return; } @@ -927,37 +1016,34 @@ void process_read_by_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, } mp_obj_t *attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); - if (type_uuid != bleio_attribute_type_uuid(attribute_obj)) { - // Not a primary or secondary service. - continue; - } - // Now we know it's a service. - bleio_service_obj_t *service = MP_OBJ_TO_PTR(attribute_obj); - - // Is this a 16-bit or a 128-bit uuid? It must match in size with any previous attribute - // in this transmission. - const uint32_t sizeof_service_uuid = common_hal_bleio_uuid_get_size(service->uuid) / 8; - if (sizeof_first_service_uuid == 0) { - sizeof_first_service_uuid = sizeof_service_uuid; - data_length += sizeof_service_uuid; - } else if (sizeof_first_service_uuid != sizeof_service_uuid) { - // Mismatched sizes, which can't be in the same batch. - // Transmit just what we have so far in this batch. - break; - } - + if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_service_type)) { + bleio_service_obj_t *service = MP_OBJ_TO_PTR(attribute_obj); + + // Is this a 16-bit or a 128-bit uuid? It must match in size with any previous attribute + // in this transmission. + const uint32_t sizeof_service_uuid = common_hal_bleio_uuid_get_size(service->uuid) / 8; + if (sizeof_first_service_uuid == 0) { + sizeof_first_service_uuid = sizeof_service_uuid; + data_length += sizeof_service_uuid; + } else if (sizeof_first_service_uuid != sizeof_service_uuid) { + // Mismatched sizes, which can't be in the same batch. + // Transmit just what we have so far in this batch. + break; + } - // Pass the length of ONE bt_att_group_data chunk. There may be multiple ones in this transmission. - rsp->r.len = data_length; + // Pass the length of ONE bt_att_group_data chunk. + // There may be multiple chunks in this transmission. + rsp->r.len = data_length; - struct bt_att_group_data *group_data = (struct bt_att_group_data *) &rsp_bytes[rsp_length]; + struct bt_att_group_data *group_data = (struct bt_att_group_data *) &rsp_bytes[rsp_length]; - group_data->start_handle = service->start_handle; - group_data->end_handle = service->end_handle; - common_hal_bleio_uuid_pack_into(service->uuid, group_data->value); + group_data->start_handle = service->start_handle; + group_data->end_handle = service->end_handle; + common_hal_bleio_uuid_pack_into(service->uuid, group_data->value); - rsp_length += data_length; - no_data = false; + rsp_length += data_length; + no_data = false; + } } if (no_data) { @@ -967,7 +1053,7 @@ void process_read_by_group_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, } } -int att_read_by_group_req(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid, uint8_t response_buffer[]) { +int att_read_group_req(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, uint16_t uuid, uint8_t response_buffer[]) { struct __packed { struct bt_att_hdr h; struct bt_att_read_group_req r; @@ -985,7 +1071,7 @@ int att_read_by_group_req(uint16_t conn_handle, uint16_t start_handle, uint16_t return send_req_wait_for_rsp(conn_handle, sizeof(req), (uint8_t *) &req, response_buffer); } -STATIC void process_read_by_group_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { +STATIC void process_read_group_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { if (dlen < 2) { return; // invalid, drop } @@ -1040,7 +1126,7 @@ STATIC void process_read_or_read_blob_req(uint16_t conn_handle, uint16_t mtu, ui //FIX BLELocalAttribute* attribute = GATT.attribute(handle - 1); // enum BLEAttributeType attributeType = attribute->type(); - // if (attributeType == BLE_TYPE_PRIMARY_SERVICE) { + // if (attributeType == BLE_TYPE_SERVICE_PRIMARY) { // if (offset) { // send_error(conn_handle, BT_ATT_ERR_ATTR_NOT_LONG, handle, BT_ATT_ERR_INVALID_PDU); // return; @@ -1118,110 +1204,156 @@ STATIC void process_read_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) check_and_save_expected_rsp(conn_handle, BT_ATT_OP_READ_RSP, dlen, data); } -STATIC void process_read_by_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { +STATIC void process_read_type_req(uint16_t conn_handle, uint16_t mtu, uint8_t dlen, uint8_t data[]) { struct bt_att_read_type_req *req = (struct bt_att_read_type_req *) data; + uint16_t type_uuid = req->uuid[0] | (req->uuid[1] << 8); - if (dlen != sizeof(struct bt_att_read_type_req)) { + if (dlen != sizeof(struct bt_att_read_type_req) + sizeof(type_uuid)) { send_error(conn_handle, BT_ATT_OP_READ_TYPE_REQ, req->start_handle, BT_ATT_ERR_INVALID_PDU); return; } - // uint8_t response[mtu]; - // uint16_t response_length; + typedef struct __packed { + struct bt_att_hdr h; + struct bt_att_read_type_rsp r; + } rsp_t; - // response[0] = BT_ATT_OP_READ_TYPE_RSP; - // response[1] = 0x00; - // response_length = 2; + uint8_t rsp_bytes[mtu]; + rsp_t *rsp = (rsp_t *) rsp_bytes; + rsp->h.code = BT_ATT_OP_READ_TYPE_RSP; + rsp->r.len = 0; - // for (uint16_t i = (req->start_handle - 1); i < GATT.attributeCount() && i <= (req->end_handle - 1); i++) { - // BLELocalAttribute* attribute = GATT.attribute(i); - // uint16_t handle = (i + 1); + // Keeps track of total length of the response. + size_t rsp_length = sizeof(rsp_t); - // if (attribute->type() == readByTypeReq->uuid) { - // if (attribute->type() == BLE_TYPE_CHARACTERISTIC) { - // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; + bool no_data = true; - // if (characteristic->value_handle() == handle) { - // // value handle, skip - // continue; - // } + // All the data chunks must have uuid's that are the same size. + // Keep track of the first one to make sure. + size_t sizeof_first_uuid = 0; - // int uuidLen = attribute->uuidLength(); - // int typeSize = (uuidLen == 2) ? 7 : 21; + // Size of a single bt_att_data chunk. Start with the initial size, and + // add the uuid size and other data sizes in the loop below. + size_t data_length = sizeof(struct bt_att_data); - // if (response[1] == 0) { - // response[1] = typeSize; - // } + const uint16_t max_attribute_handle = bleio_adapter_max_attribute_handle(&common_hal_bleio_adapter_obj); + for (uint16_t handle = req->start_handle; + handle <= max_attribute_handle && handle <= req->end_handle; + handle++) { - // if (response[1] != typeSize) { - // // all done, wrong size - // break; - // } + if (rsp_length + data_length > mtu) { + // The next possible bt_att_data chunk won't fit. The response is full. + break; + } - // // add the handle - // memcpy(&response[response_length], &handle, sizeof(handle)); - // response_length += sizeof(handle); + mp_obj_t *attribute_obj = bleio_adapter_get_attribute(&common_hal_bleio_adapter_obj, handle); - // // add the properties - // response[response_length++] = characteristic->properties(); + if (type_uuid == BLE_TYPE_CHARACTERISTIC && + MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { + // Request is for characteristic declarations. + bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); + + if (characteristic->handle == handle) { + // If the characteristic's handle is this attribute's handle, skip it: + // it's the attribute for characteristic value. We want to return the declaration + // handle attribute instead. (It will probably get skipped below, by the + // handle++). + continue; + } - // // add the value handle - // uint16_t value_handle = (handle + 1); - // memcpy(&response[response_length], &value_handle, sizeof(value_handle)); - // response_length += sizeof(value_handle); + // Is this a 16-bit or a 128-bit uuid? It must match in size with any previous attribute + // in this transmission. + const uint32_t sizeof_uuid = common_hal_bleio_uuid_get_size(characteristic->uuid) / 8; + if (sizeof_first_uuid == 0) { + sizeof_first_uuid = sizeof_uuid; + data_length += sizeof_uuid; + data_length += sizeof(characteristic_declaration_t); + } else if (sizeof_first_uuid != sizeof_uuid) { + // Mismatched sizes, which can't be in the same batch. + // Transmit just what we have so far in this batch. + break; + } - // // add the UUID - // memcpy(&response[response_length], characteristic->uuidData(), uuidLen); - // response_length += uuidLen; + // Pass the length of ONE bt_att_data chunk. + // There may be multiple chunks in this transmission. + rsp->r.len = data_length; - // // skip the next handle, it's a value handle - // i++; + struct bt_att_data *att_data = (struct bt_att_data *) &rsp_bytes[rsp_length]; - // if ((response_length + typeSize) > mtu) { - // break; - // } - // } else if (attribute->type() == 0x2902) { - // BLELocalDescriptor* descriptor = (BLELocalDescriptor*)attribute; + att_data->handle = characteristic->decl_handle; - // // add the handle - // memcpy(&response[response_length], &handle, sizeof(handle)); - // response_length += sizeof(handle); + characteristic_declaration_t *char_decl = (characteristic_declaration_t *) att_data->value; - // // add the value - // int valueSize = min((uint16_t)(mtu - response_length), (uint16_t)descriptor->valueSize()); - // memcpy(&response[response_length], descriptor->value(), valueSize); - // response_length += valueSize; + // Convert from the bleio properties bit values to the BLE spec properties bit values. + // They are not the same :(. + char_decl->properties = bleio_properties_to_ble_spec_properties(characteristic->props); + char_decl->value_handle = characteristic->handle; + common_hal_bleio_uuid_pack_into(characteristic->uuid, char_decl->uuid); - // response[1] = 2 + valueSize; + // We know the next handle will be the characteristic value handle, so skip it. + handle++; - // break; // all done - // } - // } else if (attribute->type() == BLE_TYPE_CHARACTERISTIC && attribute->uuidLength() == 2 && memcmp(&readByTypeReq->uuid, attribute->uuidData(), 2) == 0) { - // BLELocalCharacteristic* characteristic = (BLELocalCharacteristic*)attribute; + rsp_length += data_length; + no_data = false; - // // add the handle - // memcpy(&response[response_length], &handle, sizeof(handle)); - // response_length += sizeof(handle); + } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_descriptor_type)) { + // See if request is for a descriptor value with a 16-bit UUID, such as the CCCD. + bleio_descriptor_obj_t *descriptor = MP_OBJ_TO_PTR(attribute_obj); + if (common_hal_bleio_uuid_get_size(descriptor->uuid) == 16 && + common_hal_bleio_uuid_get_uuid16(descriptor->uuid) == type_uuid) { - // // add the value - // int value_length = min((uint16_t)(mtu - response_length), (uint16_t)characteristic->value_length()); - // memcpy(&response[response_length], characteristic->value(), value_length); - // response_length += value_length; + struct bt_att_data *att_data = (struct bt_att_data *) &rsp_bytes[rsp_length]; - // response[1] = 2 + value_length; + att_data->handle = handle; - // break; // all done - // } - // } + mp_buffer_info_t bufinfo; + if (!mp_get_buffer(descriptor->value, &bufinfo, MP_BUFFER_READ)) { + break; + } + uint16_t value_size = MIN(mtu - rsp_length, bufinfo.len); + memcpy(att_data->value, bufinfo.buf, value_size); + rsp_length += value_size; - // if (response_length == 2) { - // send_error(conn_handle, BT_ATT_OP_READ_BY_TYPE_REQ, readByTypeReq->start_handle, BT_ATT_ERR_ATTR_NOT_FOUND); - // } else { - // hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, response_length, response); - // } + // Only return one descriptor value. + no_data = false; + break; + } + + } else if (MP_OBJ_IS_TYPE(attribute_obj, &bleio_characteristic_type)) { + // See if request is for a characteristic value with a 16-bit UUID. + bleio_characteristic_obj_t *characteristic = MP_OBJ_TO_PTR(attribute_obj); + if (common_hal_bleio_uuid_get_size(characteristic->uuid) == 16 && + common_hal_bleio_uuid_get_uuid16(characteristic->uuid) == type_uuid) { + + struct bt_att_data *att_data = (struct bt_att_data *) &rsp_bytes[rsp_length]; + + att_data->handle = handle; + + mp_buffer_info_t bufinfo; + if (!mp_get_buffer(characteristic->value, &bufinfo, MP_BUFFER_READ)) { + // This shouldn't happen. There should be a buf in characteristic->value. + break; + } + uint16_t value_size = MIN(mtu - rsp_length, bufinfo.len); + memcpy(att_data->value, bufinfo.buf, value_size); + rsp_length += value_size; + + // Only return one characteristic value. + no_data = false; + break; + } + } + } // end for loop + + if (no_data) { + send_error(conn_handle, BT_ATT_OP_READ_TYPE_REQ, + req->start_handle, BT_ATT_ERR_ATTRIBUTE_NOT_FOUND); + } else { + hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, rsp_length, rsp_bytes); + } } -int att_read_by_type_req(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, uint16_t type, uint8_t response_buffer[]) { +int att_read_type_req(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, uint16_t type, uint8_t response_buffer[]) { struct __packed { struct bt_att_hdr h; struct bt_att_read_type_req r; @@ -1238,7 +1370,7 @@ int att_read_by_type_req(uint16_t conn_handle, uint16_t start_handle, uint16_t e return send_req_wait_for_rsp(conn_handle, sizeof(req), (uint8_t *) &req, response_buffer); } -STATIC void process_read_by_type_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { +STATIC void process_read_type_rsp(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { if (dlen < 1) { return; // invalid, drop } @@ -1597,23 +1729,23 @@ void att_process_data(uint16_t conn_handle, uint8_t dlen, uint8_t data[]) { break; case BT_ATT_OP_FIND_TYPE_REQ: - process_find_by_type_req(conn_handle, mtu, dlen, data); + process_find_type_req(conn_handle, mtu, dlen, data); break; case BT_ATT_OP_READ_TYPE_REQ: - process_read_by_type_req(conn_handle, mtu, dlen, data); + process_read_type_req(conn_handle, mtu, dlen, data); break; case BT_ATT_OP_READ_TYPE_RSP: - process_read_by_type_rsp(conn_handle, dlen, data); + process_read_type_rsp(conn_handle, dlen, data); break; case BT_ATT_OP_READ_GROUP_REQ: - process_read_by_group_req(conn_handle, mtu, dlen, data); + process_read_group_req(conn_handle, mtu, dlen, data); break; case BT_ATT_OP_READ_GROUP_RSP: - process_read_by_group_rsp(conn_handle, dlen, data); + process_read_group_rsp(conn_handle, dlen, data); break; case BT_ATT_OP_READ_REQ: diff --git a/ports/nrf/common-hal/_bleio/UUID.c b/ports/nrf/common-hal/_bleio/UUID.c index f80352ccb..0c79e980e 100644 --- a/ports/nrf/common-hal/_bleio/UUID.c +++ b/ports/nrf/common-hal/_bleio/UUID.c @@ -40,7 +40,7 @@ // If uuid128 is NULL, this is a Bluetooth SIG 16-bit UUID. // If uuid128 is not NULL, it's a 128-bit (16-byte) UUID, with bytes 12 and 13 zero'd out, where // the 16-bit part goes. Those 16 bits are passed in uuid16. -void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, uint32_t uuid16, const uint8_t uuid128[16]) { +void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, const uint8_t uuid128[16]) { self->nrf_ble_uuid.uuid = uuid16; if (uuid128 == NULL) { self->nrf_ble_uuid.type = BLE_UUID_TYPE_BLE; diff --git a/shared-bindings/_bleio/UUID.c b/shared-bindings/_bleio/UUID.c index 6d92cf793..93f89403b 100644 --- a/shared-bindings/_bleio/UUID.c +++ b/shared-bindings/_bleio/UUID.c @@ -283,7 +283,7 @@ void bleio_uuid_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t mp_printf(print, "UUID(0x%04x)", common_hal_bleio_uuid_get_uuid16(self)); } else { uint8_t uuid128[16]; - (void) common_hal_bleio_uuid_get_uuid128(self, uuid128); + common_hal_bleio_uuid_get_uuid128(self, uuid128); mp_printf(print, "UUID('" "%02x%02x%02x%02x-" "%02x%02x-" diff --git a/shared-bindings/_bleio/UUID.h b/shared-bindings/_bleio/UUID.h index 178b0ca96..b10cce67f 100644 --- a/shared-bindings/_bleio/UUID.h +++ b/shared-bindings/_bleio/UUID.h @@ -36,7 +36,7 @@ extern const mp_obj_type_t bleio_uuid_type; extern void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, const uint8_t uuid128[16]); extern uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self); -extern bool common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]); +extern void common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]); extern uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self); void common_hal_bleio_uuid_pack_into(bleio_uuid_obj_t *self, uint8_t* buf); diff --git a/shared-module/_bleio/Characteristic.h b/shared-module/_bleio/Characteristic.h index 409a57c76..7776b1fa5 100644 --- a/shared-module/_bleio/Characteristic.h +++ b/shared-module/_bleio/Characteristic.h @@ -27,6 +27,9 @@ #ifndef MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H #define MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H +// These are not the Bluetooth spec values. They are what is used by the Nordic SoftDevice. +// The bit values are in different positions. + typedef enum { CHAR_PROP_NONE = 0, CHAR_PROP_BROADCAST = 1u << 0, @@ -40,4 +43,14 @@ typedef enum { } bleio_characteristic_properties_enum_t; typedef uint8_t bleio_characteristic_properties_t; +// Bluetooth spec property values +#define BT_GATT_CHRC_BROADCAST 0x01 +#define BT_GATT_CHRC_READ 0x02 +#define BT_GATT_CHRC_WRITE_WITHOUT_RESP 0x04 +#define BT_GATT_CHRC_WRITE 0x08 +#define BT_GATT_CHRC_NOTIFY 0x10 +#define BT_GATT_CHRC_INDICATE 0x20 +#define BT_GATT_CHRC_AUTH 0x40 +#define BT_GATT_CHRC_EXT_PROP 0x80 + #endif // MICROPY_INCLUDED_SHARED_MODULE_BLEIO_CHARACTERISTIC_H -- cgit v1.2.3 From ef1782f85e9020a01658d28708b44444915f74b2 Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Mon, 10 Aug 2020 12:04:44 -0400 Subject: fix trailing whitespace --- shared-bindings/_pixelbuf/PixelBuf.c | 2 +- shared-module/_pixelbuf/PixelBuf.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/_pixelbuf/PixelBuf.c b/shared-bindings/_pixelbuf/PixelBuf.c index 758801e51..1ffca7edf 100644 --- a/shared-bindings/_pixelbuf/PixelBuf.c +++ b/shared-bindings/_pixelbuf/PixelBuf.c @@ -331,7 +331,7 @@ STATIC mp_obj_t pixelbuf_pixelbuf_subscr(mp_obj_t self_in, mp_obj_t index_in, mp #if MICROPY_PY_ARRAY_SLICE_ASSIGN size_t num_items = mp_obj_get_int(mp_obj_len(value)); - + if (num_items != slice_len && num_items != (slice_len * common_hal__pixelbuf_pixelbuf_get_bpp(self_in))) { mp_raise_ValueError_varg(translate("Unmatched number of items on RHS (expected %d, got %d)."), slice_len, num_items); } diff --git a/shared-module/_pixelbuf/PixelBuf.c b/shared-module/_pixelbuf/PixelBuf.c index 50906fcc1..0dc2a5ab8 100644 --- a/shared-module/_pixelbuf/PixelBuf.c +++ b/shared-module/_pixelbuf/PixelBuf.c @@ -139,7 +139,7 @@ uint8_t _pixelbuf_get_as_uint8(mp_obj_t obj) { return mp_obj_get_int_truncated(obj); } else if (mp_obj_is_float(obj)) { return (uint8_t)mp_obj_get_float(obj); - } + } mp_raise_TypeError_varg( translate("can't convert %q to %q"), mp_obj_get_type_qstr(obj), MP_QSTR_int); } -- cgit v1.2.3 From 1b7709f3250289ac746090306425734a5e4294a3 Mon Sep 17 00:00:00 2001 From: Roy Hooper Date: Mon, 10 Aug 2020 18:05:13 -0400 Subject: use the stack --- shared-bindings/_pixelbuf/PixelBuf.c | 14 ++++++++++++-- shared-bindings/_pixelbuf/PixelBuf.h | 2 +- shared-module/_pixelbuf/PixelBuf.c | 17 ++++++++--------- 3 files changed, 21 insertions(+), 12 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/_pixelbuf/PixelBuf.c b/shared-bindings/_pixelbuf/PixelBuf.c index 1ffca7edf..88e8aa801 100644 --- a/shared-bindings/_pixelbuf/PixelBuf.c +++ b/shared-bindings/_pixelbuf/PixelBuf.c @@ -309,6 +309,16 @@ STATIC mp_obj_t pixelbuf_pixelbuf_subscr(mp_obj_t self_in, mp_obj_t index_in, mp size_t length = common_hal__pixelbuf_pixelbuf_get_len(self_in); mp_seq_get_fast_slice_indexes(length, index_in, &slice); + static mp_obj_tuple_t flat_item_tuple = { + .base = {&mp_type_tuple}, + .len = 0, + .items = { + mp_const_none, + mp_const_none, + mp_const_none, + mp_const_none, + } + }; size_t slice_len; if (slice.step > 0) { @@ -335,8 +345,8 @@ STATIC mp_obj_t pixelbuf_pixelbuf_subscr(mp_obj_t self_in, mp_obj_t index_in, mp if (num_items != slice_len && num_items != (slice_len * common_hal__pixelbuf_pixelbuf_get_bpp(self_in))) { mp_raise_ValueError_varg(translate("Unmatched number of items on RHS (expected %d, got %d)."), slice_len, num_items); } - - common_hal__pixelbuf_pixelbuf_set_pixels(self_in, slice.start, slice.step, slice_len, value, num_items != slice_len); + common_hal__pixelbuf_pixelbuf_set_pixels(self_in, slice.start, slice.step, slice_len, value, + num_items != slice_len ? &flat_item_tuple : mp_const_none); return mp_const_none; #else return MP_OBJ_NULL; // op not supported diff --git a/shared-bindings/_pixelbuf/PixelBuf.h b/shared-bindings/_pixelbuf/PixelBuf.h index 111223be0..d41082059 100644 --- a/shared-bindings/_pixelbuf/PixelBuf.h +++ b/shared-bindings/_pixelbuf/PixelBuf.h @@ -47,6 +47,6 @@ void common_hal__pixelbuf_pixelbuf_fill(mp_obj_t self, mp_obj_t item); void common_hal__pixelbuf_pixelbuf_show(mp_obj_t self); mp_obj_t common_hal__pixelbuf_pixelbuf_get_pixel(mp_obj_t self, size_t index); void common_hal__pixelbuf_pixelbuf_set_pixel(mp_obj_t self, size_t index, mp_obj_t item); -void common_hal__pixelbuf_pixelbuf_set_pixels(mp_obj_t self_in, size_t start, mp_int_t step, size_t slice_len, mp_obj_t* values, bool flattened); +void common_hal__pixelbuf_pixelbuf_set_pixels(mp_obj_t self_in, size_t start, mp_int_t step, size_t slice_len, mp_obj_t* values, mp_obj_tuple_t *flatten_to); #endif // CP_SHARED_BINDINGS_PIXELBUF_PIXELBUF_H diff --git a/shared-module/_pixelbuf/PixelBuf.c b/shared-module/_pixelbuf/PixelBuf.c index 0dc2a5ab8..f3e679631 100644 --- a/shared-module/_pixelbuf/PixelBuf.c +++ b/shared-module/_pixelbuf/PixelBuf.c @@ -230,22 +230,21 @@ void _pixelbuf_set_pixel(pixelbuf_pixelbuf_obj_t* self, size_t index, mp_obj_t v _pixelbuf_set_pixel_color(self, index, r, g, b, w); } -void common_hal__pixelbuf_pixelbuf_set_pixels(mp_obj_t self_in, size_t start, mp_int_t step, size_t slice_len, mp_obj_t* values, bool flattened) { +void common_hal__pixelbuf_pixelbuf_set_pixels(mp_obj_t self_in, size_t start, mp_int_t step, size_t slice_len, mp_obj_t* values, + mp_obj_tuple_t *flatten_to) +{ pixelbuf_pixelbuf_obj_t* self = native_pixelbuf(self_in); mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(values, &iter_buf); mp_obj_t item; size_t i = 0; - mp_obj_tuple_t *tuple; - uint bpp = self->bytes_per_pixel; - if (flattened) { - tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(bpp, NULL)); - } + bool flattened = flatten_to != mp_const_none; + if (flattened) flatten_to->len = self->bytes_per_pixel; while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { if (flattened) { - tuple->items[i % bpp] = item; - if (++i % bpp == 0) { - _pixelbuf_set_pixel(self, start, tuple); + flatten_to->items[i % self->bytes_per_pixel] = item; + if (++i % self->bytes_per_pixel == 0) { + _pixelbuf_set_pixel(self, start, flatten_to); start+=step; } } else { -- cgit v1.2.3 From ffc488e748890976fe1923c5503300f66064d904 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 31 Jul 2020 14:34:24 -0500 Subject: framebufferio: Fix crash calling unimplemented get_brightness If set_brightness was implemented but get_brightness wasn't, this would hard fault --- shared-module/framebufferio/FramebufferDisplay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 2a90fa0d4..73917b1a3 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -109,7 +109,7 @@ bool common_hal_framebufferio_framebufferdisplay_set_auto_brightness(framebuffer } mp_float_t common_hal_framebufferio_framebufferdisplay_get_brightness(framebufferio_framebufferdisplay_obj_t* self) { - if (self->framebuffer_protocol->set_brightness) { + if (self->framebuffer_protocol->get_brightness) { return self->framebuffer_protocol->get_brightness(self->framebuffer); } return -1; -- cgit v1.2.3 From 5a7b2a20381513797b4e548684f8af5af46be0fa Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 31 Jul 2020 14:35:00 -0500 Subject: framebufferio: Don't call swapbuffers unnecessarily --- shared-module/framebufferio/FramebufferDisplay.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'shared-module') diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 73917b1a3..fed3352aa 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -219,12 +219,14 @@ STATIC void _refresh_display(framebufferio_framebufferdisplay_obj_t* self) { displayio_display_core_start_refresh(&self->core); self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); const displayio_area_t* current_area = _get_refresh_areas(self); - while (current_area != NULL) { - _refresh_area(self, current_area); - current_area = current_area->next; + if (current_area) { + while (current_area != NULL) { + _refresh_area(self, current_area); + current_area = current_area->next; + } + self->framebuffer_protocol->swapbuffers(self->framebuffer); } displayio_display_core_finish_refresh(&self->core); - self->framebuffer_protocol->swapbuffers(self->framebuffer); } void common_hal_framebufferio_framebufferdisplay_set_rotation(framebufferio_framebufferdisplay_obj_t* self, int rotation){ -- cgit v1.2.3 From 6d19a098888236c7442e563bae90b09630fbefe2 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 31 Jul 2020 14:35:50 -0500 Subject: framebufferio: Set type to none when releasing This avoids the message "Too many displays in use" when they are released directly, rather than via release_displays(). --- shared-module/framebufferio/FramebufferDisplay.c | 1 + 1 file changed, 1 insertion(+) (limited to 'shared-module') diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index fed3352aa..d21a103e2 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -309,6 +309,7 @@ void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) { common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, false); release_display_core(&self->core); self->framebuffer_protocol->deinit(self->framebuffer); + self->base.type = &mp_type_NoneType; } void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) { -- cgit v1.2.3 From a84cc19499e1cb71387cb5be379676d0c8b84f9a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 31 Jul 2020 15:46:07 -0500 Subject: framebufferio: Handle 1 (tested), 2, and 4 bpp displays --- shared-module/framebufferio/FramebufferDisplay.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'shared-module') diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index d21a103e2..b00797537 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -147,6 +147,14 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di return true; } uint16_t subrectangles = 1; + + // If pixels are packed by row then rows are on byte boundaries + if (self->core.colorspace.depth < 8 && self->core.colorspace.pixels_in_byte_share_row) { + int div = 8 / self->core.colorspace.depth; + clipped.x1 = (clipped.x1 / div) * div; + clipped.x2 = ((clipped.x2 + div - 1) / div) * div; + } + uint16_t rows_per_buffer = displayio_area_height(&clipped); uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; uint16_t pixels_per_buffer = displayio_area_size(&clipped); @@ -187,6 +195,7 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di .x2 = clipped.x2, .y2 = clipped.y1 + rows_per_buffer * (j + 1) }; + if (remaining_rows < rows_per_buffer) { subrectangle.y2 = subrectangle.y1 + remaining_rows; } @@ -197,12 +206,15 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); - // COULDDO: this arithmetic only supports multiple-of-8 bpp - uint8_t *dest = self->bufinfo.buf + (subrectangle.y1 * self->core.width + subrectangle.x1) * (self->core.colorspace.depth / 8); + uint8_t *buf = (uint8_t *)self->bufinfo.buf, *endbuf = buf + self->bufinfo.len; + (void)endbuf; // Hint to compiler that endbuf is "used" even if NDEBUG + + uint8_t *dest = self->bufinfo.buf + (subrectangle.y1 * self->core.width + subrectangle.x1) * self->core.colorspace.depth / 8; uint8_t *src = (uint8_t*)buffer; - size_t rowsize = (subrectangle.x2 - subrectangle.x1) * (self->core.colorspace.depth / 8); - size_t rowstride = self->core.width * (self->core.colorspace.depth/8); + size_t rowsize = (subrectangle.x2 - subrectangle.x1) * self->core.colorspace.depth / 8; + size_t rowstride = self->core.width * self->core.colorspace.depth/8; for (uint16_t i = subrectangle.y1; i < subrectangle.y2; i++) { + assert(dest >= buf && dest < endbuf && dest+rowsize <= endbuf); memcpy(dest, src, rowsize); dest += rowstride; src += rowsize; -- cgit v1.2.3 From 8021f3b4cbb96e0edaf139fa88ea7273c92a5493 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 31 Jul 2020 15:46:39 -0500 Subject: framebufferio: handle sharp memory displays A bit of cheating; we need to add a protocol getter for reverse_bytes_in_word --- shared-module/framebufferio/FramebufferDisplay.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'shared-module') diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index b00797537..190d3cb9d 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -51,7 +51,7 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu uint16_t ram_width = 0x100; uint16_t ram_height = 0x100; - + uint16_t depth = self->framebuffer_protocol->get_color_depth(self->framebuffer); displayio_display_core_construct( &self->core, NULL, @@ -62,12 +62,13 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu 0, 0, rotation, - self->framebuffer_protocol->get_color_depth(self->framebuffer), - false, - false, + depth, + (depth < 12), // grayscale + true, // pixels_in_byte_share_row self->framebuffer_protocol->get_bytes_per_cell(self->framebuffer), - false, - false); + true, // reverse_pixels_in_byte + false // reverse_bytes_in_word + ); self->first_manual_refresh = !auto_refresh; -- cgit v1.2.3 From a33e48c065093212729e620bb22da5ca327fabe4 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 6 Aug 2020 14:28:10 -0500 Subject: framebufferio: add "first pixel offset" and "row stride" --- shared-module/framebufferio/FramebufferDisplay.c | 17 ++++++++++++++--- shared-module/framebufferio/FramebufferDisplay.h | 5 +++++ 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'shared-module') diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 190d3cb9d..e16777b83 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -70,6 +70,15 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu false // reverse_bytes_in_word ); + self->first_pixel_offset = self->framebuffer_protocol->get_first_pixel_offset + ? self->framebuffer_protocol->get_first_pixel_offset(self->framebuffer) + : 0; + self->row_stride = self->framebuffer_protocol->get_row_stride + ? self->framebuffer_protocol->get_row_stride(self->framebuffer) + : 0; + if (self->row_stride == 0) { + self->row_stride = self->core.width * self->core.colorspace.depth/8; + } self->first_manual_refresh = !auto_refresh; self->native_frames_per_second = self->framebuffer_protocol->get_native_frames_per_second(self->framebuffer); @@ -209,11 +218,13 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di uint8_t *buf = (uint8_t *)self->bufinfo.buf, *endbuf = buf + self->bufinfo.len; (void)endbuf; // Hint to compiler that endbuf is "used" even if NDEBUG + buf += self->first_pixel_offset; - uint8_t *dest = self->bufinfo.buf + (subrectangle.y1 * self->core.width + subrectangle.x1) * self->core.colorspace.depth / 8; + size_t rowstride = self->row_stride; + uint8_t *dest = buf + subrectangle.y1 * rowstride + subrectangle.x1 * self->core.colorspace.depth / 8; uint8_t *src = (uint8_t*)buffer; size_t rowsize = (subrectangle.x2 - subrectangle.x1) * self->core.colorspace.depth / 8; - size_t rowstride = self->core.width * self->core.colorspace.depth/8; + for (uint16_t i = subrectangle.y1; i < subrectangle.y2; i++) { assert(dest >= buf && dest < endbuf && dest+rowsize <= endbuf); memcpy(dest, src, rowsize); @@ -230,9 +241,9 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di STATIC void _refresh_display(framebufferio_framebufferdisplay_obj_t* self) { displayio_display_core_start_refresh(&self->core); - self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); const displayio_area_t* current_area = _get_refresh_areas(self); if (current_area) { + self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); while (current_area != NULL) { _refresh_area(self, current_area); current_area = current_area->next; diff --git a/shared-module/framebufferio/FramebufferDisplay.h b/shared-module/framebufferio/FramebufferDisplay.h index ca1ab984a..1d207039a 100644 --- a/shared-module/framebufferio/FramebufferDisplay.h +++ b/shared-module/framebufferio/FramebufferDisplay.h @@ -48,6 +48,7 @@ typedef struct { uint64_t last_refresh_call; uint16_t native_frames_per_second; uint16_t native_ms_per_frame; + uint16_t first_pixel_offset, row_stride; bool auto_refresh; bool first_manual_refresh; } framebufferio_framebufferdisplay_obj_t; @@ -70,6 +71,8 @@ typedef bool (*framebuffer_set_auto_brightness_fun)(mp_obj_t, bool); typedef bool (*framebuffer_get_auto_brightness_fun)(mp_obj_t); typedef int (*framebuffer_get_width_fun)(mp_obj_t); typedef int (*framebuffer_get_height_fun)(mp_obj_t); +typedef int (*framebuffer_get_row_stride_fun)(mp_obj_t); +typedef int (*framebuffer_get_first_pixel_offset_fun)(mp_obj_t); typedef int (*framebuffer_get_color_depth_fun)(mp_obj_t); typedef int (*framebuffer_get_bytes_per_cell_fun)(mp_obj_t); typedef int (*framebuffer_get_native_frames_per_second_fun)(mp_obj_t); @@ -86,6 +89,8 @@ typedef struct _framebuffer_p_t { framebuffer_get_native_frames_per_second_fun get_native_frames_per_second; framebuffer_get_brightness_fun get_brightness; framebuffer_set_brightness_fun set_brightness; + framebuffer_get_row_stride_fun get_row_stride; + framebuffer_get_first_pixel_offset_fun get_first_pixel_offset; framebuffer_get_auto_brightness_fun get_auto_brightness; framebuffer_set_auto_brightness_fun set_auto_brightness; } framebuffer_p_t; -- cgit v1.2.3 From 1ee2062c1b64ecfda0af49cb0f721573aad7dea4 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 6 Aug 2020 14:28:22 -0500 Subject: framebufferio: Check early if framebuffer is big enough --- shared-module/framebufferio/FramebufferDisplay.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'shared-module') diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index e16777b83..230dd6991 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -79,6 +79,13 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu if (self->row_stride == 0) { self->row_stride = self->core.width * self->core.colorspace.depth/8; } + + self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); + size_t framebuffer_size = self->first_pixel_offset + self->row_stride * self->core.height; + if (self->bufinfo.len < framebuffer_size) { + mp_raise_IndexError_varg(translate("Framebuffer requires %d bytes"), framebuffer_size); + } + self->first_manual_refresh = !auto_refresh; self->native_frames_per_second = self->framebuffer_protocol->get_native_frames_per_second(self->framebuffer); -- cgit v1.2.3 From 5e4ed9341586c3444409feeb61237e86a5c74c6f Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 6 Aug 2020 14:46:54 -0500 Subject: framebufferio: Add getters for remaining displayio_display_core_construct arguments .. and introduce a convenience macro that helps many of them be required (if their values match defaults or are inapplicable) --- shared-module/framebufferio/FramebufferDisplay.c | 27 ++++++------- shared-module/framebufferio/FramebufferDisplay.h | 48 ++++++++++++++++-------- 2 files changed, 46 insertions(+), 29 deletions(-) (limited to 'shared-module') diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 230dd6991..37989c29f 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -40,6 +40,11 @@ #include #include +#define fb_getter_default(method, default_value) \ + (self->framebuffer_protocol->method \ + ? self->framebuffer_protocol->method(self->framebuffer) \ + : (default_value)) + void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebufferdisplay_obj_t* self, mp_obj_t framebuffer, uint16_t rotation, @@ -51,7 +56,7 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu uint16_t ram_width = 0x100; uint16_t ram_height = 0x100; - uint16_t depth = self->framebuffer_protocol->get_color_depth(self->framebuffer); + uint16_t depth = fb_getter_default(get_color_depth, 16); displayio_display_core_construct( &self->core, NULL, @@ -63,19 +68,15 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu 0, rotation, depth, - (depth < 12), // grayscale - true, // pixels_in_byte_share_row - self->framebuffer_protocol->get_bytes_per_cell(self->framebuffer), - true, // reverse_pixels_in_byte - false // reverse_bytes_in_word + fb_getter_default(get_grayscale, (depth < 8)), + fb_getter_default(get_pixels_in_byte_share_row, false), + fb_getter_default(get_bytes_per_cell, 2), + fb_getter_default(get_reverse_pixels_in_byte, false), + fb_getter_default(get_reverse_pixels_in_word, false) ); - self->first_pixel_offset = self->framebuffer_protocol->get_first_pixel_offset - ? self->framebuffer_protocol->get_first_pixel_offset(self->framebuffer) - : 0; - self->row_stride = self->framebuffer_protocol->get_row_stride - ? self->framebuffer_protocol->get_row_stride(self->framebuffer) - : 0; + self->first_pixel_offset = fb_getter_default(get_first_pixel_offset, 0); + self->row_stride = fb_getter_default(get_row_stride, 0); if (self->row_stride == 0) { self->row_stride = self->core.width * self->core.colorspace.depth/8; } @@ -88,7 +89,7 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu self->first_manual_refresh = !auto_refresh; - self->native_frames_per_second = self->framebuffer_protocol->get_native_frames_per_second(self->framebuffer); + self->native_frames_per_second = fb_getter_default(get_native_frames_per_second, 60); self->native_ms_per_frame = 1000 / self->native_frames_per_second; supervisor_start_terminal(self->core.width, self->core.height); diff --git a/shared-module/framebufferio/FramebufferDisplay.h b/shared-module/framebufferio/FramebufferDisplay.h index 1d207039a..93ad0118a 100644 --- a/shared-module/framebufferio/FramebufferDisplay.h +++ b/shared-module/framebufferio/FramebufferDisplay.h @@ -62,35 +62,51 @@ void framebufferio_framebufferdisplay_collect_ptrs(framebufferio_framebufferdisp mp_obj_t common_hal_framebufferio_framebufferdisplay_get_framebuffer(framebufferio_framebufferdisplay_obj_t* self); -typedef void (*framebuffer_get_bufinfo_fun)(mp_obj_t, mp_buffer_info_t *bufinfo); -typedef void (*framebuffer_swapbuffers_fun)(mp_obj_t); -typedef void (*framebuffer_deinit_fun)(mp_obj_t); -typedef bool (*framebuffer_set_brightness_fun)(mp_obj_t, mp_float_t); -typedef mp_float_t (*framebuffer_get_brightness_fun)(mp_obj_t); -typedef bool (*framebuffer_set_auto_brightness_fun)(mp_obj_t, bool); typedef bool (*framebuffer_get_auto_brightness_fun)(mp_obj_t); -typedef int (*framebuffer_get_width_fun)(mp_obj_t); -typedef int (*framebuffer_get_height_fun)(mp_obj_t); -typedef int (*framebuffer_get_row_stride_fun)(mp_obj_t); -typedef int (*framebuffer_get_first_pixel_offset_fun)(mp_obj_t); -typedef int (*framebuffer_get_color_depth_fun)(mp_obj_t); +typedef bool (*framebuffer_get_reverse_pixels_in_byte_fun)(mp_obj_t); +typedef bool (*framebuffer_get_reverse_pixels_in_word_fun)(mp_obj_t); +typedef bool (*framebuffer_set_auto_brightness_fun)(mp_obj_t, bool); +typedef bool (*framebuffer_set_brightness_fun)(mp_obj_t, mp_float_t); typedef int (*framebuffer_get_bytes_per_cell_fun)(mp_obj_t); +typedef int (*framebuffer_get_color_depth_fun)(mp_obj_t); +typedef int (*framebuffer_get_first_pixel_offset_fun)(mp_obj_t); +typedef int (*framebuffer_get_grayscale_fun)(mp_obj_t); +typedef int (*framebuffer_get_height_fun)(mp_obj_t); typedef int (*framebuffer_get_native_frames_per_second_fun)(mp_obj_t); +typedef int (*framebuffer_get_pixels_in_byte_share_row_fun)(mp_obj_t); +typedef int (*framebuffer_get_row_stride_fun)(mp_obj_t); +typedef int (*framebuffer_get_width_fun)(mp_obj_t); +typedef mp_float_t (*framebuffer_get_brightness_fun)(mp_obj_t); +typedef void (*framebuffer_deinit_fun)(mp_obj_t); +typedef void (*framebuffer_get_bufinfo_fun)(mp_obj_t, mp_buffer_info_t *bufinfo); +typedef void (*framebuffer_swapbuffers_fun)(mp_obj_t); typedef struct _framebuffer_p_t { MP_PROTOCOL_HEAD // MP_QSTR_protocol_framebuffer + + // Mandatory framebuffer_get_bufinfo_fun get_bufinfo; framebuffer_swapbuffers_fun swapbuffers; framebuffer_deinit_fun deinit; framebuffer_get_width_fun get_width; framebuffer_get_height_fun get_height; - framebuffer_get_color_depth_fun get_color_depth; - framebuffer_get_bytes_per_cell_fun get_bytes_per_cell; - framebuffer_get_native_frames_per_second_fun get_native_frames_per_second; + + // Optional getters + framebuffer_get_bytes_per_cell_fun get_bytes_per_cell; // default: 2 + framebuffer_get_color_depth_fun get_color_depth; // default: 16 + framebuffer_get_first_pixel_offset_fun get_first_pixel_offset; // default: 0 + framebuffer_get_grayscale_fun get_grayscale; // default: grayscale if depth < 8 + framebuffer_get_native_frames_per_second_fun get_native_frames_per_second; // default: 60 + framebuffer_get_pixels_in_byte_share_row_fun get_pixels_in_byte_share_row; // default: false + framebuffer_get_reverse_pixels_in_byte_fun get_reverse_pixels_in_byte; // default: false + framebuffer_get_reverse_pixels_in_word_fun get_reverse_pixels_in_word; // default: false + framebuffer_get_row_stride_fun get_row_stride; // default: 0 (no extra row padding) + + // Optional -- default is no brightness control framebuffer_get_brightness_fun get_brightness; framebuffer_set_brightness_fun set_brightness; - framebuffer_get_row_stride_fun get_row_stride; - framebuffer_get_first_pixel_offset_fun get_first_pixel_offset; + + // Optional -- default is no automatic brightness control framebuffer_get_auto_brightness_fun get_auto_brightness; framebuffer_set_auto_brightness_fun set_auto_brightness; } framebuffer_p_t; -- cgit v1.2.3 From 9c4f644641400c7b7eea37ace73782bc1cec2691 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 6 Aug 2020 14:51:52 -0500 Subject: framebufferio: add dirty row tracking --- shared-bindings/rgbmatrix/RGBMatrix.c | 3 ++- shared-module/framebufferio/FramebufferDisplay.c | 10 +++++++--- shared-module/framebufferio/FramebufferDisplay.h | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/rgbmatrix/RGBMatrix.c b/shared-bindings/rgbmatrix/RGBMatrix.c index d6b79f5eb..9cfc0d409 100644 --- a/shared-bindings/rgbmatrix/RGBMatrix.c +++ b/shared-bindings/rgbmatrix/RGBMatrix.c @@ -352,7 +352,8 @@ STATIC void rgbmatrix_rgbmatrix_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t * // These version exists so that the prototype matches the protocol, // avoiding a type cast that can hide errors -STATIC void rgbmatrix_rgbmatrix_swapbuffers(mp_obj_t self_in) { +STATIC void rgbmatrix_rgbmatrix_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) { + (void)dirty_row_bitmap; common_hal_rgbmatrix_rgbmatrix_refresh(self_in); } diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 37989c29f..9a6797cd8 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -156,7 +156,8 @@ STATIC const displayio_area_t* _get_refresh_areas(framebufferio_framebufferdispl return NULL; } -STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const displayio_area_t* area) { +#define MARK_ROW_DIRTY(r) (dirty_row_bitmask[r/8] = (1 << (r & 7))) +STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const displayio_area_t* area, uint8_t *dirty_row_bitmask) { uint16_t buffer_size = 128; // In uint32_ts displayio_area_t clipped; @@ -235,6 +236,7 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di for (uint16_t i = subrectangle.y1; i < subrectangle.y2; i++) { assert(dest >= buf && dest < endbuf && dest+rowsize <= endbuf); + MARK_ROW_DIRTY(i); memcpy(dest, src, rowsize); dest += rowstride; src += rowsize; @@ -251,12 +253,14 @@ STATIC void _refresh_display(framebufferio_framebufferdisplay_obj_t* self) { displayio_display_core_start_refresh(&self->core); const displayio_area_t* current_area = _get_refresh_areas(self); if (current_area) { + uint8_t dirty_row_bitmask[(self->core.height + 7) / 8]; + memset(dirty_row_bitmask, 0, sizeof(dirty_row_bitmask)); self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); while (current_area != NULL) { - _refresh_area(self, current_area); + _refresh_area(self, current_area, dirty_row_bitmask); current_area = current_area->next; } - self->framebuffer_protocol->swapbuffers(self->framebuffer); + self->framebuffer_protocol->swapbuffers(self->framebuffer, dirty_row_bitmask); } displayio_display_core_finish_refresh(&self->core); } diff --git a/shared-module/framebufferio/FramebufferDisplay.h b/shared-module/framebufferio/FramebufferDisplay.h index 93ad0118a..027086b5a 100644 --- a/shared-module/framebufferio/FramebufferDisplay.h +++ b/shared-module/framebufferio/FramebufferDisplay.h @@ -79,7 +79,7 @@ typedef int (*framebuffer_get_width_fun)(mp_obj_t); typedef mp_float_t (*framebuffer_get_brightness_fun)(mp_obj_t); typedef void (*framebuffer_deinit_fun)(mp_obj_t); typedef void (*framebuffer_get_bufinfo_fun)(mp_obj_t, mp_buffer_info_t *bufinfo); -typedef void (*framebuffer_swapbuffers_fun)(mp_obj_t); +typedef void (*framebuffer_swapbuffers_fun)(mp_obj_t, uint8_t *dirty_row_bitmask); typedef struct _framebuffer_p_t { MP_PROTOCOL_HEAD // MP_QSTR_protocol_framebuffer -- cgit v1.2.3 From c1400bae9bbdd55f650ddfe24edf6778f08c35b8 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 6 Aug 2020 16:03:31 -0500 Subject: sharpmemory: Implement support for Sharp Memory Displays in framebufferio --- py/circuitpy_defns.mk | 5 + py/circuitpy_mpconfig.h | 22 +- py/circuitpy_mpconfig.mk | 6 +- py/qstr.c | 1 + .../sharpdisplay/SharpMemoryFramebuffer.c | 92 +++++++ .../sharpdisplay/SharpMemoryFramebuffer.h | 34 +++ shared-bindings/sharpdisplay/__init__.c | 47 ++++ shared-bindings/sharpdisplay/__init__.h | 0 shared-module/displayio/__init__.c | 33 ++- shared-module/displayio/__init__.h | 10 + shared-module/framebufferio/FramebufferDisplay.c | 21 +- shared-module/framebufferio/FramebufferDisplay.h | 3 +- .../sharpdisplay/SharpMemoryFramebuffer.c | 282 +++++++++++++++++++++ .../sharpdisplay/SharpMemoryFramebuffer.h | 60 +++++ shared-module/sharpdisplay/__init__.c | 0 shared-module/sharpdisplay/__init__.h | 0 supervisor/shared/display.c | 21 +- 17 files changed, 608 insertions(+), 29 deletions(-) create mode 100644 shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c create mode 100644 shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h create mode 100644 shared-bindings/sharpdisplay/__init__.c create mode 100644 shared-bindings/sharpdisplay/__init__.h create mode 100644 shared-module/sharpdisplay/SharpMemoryFramebuffer.c create mode 100644 shared-module/sharpdisplay/SharpMemoryFramebuffer.h create mode 100644 shared-module/sharpdisplay/__init__.c create mode 100644 shared-module/sharpdisplay/__init__.h (limited to 'shared-module') diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index a39e0c9dd..515b386f9 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -222,6 +222,9 @@ endif ifeq ($(CIRCUITPY_SDIOIO),1) SRC_PATTERNS += sdioio/% endif +ifeq ($(CIRCUITPY_SHARPDISPLAY),1) +SRC_PATTERNS += sharpdisplay/% +endif ifeq ($(CIRCUITPY_STAGE),1) SRC_PATTERNS += _stage/% endif @@ -409,6 +412,8 @@ SRC_SHARED_MODULE_ALL = \ random/__init__.c \ rgbmatrix/RGBMatrix.c \ rgbmatrix/__init__.c \ + sharpdisplay/SharpMemoryFramebuffer.c \ + sharpdisplay/__init__.c \ socket/__init__.c \ storage/__init__.c \ struct/__init__.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 255ab99b9..f0e8adffa 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -499,13 +499,6 @@ extern const struct _mp_obj_module_t pixelbuf_module; #define PIXELBUF_MODULE #endif -#if CIRCUITPY_RGBMATRIX -extern const struct _mp_obj_module_t rgbmatrix_module; -#define RGBMATRIX_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_rgbmatrix),(mp_obj_t)&rgbmatrix_module }, -#else -#define RGBMATRIX_MODULE -#endif - #if CIRCUITPY_PULSEIO extern const struct _mp_obj_module_t pulseio_module; #define PULSEIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_pulseio), (mp_obj_t)&pulseio_module }, @@ -520,6 +513,13 @@ extern const struct _mp_obj_module_t ps2io_module; #define PS2IO_MODULE #endif +#if CIRCUITPY_RGBMATRIX +extern const struct _mp_obj_module_t rgbmatrix_module; +#define RGBMATRIX_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_rgbmatrix),(mp_obj_t)&rgbmatrix_module }, +#else +#define RGBMATRIX_MODULE +#endif + #if CIRCUITPY_RANDOM extern const struct _mp_obj_module_t random_module; #define RANDOM_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_random), (mp_obj_t)&random_module }, @@ -562,6 +562,13 @@ extern const struct _mp_obj_module_t sdioio_module; #define SDIOIO_MODULE #endif +#if CIRCUITPY_SHARPDISPLAY +extern const struct _mp_obj_module_t sharpdisplay_module; +#define SHARPDISPLAY_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_sharpdisplay),(mp_obj_t)&sharpdisplay_module }, +#else +#define SHARPDISPLAY_MODULE +#endif + #if CIRCUITPY_STAGE extern const struct _mp_obj_module_t stage_module; #define STAGE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__stage), (mp_obj_t)&stage_module }, @@ -737,6 +744,7 @@ extern const struct _mp_obj_module_t watchdog_module; SAMD_MODULE \ SDCARDIO_MODULE \ SDIOIO_MODULE \ + SHARPDISPLAY_MODULE \ STAGE_MODULE \ STORAGE_MODULE \ STRUCT_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 2cf8426e5..1ba71fa02 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -95,7 +95,7 @@ CFLAGS += -DCIRCUITPY_COUNTIO=$(CIRCUITPY_COUNTIO) CIRCUITPY_DISPLAYIO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_DISPLAYIO=$(CIRCUITPY_DISPLAYIO) -CIRCUITPY_FRAMEBUFFERIO ?= 0 +CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_FRAMEBUFFERIO=$(CIRCUITPY_FRAMEBUFFERIO) CIRCUITPY_VECTORIO ?= $(CIRCUITPY_DISPLAYIO) @@ -144,7 +144,6 @@ CFLAGS += -DCIRCUITPY_OS=$(CIRCUITPY_OS) CIRCUITPY_PIXELBUF ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_PIXELBUF=$(CIRCUITPY_PIXELBUF) -# Only for SAMD boards for the moment CIRCUITPY_RGBMATRIX ?= 0 CFLAGS += -DCIRCUITPY_RGBMATRIX=$(CIRCUITPY_RGBMATRIX) @@ -176,6 +175,9 @@ CFLAGS += -DCIRCUITPY_SDCARDIO=$(CIRCUITPY_SDCARDIO) CIRCUITPY_SDIOIO ?= 0 CFLAGS += -DCIRCUITPY_SDIOIO=$(CIRCUITPY_SDIOIO) +CIRCUITPY_SHARPDISPLAY ?= $(CIRCUITPY_FRAMEBUFFERIO) +CFLAGS += -DCIRCUITPY_SHARPDISPLAY=$(CIRCUITPY_SHARPDISPLAY) + # Currently always off. CIRCUITPY_STAGE ?= 0 CFLAGS += -DCIRCUITPY_STAGE=$(CIRCUITPY_STAGE) diff --git a/py/qstr.c b/py/qstr.c index 17d8517c9..c9ba298fb 100755 --- a/py/qstr.c +++ b/py/qstr.c @@ -137,6 +137,7 @@ STATIC const byte *find_qstr(qstr q) { while (q < pool->total_prev_len) { pool = pool->prev; } + assert(q - pool->total_prev_len < pool->len); return pool->qstrs[q - pool->total_prev_len]; } diff --git a/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c b/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c new file mode 100644 index 000000000..e8f4e970a --- /dev/null +++ b/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.c @@ -0,0 +1,92 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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/objarray.h" +#include "py/runtime.h" + +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" + +STATIC mp_obj_t sharpdisplay_framebuffer_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_spi_bus, ARG_chip_select, ARG_width, ARG_height, ARG_baudrate, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_spi_bus, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_chip_select, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} }, + { MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 2000000} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mcu_pin_obj_t *chip_select = validate_obj_is_free_pin(args[ARG_chip_select].u_obj); + busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi_bus].u_obj); + + sharpdisplay_framebuffer_obj_t* self = &allocate_display_bus_or_raise()->sharpdisplay; + self->base.type = &sharpdisplay_framebuffer_type; + + common_hal_sharpdisplay_framebuffer_construct(self, spi, chip_select, args[ARG_baudrate].u_int, args[ARG_width].u_int, args[ARG_height].u_int); + + return MP_OBJ_FROM_PTR(self); +} + + +STATIC mp_int_t sharpdisplay_framebuffer_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + sharpdisplay_framebuffer_obj_t *self = (sharpdisplay_framebuffer_obj_t*)self_in; + // a readonly framebuffer would be unusual but not impossible + if ((flags & MP_BUFFER_WRITE) && !(self->bufinfo.typecode & MP_OBJ_ARRAY_TYPECODE_FLAG_RW)) { + return 1; + } + *bufinfo = self->bufinfo; + return 0; +} + +STATIC mp_obj_t sharpdisplay_framebuffer_deinit(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = (sharpdisplay_framebuffer_obj_t*)self_in; + common_hal_sharpdisplay_framebuffer_deinit(self); + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(sharpdisplay_framebuffer_deinit_obj, sharpdisplay_framebuffer_deinit); + +STATIC const mp_rom_map_elem_t sharpdisplay_framebuffer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sharpdisplay_framebuffer_deinit_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(sharpdisplay_framebuffer_locals_dict, sharpdisplay_framebuffer_locals_dict_table); + +const mp_obj_type_t sharpdisplay_framebuffer_type = { + { &mp_type_type }, + .name = MP_QSTR_SharpMemoryFramebuffer, + .buffer_p = { .get_buffer = sharpdisplay_framebuffer_get_buffer, }, + .make_new = sharpdisplay_framebuffer_make_new, + .protocol = &sharpdisplay_framebuffer_proto, + .locals_dict = (mp_obj_dict_t*)&sharpdisplay_framebuffer_locals_dict, +}; diff --git a/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h b/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h new file mode 100644 index 000000000..30f1b867b --- /dev/null +++ b/shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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. + */ + +#pragma once + +// #include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" +// #include "shared-module/framebufferio/FramebufferDisplay.h" + +#include "py/objtype.h" + +extern const mp_obj_type_t sharpdisplay_framebuffer_type; diff --git a/shared-bindings/sharpdisplay/__init__.c b/shared-bindings/sharpdisplay/__init__.c new file mode 100644 index 000000000..d1f728c61 --- /dev/null +++ b/shared-bindings/sharpdisplay/__init__.c @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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 + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" + +//| """Support for Sharp Memory Display framebuffers""" +//| + +STATIC const mp_rom_map_elem_t sharpdisplay_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sharpdisplay) }, + { MP_ROM_QSTR(MP_QSTR_SharpMemoryFramebuffer), MP_ROM_PTR(&sharpdisplay_framebuffer_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(sharpdisplay_module_globals, sharpdisplay_module_globals_table); + +const mp_obj_module_t sharpdisplay_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&sharpdisplay_module_globals, +}; diff --git a/shared-bindings/sharpdisplay/__init__.h b/shared-bindings/sharpdisplay/__init__.h new file mode 100644 index 000000000..e69de29bb diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index efc28470f..e52ec5b9e 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -19,14 +19,19 @@ #include "supervisor/spi_flash_api.h" #include "py/mpconfig.h" +#if CIRCUITPY_SHARPDISPLAY +#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" +#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" +#endif + primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT]; -#if CIRCUITPY_RGBMATRIX -STATIC bool any_display_uses_this_rgbmatrix(rgbmatrix_rgbmatrix_obj_t* pm) { +#if CIRCUITPY_RGBMATRIX || CIRCUITPY_SHARPDISPLAY +STATIC bool any_display_uses_this_framebuffer(mp_obj_base_t *obj) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - if (displays[i].framebuffer_display.base.type == &framebufferio_framebufferdisplay_type) { + if (displays[i].display_base.type == &framebufferio_framebufferdisplay_type) { framebufferio_framebufferdisplay_obj_t* display = &displays[i].framebuffer_display; - if (display->framebuffer == pm) { + if (display->framebuffer == obj) { return true; } } @@ -105,6 +110,10 @@ void common_hal_displayio_release_displays(void) { #if CIRCUITPY_FRAMEBUFFERIO } else if (bus_type == &rgbmatrix_RGBMatrix_type) { common_hal_rgbmatrix_rgbmatrix_deinit(&displays[i].rgbmatrix); +#endif +#if CIRCUITPY_SHARPDISPLAY + } else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { + common_hal_sharpdisplay_framebuffer_deinit(&displays[i].sharpdisplay); #endif } displays[i].fourwire_bus.base.type = &mp_type_NoneType; @@ -170,9 +179,18 @@ void reset_displays(void) { #if CIRCUITPY_RGBMATRIX } else if (displays[i].rgbmatrix.base.type == &rgbmatrix_RGBMatrix_type) { rgbmatrix_rgbmatrix_obj_t * pm = &displays[i].rgbmatrix; - if(!any_display_uses_this_rgbmatrix(pm)) { + if(!any_display_uses_this_framebuffer(&pm->base)) { common_hal_rgbmatrix_rgbmatrix_deinit(pm); } +#endif +#if CIRCUITPY_SHARPDISPLAY + } else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { + sharpdisplay_framebuffer_obj_t * sharp = &displays[i].sharpdisplay; + if(any_display_uses_this_framebuffer(&sharp->base)) { + common_hal_sharpdisplay_framebuffer_reset(sharp); + } else { + common_hal_sharpdisplay_framebuffer_deinit(sharp); + } #endif } else { // Not an active display bus. @@ -203,6 +221,11 @@ void displayio_gc_collect(void) { rgbmatrix_rgbmatrix_collect_ptrs(&displays[i].rgbmatrix); } #endif +#if CIRCUITPY_SHARPDISPLAY + if (displays[i].rgbmatrix.base.type == &sharpdisplay_framebuffer_type) { + common_hal_sharpdisplay_framebuffer_collect_ptrs(&displays[i].sharpdisplay); + } +#endif if (displays[i].display.base.type == NULL) { continue; diff --git a/shared-module/displayio/__init__.h b/shared-module/displayio/__init__.h index 9eb10c28b..44ad5a9a9 100644 --- a/shared-module/displayio/__init__.h +++ b/shared-module/displayio/__init__.h @@ -36,18 +36,28 @@ #include "shared-bindings/displayio/Group.h" #include "shared-bindings/displayio/I2CDisplay.h" #include "shared-bindings/displayio/ParallelBus.h" +#if CIRCUITPY_RGBMATRIX #include "shared-bindings/rgbmatrix/RGBMatrix.h" +#endif +#if CIRCUITPY_SHARPDISPLAY +#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" +#endif typedef struct { union { + mp_obj_base_t bus_base; displayio_fourwire_obj_t fourwire_bus; displayio_i2cdisplay_obj_t i2cdisplay_bus; displayio_parallelbus_obj_t parallel_bus; #if CIRCUITPY_RGBMATRIX rgbmatrix_rgbmatrix_obj_t rgbmatrix; +#endif +#if CIRCUITPY_SHARPDISPLAY + sharpdisplay_framebuffer_obj_t sharpdisplay; #endif }; union { + mp_obj_base_t display_base; displayio_display_obj_t display; displayio_epaperdisplay_obj_t epaper_display; #if CIRCUITPY_FRAMEBUFFERIO diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 9a6797cd8..6b5346877 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -156,7 +156,7 @@ STATIC const displayio_area_t* _get_refresh_areas(framebufferio_framebufferdispl return NULL; } -#define MARK_ROW_DIRTY(r) (dirty_row_bitmask[r/8] = (1 << (r & 7))) +#define MARK_ROW_DIRTY(r) (dirty_row_bitmask[r/8] |= (1 << (r & 7))) STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const displayio_area_t* area, uint8_t *dirty_row_bitmask) { uint16_t buffer_size = 128; // In uint32_ts @@ -250,6 +250,10 @@ STATIC bool _refresh_area(framebufferio_framebufferdisplay_obj_t* self, const di } STATIC void _refresh_display(framebufferio_framebufferdisplay_obj_t* self) { + self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); + if(!self->bufinfo.buf) { + return; + } displayio_display_core_start_refresh(&self->core); const displayio_area_t* current_area = _get_refresh_areas(self); if (current_area) { @@ -348,17 +352,18 @@ void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) { self->base.type = &mp_type_NoneType; } -void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self) { - common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, true); - common_hal_framebufferio_framebufferdisplay_show(self, NULL); -} - void framebufferio_framebufferdisplay_collect_ptrs(framebufferio_framebufferdisplay_obj_t* self) { gc_collect_ptr(self->framebuffer); displayio_display_core_collect_ptrs(&self->core); } void framebufferio_framebufferdisplay_reset(framebufferio_framebufferdisplay_obj_t* self) { - common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, true); - common_hal_framebufferio_framebufferdisplay_show(self, NULL); + mp_obj_type_t *fb_type = mp_obj_get_type(self->framebuffer); + if(fb_type != NULL && fb_type != &mp_type_NoneType) { + common_hal_framebufferio_framebufferdisplay_set_auto_refresh(self, true); + common_hal_framebufferio_framebufferdisplay_show(self, NULL); + self->core.full_refresh = true; + } else { + release_framebufferdisplay(self); + } } diff --git a/shared-module/framebufferio/FramebufferDisplay.h b/shared-module/framebufferio/FramebufferDisplay.h index 027086b5a..111c9f670 100644 --- a/shared-module/framebufferio/FramebufferDisplay.h +++ b/shared-module/framebufferio/FramebufferDisplay.h @@ -55,7 +55,6 @@ typedef struct { void framebufferio_framebufferdisplay_background(framebufferio_framebufferdisplay_obj_t* self); void release_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self); -void reset_framebufferdisplay(framebufferio_framebufferdisplay_obj_t* self); void framebufferio_framebufferdisplay_reset(framebufferio_framebufferdisplay_obj_t* self); void framebufferio_framebufferdisplay_collect_ptrs(framebufferio_framebufferdisplay_obj_t* self); @@ -73,7 +72,7 @@ typedef int (*framebuffer_get_first_pixel_offset_fun)(mp_obj_t); typedef int (*framebuffer_get_grayscale_fun)(mp_obj_t); typedef int (*framebuffer_get_height_fun)(mp_obj_t); typedef int (*framebuffer_get_native_frames_per_second_fun)(mp_obj_t); -typedef int (*framebuffer_get_pixels_in_byte_share_row_fun)(mp_obj_t); +typedef bool (*framebuffer_get_pixels_in_byte_share_row_fun)(mp_obj_t); typedef int (*framebuffer_get_row_stride_fun)(mp_obj_t); typedef int (*framebuffer_get_width_fun)(mp_obj_t); typedef mp_float_t (*framebuffer_get_brightness_fun)(mp_obj_t); diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c new file mode 100644 index 000000000..ac9c22572 --- /dev/null +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c @@ -0,0 +1,282 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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 + +#include "py/gc.h" + +#include "shared-bindings/board/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" +#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" + +#include "supervisor/memory.h" + +#define SHARPMEM_BIT_WRITECMD_LSB (0x80) +#define SHARPMEM_BIT_VCOM_LSB (0x40) + +static inline void *hybrid_alloc(size_t sz) { + if (gc_alloc_possible()) { + return m_malloc(sz + sizeof(void*), true); + } else { + supervisor_allocation *allocation = allocate_memory(align32_size(sz), false); + if (!allocation) { + return NULL; + } + memset(allocation->ptr, 0, sz); + return allocation->ptr; + } +} + +static inline void hybrid_free(void *ptr_in) { + supervisor_allocation *allocation = allocation_from_ptr(ptr_in); + + if (allocation) { + free_memory(allocation); + } +} + +STATIC uint8_t bitrev(uint8_t n) { + uint8_t r = 0; + for(int i=0;i<8;i++) r |= ((n>>i) & 1)<<(7-i); + return r; +} + +int common_hal_sharpdisplay_framebuffer_get_width(sharpdisplay_framebuffer_obj_t *self) { + return self->width; +} + +int common_hal_sharpdisplay_framebuffer_get_height(sharpdisplay_framebuffer_obj_t *self) { + return self->height; +} + +int common_hal_sharpdisplay_framebuffer_get_row_stride(sharpdisplay_framebuffer_obj_t *self) { + return (self->width + 7) / 8 + 2; +} + +int common_hal_sharpdisplay_framebuffer_get_first_pixel_offset(sharpdisplay_framebuffer_obj_t *self) { + return 2; +} + +bool common_hal_sharpdisplay_framebuffer_get_reverse_pixels_in_byte(sharpdisplay_framebuffer_obj_t *self) { + return true; +} + +bool common_hal_sharpdisplay_framebuffer_get_pixels_in_byte_share_row(sharpdisplay_framebuffer_obj_t *self) { + return true; +} + +void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *self) { + if (!allocation_from_ptr(self->bufinfo.buf)) { + self->bufinfo.buf = NULL; + } + + if (self->bus != &self->inline_bus +#if BOARD_SPI + && self->bus != common_hal_board_get_spi() +#endif + ) { + memcpy(&self->inline_bus, self->bus, sizeof(busio_spi_obj_t)); + self->bus = &self->inline_bus; + } +} + +void common_hal_sharpdisplay_framebuffer_reconstruct(sharpdisplay_framebuffer_obj_t *self) { + +} + +void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo) { + if (!self->bufinfo.buf) { + int row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self); + int height = common_hal_sharpdisplay_framebuffer_get_height(self); + self->bufinfo.len = row_stride * height + 2; + self->bufinfo.buf = hybrid_alloc(self->bufinfo.len); + + uint8_t *data = self->bufinfo.buf; + *data++ = SHARPMEM_BIT_WRITECMD_LSB; + + for(int y=0; yfull_refresh = true; + } + *bufinfo = self->bufinfo; +} + +void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t *self) { + if (self->base.type != &sharpdisplay_framebuffer_type) { + return; + } + + if (self->bus == &self->inline_bus) { + common_hal_busio_spi_deinit(self->bus); + } + + common_hal_reset_pin(self->chip_select.pin); + + hybrid_free(self->bufinfo.buf); + + memset(self, 0, sizeof(*self)); +} + +void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_t *self, busio_spi_obj_t *spi, mcu_pin_obj_t *chip_select, int baudrate, int width, int height) { + common_hal_digitalio_digitalinout_construct(&self->chip_select, chip_select); + common_hal_digitalio_digitalinout_switch_to_output(&self->chip_select, true, DRIVE_MODE_PUSH_PULL); + common_hal_never_reset_pin(chip_select); + + self->bus = spi; + common_hal_busio_spi_never_reset(self->bus); + + self->width = width; + self->height = height; + self->baudrate = baudrate; + + int row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self); + self->bufinfo.len = row_stride * height + 2; + self->bufinfo.buf = gc_alloc(self->bufinfo.len, false, true); + + uint8_t *data = self->bufinfo.buf; + *data++ = SHARPMEM_BIT_WRITECMD_LSB; + + for(int y=0; yheight; y++) { + *data = bitrev(y+1); + data += row_stride; + } + self->full_refresh = true; +} + +void common_hal_sharpdisplay_framebuffer_swapbuffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask) { + // claim SPI bus + if (!common_hal_busio_spi_try_lock(self->bus)) { + return; + } + common_hal_busio_spi_configure(self->bus, self->baudrate, 0, 0, 8); + + // set chip select high + common_hal_digitalio_digitalinout_set_value(&self->chip_select, true); + + // output the toggling signal + uint8_t *data = self->bufinfo.buf; + data[0] ^= SHARPMEM_BIT_VCOM_LSB; + +#define PARTIAL_UPDATES (1) +#if PARTIAL_UPDATES + common_hal_busio_spi_write(self->bus, data++, 1); + + // output each changed row + size_t row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self); + for(int y=0; yheight; y++) { + if(self->full_refresh || (dirty_row_bitmask[y/8] & (1 << (y & 7)))) { + common_hal_busio_spi_write(self->bus, data, row_stride); + } + data += row_stride; + } + + // output a trailing zero + common_hal_busio_spi_write(self->bus, data, 1); +#else + common_hal_busio_spi_write(self->bus, data, self->bufinfo.len); +#endif + + // set chip select low + common_hal_digitalio_digitalinout_set_value(&self->chip_select, false); + + // release SPI bus + common_hal_busio_spi_unlock(self->bus); + + self->full_refresh = false; +} + +STATIC void sharpdisplay_framebuffer_deinit(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = self_in; + common_hal_sharpdisplay_framebuffer_deinit(self); +} + +STATIC void sharpdisplay_framebuffer_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) { + sharpdisplay_framebuffer_obj_t *self = self_in; + common_hal_sharpdisplay_framebuffer_get_bufinfo(self, bufinfo); +} + +STATIC int sharpdisplay_framebuffer_get_color_depth(mp_obj_t self_in) { + return 1; +} + +STATIC int sharpdisplay_framebuffer_get_height(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = self_in; + return common_hal_sharpdisplay_framebuffer_get_height(self); +} + +STATIC int sharpdisplay_framebuffer_get_width(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = self_in; + return common_hal_sharpdisplay_framebuffer_get_width(self); +} + +STATIC int sharpdisplay_framebuffer_get_first_pixel_offset(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = self_in; + return common_hal_sharpdisplay_framebuffer_get_first_pixel_offset(self); +} + +STATIC bool sharpdisplay_framebuffer_get_pixels_in_byte_share_row(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = self_in; + return common_hal_sharpdisplay_framebuffer_get_pixels_in_byte_share_row(self); +} + +STATIC bool sharpdisplay_framebuffer_get_reverse_pixels_in_byte(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = self_in; + return common_hal_sharpdisplay_framebuffer_get_reverse_pixels_in_byte(self); +} + +STATIC int sharpdisplay_framebuffer_get_row_stride(mp_obj_t self_in) { + sharpdisplay_framebuffer_obj_t *self = self_in; + return common_hal_sharpdisplay_framebuffer_get_row_stride(self); +} + +STATIC void sharpdisplay_framebuffer_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmask) { + sharpdisplay_framebuffer_obj_t *self = self_in; + common_hal_sharpdisplay_framebuffer_swapbuffers(self, dirty_row_bitmask); +} + +const framebuffer_p_t sharpdisplay_framebuffer_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer) + .deinit = sharpdisplay_framebuffer_deinit, + .get_bufinfo = sharpdisplay_framebuffer_get_bufinfo, + .get_color_depth = sharpdisplay_framebuffer_get_color_depth, + .get_height = sharpdisplay_framebuffer_get_height, + .get_width = sharpdisplay_framebuffer_get_width, + .swapbuffers = sharpdisplay_framebuffer_swapbuffers, + + .get_first_pixel_offset = sharpdisplay_framebuffer_get_first_pixel_offset, + .get_pixels_in_byte_share_row = sharpdisplay_framebuffer_get_pixels_in_byte_share_row, + .get_reverse_pixels_in_byte = sharpdisplay_framebuffer_get_reverse_pixels_in_byte, + .get_row_stride = sharpdisplay_framebuffer_get_row_stride, +}; + +void common_hal_sharpdisplay_framebuffer_collect_ptrs(sharpdisplay_framebuffer_obj_t *self) { + gc_collect_ptr(self->framebuffer); + gc_collect_ptr(self->bus); + gc_collect_ptr(self->bufinfo.buf); +} diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.h b/shared-module/sharpdisplay/SharpMemoryFramebuffer.h new file mode 100644 index 000000000..8acacc94e --- /dev/null +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.h @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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. + */ + +#pragma once + +#include "py/obj.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-module/framebufferio/FramebufferDisplay.h" + +typedef struct { + mp_obj_base_t base; + mp_obj_t framebuffer; + busio_spi_obj_t* bus; + busio_spi_obj_t inline_bus; + digitalio_digitalinout_obj_t chip_select; + mp_buffer_info_t bufinfo; + + uint16_t width, height; + uint32_t baudrate; + + bool full_refresh:1; +} sharpdisplay_framebuffer_obj_t; + +void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_t *self, busio_spi_obj_t *spi, mcu_pin_obj_t *chip_select, int baudrate, int width, int height); +void common_hal_sharpdisplay_framebuffer_swap_buffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask); +void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t *self); +void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo); +int common_hal_sharpdisplay_framebuffer_get_height(sharpdisplay_framebuffer_obj_t *self); +int common_hal_sharpdisplay_framebuffer_get_width(sharpdisplay_framebuffer_obj_t *self); +void common_hal_sharpdisplay_framebuffer_swap_buffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask); +void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *self); +void common_hal_sharpdisplay_framebuffer_reconstruct(sharpdisplay_framebuffer_obj_t *self); + +extern const framebuffer_p_t sharpdisplay_framebuffer_proto; + +void common_hal_sharpdisplay_framebuffer_collect_ptrs(sharpdisplay_framebuffer_obj_t*); diff --git a/shared-module/sharpdisplay/__init__.c b/shared-module/sharpdisplay/__init__.c new file mode 100644 index 000000000..e69de29bb diff --git a/shared-module/sharpdisplay/__init__.h b/shared-module/sharpdisplay/__init__.h new file mode 100644 index 000000000..e69de29bb diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index 9c074209b..a86ef6396 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -38,6 +38,11 @@ #include "shared-module/displayio/__init__.h" #endif +#if CIRCUITPY_SHARPDISPLAY +#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" +#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" +#endif + extern size_t blinka_bitmap_data[]; extern displayio_bitmap_t blinka_bitmap; extern displayio_group_t circuitpython_splash; @@ -116,15 +121,21 @@ void supervisor_display_move_memory(void) { grid->inline_tiles = false; } MP_STATE_VM(terminal_tilegrid_tiles) = NULL; - #if CIRCUITPY_RGBMATRIX for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - if (displays[i].rgbmatrix.base.type == &rgbmatrix_RGBMatrix_type) { - rgbmatrix_rgbmatrix_obj_t * pm = &displays[i].rgbmatrix; + #if CIRCUITPY_RGBMATRIX + if (displays[i].rgbmatrix.base.type == &rgbmatrix_RGBMatrix_type) { + rgbmatrix_rgbmatrix_obj_t * pm = &displays[i].rgbmatrix; common_hal_rgbmatrix_rgbmatrix_reconstruct(pm, NULL); - } + } + #endif + #if CIRCUITPY_SHARPDISPLAY + if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { + sharpdisplay_framebuffer_obj_t * sharp = &displays[i].sharpdisplay; + common_hal_sharpdisplay_framebuffer_reconstruct(sharp); + } + #endif } #endif - #endif } size_t blinka_bitmap_data[32] = { -- cgit v1.2.3 From 759ded9c38390c6d4328bd34aa211499b7e9f4f6 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 12 Aug 2020 07:39:12 -0500 Subject: Fix build errors when SHARPDISPLAY && !RGBMATRIX --- shared-module/displayio/__init__.c | 4 ++-- supervisor/shared/display.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index e52ec5b9e..5afcba35e 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -107,7 +107,7 @@ void common_hal_displayio_release_displays(void) { common_hal_displayio_i2cdisplay_deinit(&displays[i].i2cdisplay_bus); } else if (bus_type == &displayio_parallelbus_type) { common_hal_displayio_parallelbus_deinit(&displays[i].parallel_bus); -#if CIRCUITPY_FRAMEBUFFERIO +#if CIRCUITPY_RGBMATRIX } else if (bus_type == &rgbmatrix_RGBMatrix_type) { common_hal_rgbmatrix_rgbmatrix_deinit(&displays[i].rgbmatrix); #endif @@ -222,7 +222,7 @@ void displayio_gc_collect(void) { } #endif #if CIRCUITPY_SHARPDISPLAY - if (displays[i].rgbmatrix.base.type == &sharpdisplay_framebuffer_type) { + if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { common_hal_sharpdisplay_framebuffer_collect_ptrs(&displays[i].sharpdisplay); } #endif diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index a86ef6396..08dd71404 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -39,6 +39,7 @@ #endif #if CIRCUITPY_SHARPDISPLAY +#include "shared-module/displayio/__init__.h" #include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" #include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" #endif -- cgit v1.2.3 From d61f66d173c956b10679e83b93d7f84fbc6f0bb4 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 12 Aug 2020 12:50:08 -0500 Subject: Update shared-module/framebufferio/FramebufferDisplay.h Co-authored-by: Scott Shawcroft --- shared-module/framebufferio/FramebufferDisplay.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/framebufferio/FramebufferDisplay.h b/shared-module/framebufferio/FramebufferDisplay.h index 111c9f670..89df0d27c 100644 --- a/shared-module/framebufferio/FramebufferDisplay.h +++ b/shared-module/framebufferio/FramebufferDisplay.h @@ -48,7 +48,8 @@ typedef struct { uint64_t last_refresh_call; uint16_t native_frames_per_second; uint16_t native_ms_per_frame; - uint16_t first_pixel_offset, row_stride; + uint16_t first_pixel_offset; + uint16_t row_stride; bool auto_refresh; bool first_manual_refresh; } framebufferio_framebufferdisplay_obj_t; -- cgit v1.2.3 From 195c0ea986fd44f3b56cc57f23e8259df1e18202 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 12 Aug 2020 13:01:43 -0500 Subject: sharpdisplay: Make PARTIAL_UPDATES unconditional --- shared-module/sharpdisplay/SharpMemoryFramebuffer.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'shared-module') diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c index ac9c22572..71e00d7f0 100644 --- a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c @@ -183,8 +183,6 @@ void common_hal_sharpdisplay_framebuffer_swapbuffers(sharpdisplay_framebuffer_ob uint8_t *data = self->bufinfo.buf; data[0] ^= SHARPMEM_BIT_VCOM_LSB; -#define PARTIAL_UPDATES (1) -#if PARTIAL_UPDATES common_hal_busio_spi_write(self->bus, data++, 1); // output each changed row @@ -198,9 +196,6 @@ void common_hal_sharpdisplay_framebuffer_swapbuffers(sharpdisplay_framebuffer_ob // output a trailing zero common_hal_busio_spi_write(self->bus, data, 1); -#else - common_hal_busio_spi_write(self->bus, data, self->bufinfo.len); -#endif // set chip select low common_hal_digitalio_digitalinout_set_value(&self->chip_select, false); -- cgit v1.2.3 From 14f5d03b6dd947bd82d2daf88ca398d7d3b44930 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Thu, 13 Aug 2020 18:59:00 -0500 Subject: bringing up to date --- extmod/ulab | 2 +- frozen/Adafruit_CircuitPython_BLE | 2 +- ...uit_CircuitPython_BLE_Apple_Notification_Center | 2 +- frozen/Adafruit_CircuitPython_BusDevice | 2 +- frozen/Adafruit_CircuitPython_CircuitPlayground | 2 +- frozen/Adafruit_CircuitPython_Crickit | 2 +- frozen/Adafruit_CircuitPython_DRV2605 | 2 +- frozen/Adafruit_CircuitPython_DS3231 | 2 +- frozen/Adafruit_CircuitPython_ESP32SPI | 2 +- frozen/Adafruit_CircuitPython_FocalTouch | 2 +- frozen/Adafruit_CircuitPython_HID | 2 +- frozen/Adafruit_CircuitPython_IRRemote | 2 +- frozen/Adafruit_CircuitPython_LIS3DH | 2 +- frozen/Adafruit_CircuitPython_LSM6DS | 2 +- frozen/Adafruit_CircuitPython_Motor | 2 +- frozen/Adafruit_CircuitPython_Register | 2 +- frozen/Adafruit_CircuitPython_Requests | 2 +- frozen/Adafruit_CircuitPython_Thermistor | 2 +- frozen/Adafruit_CircuitPython_seesaw | 2 +- frozen/circuitpython-stage | 2 +- lib/mp3 | 2 +- lib/protomatter | 2 +- lib/tinyusb | 2 +- ports/atmel-samd/asf4 | 2 +- ports/atmel-samd/peripherals | 2 +- ports/cxd56/spresense-exported-sdk | 2 +- ports/esp32s2/esp-idf | 2 +- ports/stm/st_driver | 2 +- shared-bindings/_typing/__init__ 2.pyi | 54 +++ shared-bindings/gnss/GNSS 2.c | 205 +++++++++ shared-bindings/gnss/GNSS 2.h | 27 ++ shared-bindings/gnss/PositionFix 2.c | 80 ++++ shared-bindings/gnss/PositionFix 2.h | 28 ++ shared-bindings/gnss/SatelliteSystem 2.c | 113 +++++ shared-bindings/gnss/SatelliteSystem 2.h | 33 ++ shared-bindings/gnss/__init__ 2.c | 31 ++ shared-bindings/i2cperipheral/I2CPeripheral 2.c | 436 +++++++++++++++++++ shared-bindings/i2cperipheral/I2CPeripheral 2.h | 60 +++ shared-bindings/i2cperipheral/__init__ 2.c | 106 +++++ shared-bindings/memorymonitor/AllocationAlarm 2.c | 137 ++++++ shared-bindings/memorymonitor/AllocationAlarm 2.h | 39 ++ shared-bindings/memorymonitor/AllocationSize 2.c | 183 ++++++++ shared-bindings/memorymonitor/AllocationSize 2.h | 42 ++ shared-bindings/memorymonitor/__init__ 2.c | 76 ++++ shared-bindings/memorymonitor/__init__ 2.h | 49 +++ shared-bindings/sdcardio/SDCard 2.c | 183 ++++++++ shared-bindings/sdcardio/SDCard 2.h | 30 ++ shared-bindings/sdcardio/__init__ 2.c | 47 +++ shared-bindings/sdcardio/__init__ 2.h | 0 shared-bindings/sdioio/SDCard 2.c | 296 +++++++++++++ shared-bindings/sdioio/SDCard 2.h | 66 +++ shared-bindings/sdioio/__init__ 2.c | 47 +++ shared-bindings/sdioio/__init__ 2.h | 0 shared-module/memorymonitor/AllocationAlarm 2.c | 94 +++++ shared-module/memorymonitor/AllocationAlarm 2.h | 51 +++ shared-module/memorymonitor/AllocationSize 2.c | 91 ++++ shared-module/memorymonitor/AllocationSize 2.h | 51 +++ shared-module/memorymonitor/__init__ 2.c | 39 ++ shared-module/memorymonitor/__init__ 2.h | 35 ++ shared-module/sdcardio/SDCard 2.c | 466 +++++++++++++++++++++ shared-module/sdcardio/SDCard 2.h | 51 +++ shared-module/sdcardio/__init__ 2.c | 0 shared-module/sdcardio/__init__ 2.h | 0 supervisor/background_callback 2.h | 87 ++++ supervisor/shared/background_callback 2.c | 138 ++++++ 65 files changed, 3499 insertions(+), 28 deletions(-) create mode 100644 shared-bindings/_typing/__init__ 2.pyi create mode 100644 shared-bindings/gnss/GNSS 2.c create mode 100644 shared-bindings/gnss/GNSS 2.h create mode 100644 shared-bindings/gnss/PositionFix 2.c create mode 100644 shared-bindings/gnss/PositionFix 2.h create mode 100644 shared-bindings/gnss/SatelliteSystem 2.c create mode 100644 shared-bindings/gnss/SatelliteSystem 2.h create mode 100644 shared-bindings/gnss/__init__ 2.c create mode 100644 shared-bindings/i2cperipheral/I2CPeripheral 2.c create mode 100644 shared-bindings/i2cperipheral/I2CPeripheral 2.h create mode 100644 shared-bindings/i2cperipheral/__init__ 2.c create mode 100644 shared-bindings/memorymonitor/AllocationAlarm 2.c create mode 100644 shared-bindings/memorymonitor/AllocationAlarm 2.h create mode 100644 shared-bindings/memorymonitor/AllocationSize 2.c create mode 100644 shared-bindings/memorymonitor/AllocationSize 2.h create mode 100644 shared-bindings/memorymonitor/__init__ 2.c create mode 100644 shared-bindings/memorymonitor/__init__ 2.h create mode 100644 shared-bindings/sdcardio/SDCard 2.c create mode 100644 shared-bindings/sdcardio/SDCard 2.h create mode 100644 shared-bindings/sdcardio/__init__ 2.c create mode 100644 shared-bindings/sdcardio/__init__ 2.h create mode 100644 shared-bindings/sdioio/SDCard 2.c create mode 100644 shared-bindings/sdioio/SDCard 2.h create mode 100644 shared-bindings/sdioio/__init__ 2.c create mode 100644 shared-bindings/sdioio/__init__ 2.h create mode 100644 shared-module/memorymonitor/AllocationAlarm 2.c create mode 100644 shared-module/memorymonitor/AllocationAlarm 2.h create mode 100644 shared-module/memorymonitor/AllocationSize 2.c create mode 100644 shared-module/memorymonitor/AllocationSize 2.h create mode 100644 shared-module/memorymonitor/__init__ 2.c create mode 100644 shared-module/memorymonitor/__init__ 2.h create mode 100644 shared-module/sdcardio/SDCard 2.c create mode 100644 shared-module/sdcardio/SDCard 2.h create mode 100644 shared-module/sdcardio/__init__ 2.c create mode 100644 shared-module/sdcardio/__init__ 2.h create mode 100644 supervisor/background_callback 2.h create mode 100644 supervisor/shared/background_callback 2.c (limited to 'shared-module') diff --git a/extmod/ulab b/extmod/ulab index 11a7ecff6..cf61d728e 160000 --- a/extmod/ulab +++ b/extmod/ulab @@ -1 +1 @@ -Subproject commit 11a7ecff6d76a02644ff23a734b792afaa615e44 +Subproject commit cf61d728e70b9ec57e5711b40540793a89296f5d diff --git a/frozen/Adafruit_CircuitPython_BLE b/frozen/Adafruit_CircuitPython_BLE index 41f7a3530..5d584576e 160000 --- a/frozen/Adafruit_CircuitPython_BLE +++ b/frozen/Adafruit_CircuitPython_BLE @@ -1 +1 @@ -Subproject commit 41f7a3530d4cacdbf668399d3a015ea29c7e169b +Subproject commit 5d584576ef79ca36506e6c7470e7ac5204cf0a8d diff --git a/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center b/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center index 6a034887e..3ffb3f02d 160000 --- a/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center +++ b/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center @@ -1 +1 @@ -Subproject commit 6a034887e370caa61fee5f51db8dd393d3e72542 +Subproject commit 3ffb3f02d2046910e09d1f5a74721bd1a4cdf8cf diff --git a/frozen/Adafruit_CircuitPython_BusDevice b/frozen/Adafruit_CircuitPython_BusDevice index eb4b21e21..e9411c424 160000 --- a/frozen/Adafruit_CircuitPython_BusDevice +++ b/frozen/Adafruit_CircuitPython_BusDevice @@ -1 +1 @@ -Subproject commit eb4b21e216efd8ec0c4862a938e81b56be961724 +Subproject commit e9411c4244984b69ec6928370ede40cec014c10b diff --git a/frozen/Adafruit_CircuitPython_CircuitPlayground b/frozen/Adafruit_CircuitPython_CircuitPlayground index 3c540329b..e9f15d615 160000 --- a/frozen/Adafruit_CircuitPython_CircuitPlayground +++ b/frozen/Adafruit_CircuitPython_CircuitPlayground @@ -1 +1 @@ -Subproject commit 3c540329b63163e45f108df4bfebc387d5352c4f +Subproject commit e9f15d61502f34173912ba271aaaf9446dae8da1 diff --git a/frozen/Adafruit_CircuitPython_Crickit b/frozen/Adafruit_CircuitPython_Crickit index 809646ba1..0e1230676 160000 --- a/frozen/Adafruit_CircuitPython_Crickit +++ b/frozen/Adafruit_CircuitPython_Crickit @@ -1 +1 @@ -Subproject commit 809646ba11366b5aedbc8a90be1da1829304bf62 +Subproject commit 0e1230676a54da17a309d1dfffdd7fa90240191c diff --git a/frozen/Adafruit_CircuitPython_DRV2605 b/frozen/Adafruit_CircuitPython_DRV2605 index 209edd164..7914a6390 160000 --- a/frozen/Adafruit_CircuitPython_DRV2605 +++ b/frozen/Adafruit_CircuitPython_DRV2605 @@ -1 +1 @@ -Subproject commit 209edd164eb640a8ced561a54505792fc99a67b9 +Subproject commit 7914a6390318687bb8e2e9c4119aa932fea01531 diff --git a/frozen/Adafruit_CircuitPython_DS3231 b/frozen/Adafruit_CircuitPython_DS3231 index 5d81a9ea8..0d49a1fcd 160000 --- a/frozen/Adafruit_CircuitPython_DS3231 +++ b/frozen/Adafruit_CircuitPython_DS3231 @@ -1 +1 @@ -Subproject commit 5d81a9ea822a85e46be4a512ac44abf21e77d816 +Subproject commit 0d49a1fcd96c13a94e8bdf26f92abe79b8517906 diff --git a/frozen/Adafruit_CircuitPython_ESP32SPI b/frozen/Adafruit_CircuitPython_ESP32SPI index 01f3f6674..94b03517c 160000 --- a/frozen/Adafruit_CircuitPython_ESP32SPI +++ b/frozen/Adafruit_CircuitPython_ESP32SPI @@ -1 +1 @@ -Subproject commit 01f3f6674b4493ba29b857e0f43deb69975736ec +Subproject commit 94b03517c1f4ff68cc2bb09b0963f7e7e3ce3d04 diff --git a/frozen/Adafruit_CircuitPython_FocalTouch b/frozen/Adafruit_CircuitPython_FocalTouch index 1e3312ab1..72968d354 160000 --- a/frozen/Adafruit_CircuitPython_FocalTouch +++ b/frozen/Adafruit_CircuitPython_FocalTouch @@ -1 +1 @@ -Subproject commit 1e3312ab1cba0b1d3bb1f559c52acfdc1a6d57b8 +Subproject commit 72968d3546f9d6c5af138d4c179343007cb9662c diff --git a/frozen/Adafruit_CircuitPython_HID b/frozen/Adafruit_CircuitPython_HID index 829ba0f0a..65fb213b8 160000 --- a/frozen/Adafruit_CircuitPython_HID +++ b/frozen/Adafruit_CircuitPython_HID @@ -1 +1 @@ -Subproject commit 829ba0f0a2d8a63f7d0215c6c9fc821e14e52a93 +Subproject commit 65fb213b8c554181d54b77f75335e16e2f4c0987 diff --git a/frozen/Adafruit_CircuitPython_IRRemote b/frozen/Adafruit_CircuitPython_IRRemote index fc3a7b479..d435fc9a9 160000 --- a/frozen/Adafruit_CircuitPython_IRRemote +++ b/frozen/Adafruit_CircuitPython_IRRemote @@ -1 +1 @@ -Subproject commit fc3a7b479874a1ea315ddb3bf6c5e281e16ef097 +Subproject commit d435fc9a9d90cb063608ae037bf5284b33bc5e84 diff --git a/frozen/Adafruit_CircuitPython_LIS3DH b/frozen/Adafruit_CircuitPython_LIS3DH index 9fe8f314c..457aba6dd 160000 --- a/frozen/Adafruit_CircuitPython_LIS3DH +++ b/frozen/Adafruit_CircuitPython_LIS3DH @@ -1 +1 @@ -Subproject commit 9fe8f314c032cee89b9ad7697d61e9cba76431ff +Subproject commit 457aba6dd59ad00502b80c9031655d3d26ecc82b diff --git a/frozen/Adafruit_CircuitPython_LSM6DS b/frozen/Adafruit_CircuitPython_LSM6DS index f1cc47f02..ee8f2187d 160000 --- a/frozen/Adafruit_CircuitPython_LSM6DS +++ b/frozen/Adafruit_CircuitPython_LSM6DS @@ -1 +1 @@ -Subproject commit f1cc47f024b27e670b9bf2a51c89e32f93c1b957 +Subproject commit ee8f2187d4795b08ae4aa60558f564d26c997be9 diff --git a/frozen/Adafruit_CircuitPython_Motor b/frozen/Adafruit_CircuitPython_Motor index 434e5b534..5fd72fb96 160000 --- a/frozen/Adafruit_CircuitPython_Motor +++ b/frozen/Adafruit_CircuitPython_Motor @@ -1 +1 @@ -Subproject commit 434e5b5346cb0a1a9eb15989b00278be87cb2ff1 +Subproject commit 5fd72fb963c4a0318d29282ca2cc988f19787fda diff --git a/frozen/Adafruit_CircuitPython_Register b/frozen/Adafruit_CircuitPython_Register index 6143ec2a9..56358b449 160000 --- a/frozen/Adafruit_CircuitPython_Register +++ b/frozen/Adafruit_CircuitPython_Register @@ -1 +1 @@ -Subproject commit 6143ec2a96a6d218041e9cab5968de26702d7bbf +Subproject commit 56358b4494da825cd99a56a854119f926abca670 diff --git a/frozen/Adafruit_CircuitPython_Requests b/frozen/Adafruit_CircuitPython_Requests index 43017e30a..41de8b3c0 160000 --- a/frozen/Adafruit_CircuitPython_Requests +++ b/frozen/Adafruit_CircuitPython_Requests @@ -1 +1 @@ -Subproject commit 43017e30a1e772b67ac68293a944e863c031e389 +Subproject commit 41de8b3c05dd78d7be8893a0f6cb47a7e9b421a2 diff --git a/frozen/Adafruit_CircuitPython_Thermistor b/frozen/Adafruit_CircuitPython_Thermistor index fb773e0ed..b5bbdbd56 160000 --- a/frozen/Adafruit_CircuitPython_Thermistor +++ b/frozen/Adafruit_CircuitPython_Thermistor @@ -1 +1 @@ -Subproject commit fb773e0ed1891cda2ace6271fafc5312e167d275 +Subproject commit b5bbdbd56ca205c581ba2c84d927ef99befce88e diff --git a/frozen/Adafruit_CircuitPython_seesaw b/frozen/Adafruit_CircuitPython_seesaw index 88738da27..76c0dd132 160000 --- a/frozen/Adafruit_CircuitPython_seesaw +++ b/frozen/Adafruit_CircuitPython_seesaw @@ -1 +1 @@ -Subproject commit 88738da275a83acabb14b7140d1c79b33cdc7b02 +Subproject commit 76c0dd13294ce8ae0518cb9882dcad5d3668977e diff --git a/frozen/circuitpython-stage b/frozen/circuitpython-stage index 9596a5904..0d2c083a2 160000 --- a/frozen/circuitpython-stage +++ b/frozen/circuitpython-stage @@ -1 +1 @@ -Subproject commit 9596a5904ed757e6fbffcf03e7aa77ae9ecf5223 +Subproject commit 0d2c083a2fb57a1562d4806775f45273abbfbfae diff --git a/lib/mp3 b/lib/mp3 index bc58a6549..c3c664bf4 160000 --- a/lib/mp3 +++ b/lib/mp3 @@ -1 +1 @@ -Subproject commit bc58a654964c799e972719a63ff12694998f3549 +Subproject commit c3c664bf4db6a36d11808dfcbb5dbf7cff1715b8 diff --git a/lib/protomatter b/lib/protomatter index 761d6437e..9f71088d2 160000 --- a/lib/protomatter +++ b/lib/protomatter @@ -1 +1 @@ -Subproject commit 761d6437e8cd6a131d51de96974337121a9c7164 +Subproject commit 9f71088d2c32206c6f0495704ae0c040426d5764 diff --git a/lib/tinyusb b/lib/tinyusb index 22100b252..dc5445e2f 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit 22100b252fc2eb8f51ed407949645653c4880fd9 +Subproject commit dc5445e2f45cb348a44fe24fc1be4bc8b5ba5bab diff --git a/ports/atmel-samd/asf4 b/ports/atmel-samd/asf4 index 35a152579..039b5f3bb 160000 --- a/ports/atmel-samd/asf4 +++ b/ports/atmel-samd/asf4 @@ -1 +1 @@ -Subproject commit 35a1525796c7ef8a3893d90befdad2f267fca20e +Subproject commit 039b5f3bbc3f4ba4421e581db290560d59fef625 diff --git a/ports/atmel-samd/peripherals b/ports/atmel-samd/peripherals index 0f5f1522d..6b531fc92 160000 --- a/ports/atmel-samd/peripherals +++ b/ports/atmel-samd/peripherals @@ -1 +1 @@ -Subproject commit 0f5f1522d09c8fa7d858edec484a994c21c59668 +Subproject commit 6b531fc923d9f02b14bd731a5f584ddf716e8773 diff --git a/ports/cxd56/spresense-exported-sdk b/ports/cxd56/spresense-exported-sdk index c991d439f..7f6568c7f 160000 --- a/ports/cxd56/spresense-exported-sdk +++ b/ports/cxd56/spresense-exported-sdk @@ -1 +1 @@ -Subproject commit c991d439fac9c23cfcac0da16fe8055f818d40a4 +Subproject commit 7f6568c7f4898cdb24a2f06040784a836050686e diff --git a/ports/esp32s2/esp-idf b/ports/esp32s2/esp-idf index 160ba4924..0daf6e0e4 160000 --- a/ports/esp32s2/esp-idf +++ b/ports/esp32s2/esp-idf @@ -1 +1 @@ -Subproject commit 160ba4924d8b588e718f76e3a0d0e92c11052fa3 +Subproject commit 0daf6e0e41f95d22d193d08941a00df9525bc405 diff --git a/ports/stm/st_driver b/ports/stm/st_driver index 190083475..3fc2e0f3d 160000 --- a/ports/stm/st_driver +++ b/ports/stm/st_driver @@ -1 +1 @@ -Subproject commit 1900834751fd6754457874b8c971690bab33e0a7 +Subproject commit 3fc2e0f3db155b33177bb0705e0dd65cadb58412 diff --git a/shared-bindings/_typing/__init__ 2.pyi b/shared-bindings/_typing/__init__ 2.pyi new file mode 100644 index 000000000..48e68a8d5 --- /dev/null +++ b/shared-bindings/_typing/__init__ 2.pyi @@ -0,0 +1,54 @@ +"""Types for the C-level protocols""" + +from typing import Union + +import array +import audiocore +import audiomixer +import audiomp3 +import rgbmatrix +import ulab + +ReadableBuffer = Union[ + bytes, bytearray, memoryview, array.array, ulab.array, rgbmatrix.RGBMatrix +] +"""Classes that implement the readable buffer protocol + + - `bytes` + - `bytearray` + - `memoryview` + - `array.array` + - `ulab.array` + - `rgbmatrix.RGBMatrix` +""" + +WriteableBuffer = Union[ + bytearray, memoryview, array.array, ulab.array, rgbmatrix.RGBMatrix +] +"""Classes that implement the writeable buffer protocol + + - `bytearray` + - `memoryview` + - `array.array` + - `ulab.array` + - `rgbmatrix.RGBMatrix` +""" + +AudioSample = Union[ + audiocore.WaveFile, audiocore.RawSample, audiomixer.Mixer, audiomp3.MP3Decoder +] +"""Classes that implement the audiosample protocol + + - `audiocore.WaveFile` + - `audiocore.RawSample` + - `audiomixer.Mixer` + - `audiomp3.MP3Decoder` + + You can play these back with `audioio.AudioOut`, `audiobusio.I2SOut` or `audiopwmio.PWMAudioOut`. +""" + +FrameBuffer = Union[rgbmatrix.RGBMatrix] +"""Classes that implement the framebuffer protocol + + - `rgbmatrix.RGBMatrix` +""" diff --git a/shared-bindings/gnss/GNSS 2.c b/shared-bindings/gnss/GNSS 2.c new file mode 100644 index 000000000..087c35395 --- /dev/null +++ b/shared-bindings/gnss/GNSS 2.c @@ -0,0 +1,205 @@ +// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/gnss/GNSS.h" +#include "shared-bindings/time/__init__.h" +#include "shared-bindings/util.h" + +#include "py/objproperty.h" +#include "py/runtime.h" + +//| class GNSS: +//| """Get updated positioning information from Global Navigation Satellite System (GNSS) +//| +//| Usage:: +//| +//| import gnss +//| import time +//| +//| nav = gnss.GNSS([gnss.SatelliteSystem.GPS, gnss.SatelliteSystem.GLONASS]) +//| last_print = time.monotonic() +//| while True: +//| nav.update() +//| current = time.monotonic() +//| if current - last_print >= 1.0: +//| last_print = current +//| if nav.fix is gnss.PositionFix.INVALID: +//| print("Waiting for fix...") +//| continue +//| print("Latitude: {0:.6f} degrees".format(nav.latitude)) +//| print("Longitude: {0:.6f} degrees".format(nav.longitude))""" +//| + +//| def __init__(self, system: Union[SatelliteSystem, List[SatelliteSystem]]) -> None: +//| """Turn on the GNSS. +//| +//| :param system: satellite system to use""" +//| ... +//| +STATIC mp_obj_t gnss_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + gnss_obj_t *self = m_new_obj(gnss_obj_t); + self->base.type = &gnss_type; + enum { ARG_system }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_system, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + unsigned long selection = 0; + if (MP_OBJ_IS_TYPE(args[ARG_system].u_obj, &gnss_satellitesystem_type)) { + selection |= gnss_satellitesystem_obj_to_type(args[ARG_system].u_obj); + } else if (MP_OBJ_IS_TYPE(args[ARG_system].u_obj, &mp_type_list)) { + size_t systems_size = 0; + mp_obj_t *systems; + mp_obj_list_get(args[ARG_system].u_obj, &systems_size, &systems); + for (size_t i = 0; i < systems_size; ++i) { + if (!MP_OBJ_IS_TYPE(systems[i], &gnss_satellitesystem_type)) { + mp_raise_TypeError(translate("System entry must be gnss.SatelliteSystem")); + } + selection |= gnss_satellitesystem_obj_to_type(systems[i]); + } + } else { + mp_raise_TypeError(translate("System entry must be gnss.SatelliteSystem")); + } + + common_hal_gnss_construct(self, selection); + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Turn off the GNSS.""" +//| ... +//| +STATIC mp_obj_t gnss_obj_deinit(mp_obj_t self_in) { + gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_gnss_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(gnss_deinit_obj, gnss_obj_deinit); + +STATIC void check_for_deinit(gnss_obj_t *self) { + if (common_hal_gnss_deinited(self)) { + raise_deinited_error(); + } +} + +//| def update(self) -> None: +//| """Update GNSS positioning information.""" +//| ... +//| +STATIC mp_obj_t gnss_obj_update(mp_obj_t self_in) { + gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + common_hal_gnss_update(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(gnss_update_obj, gnss_obj_update); + +//| latitude: float +//| """Latitude of current position in degrees (float).""" +//| +STATIC mp_obj_t gnss_obj_get_latitude(mp_obj_t self_in) { + gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_float(common_hal_gnss_get_latitude(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_latitude_obj, gnss_obj_get_latitude); + +const mp_obj_property_t gnss_latitude_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&gnss_get_latitude_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| longitude: float +//| """Longitude of current position in degrees (float).""" +//| +STATIC mp_obj_t gnss_obj_get_longitude(mp_obj_t self_in) { + gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_float(common_hal_gnss_get_longitude(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_longitude_obj, gnss_obj_get_longitude); + +const mp_obj_property_t gnss_longitude_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&gnss_get_longitude_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| altitude: float +//| """Altitude of current position in meters (float).""" +//| +STATIC mp_obj_t gnss_obj_get_altitude(mp_obj_t self_in) { + gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_float(common_hal_gnss_get_altitude(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_altitude_obj, gnss_obj_get_altitude); + +const mp_obj_property_t gnss_altitude_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&gnss_get_altitude_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| timestamp: time.struct_time +//| """Time when the position data was updated.""" +//| +STATIC mp_obj_t gnss_obj_get_timestamp(mp_obj_t self_in) { + gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + timeutils_struct_time_t tm; + common_hal_gnss_get_timestamp(self, &tm); + return struct_time_from_tm(&tm); +} +MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_timestamp_obj, gnss_obj_get_timestamp); + +const mp_obj_property_t gnss_timestamp_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&gnss_get_timestamp_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| fix: PositionFix +//| """Fix mode.""" +//| +STATIC mp_obj_t gnss_obj_get_fix(mp_obj_t self_in) { + gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return gnss_positionfix_type_to_obj(common_hal_gnss_get_fix(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_fix_obj, gnss_obj_get_fix); + +const mp_obj_property_t gnss_fix_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&gnss_get_fix_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t gnss_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&gnss_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&gnss_update_obj) }, + + { MP_ROM_QSTR(MP_QSTR_latitude), MP_ROM_PTR(&gnss_latitude_obj) }, + { MP_ROM_QSTR(MP_QSTR_longitude), MP_ROM_PTR(&gnss_longitude_obj) }, + { MP_ROM_QSTR(MP_QSTR_altitude), MP_ROM_PTR(&gnss_altitude_obj) }, + { MP_ROM_QSTR(MP_QSTR_timestamp), MP_ROM_PTR(&gnss_timestamp_obj) }, + { MP_ROM_QSTR(MP_QSTR_fix), MP_ROM_PTR(&gnss_fix_obj) } +}; +STATIC MP_DEFINE_CONST_DICT(gnss_locals_dict, gnss_locals_dict_table); + +const mp_obj_type_t gnss_type = { + { &mp_type_type }, + .name = MP_QSTR_GNSS, + .make_new = gnss_make_new, + .locals_dict = (mp_obj_dict_t*)&gnss_locals_dict, +}; diff --git a/shared-bindings/gnss/GNSS 2.h b/shared-bindings/gnss/GNSS 2.h new file mode 100644 index 000000000..60069a90a --- /dev/null +++ b/shared-bindings/gnss/GNSS 2.h @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation +// +// SPDX-License-Identifier: MIT + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_GNSS_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_GNSS_H + +#include "common-hal/gnss/GNSS.h" +#include "shared-bindings/gnss/SatelliteSystem.h" +#include "shared-bindings/gnss/PositionFix.h" + +#include "lib/timeutils/timeutils.h" + +extern const mp_obj_type_t gnss_type; + +void common_hal_gnss_construct(gnss_obj_t *self, unsigned long selection); +void common_hal_gnss_deinit(gnss_obj_t *self); +bool common_hal_gnss_deinited(gnss_obj_t *self); +void common_hal_gnss_update(gnss_obj_t *self); + +mp_float_t common_hal_gnss_get_latitude(gnss_obj_t *self); +mp_float_t common_hal_gnss_get_longitude(gnss_obj_t *self); +mp_float_t common_hal_gnss_get_altitude(gnss_obj_t *self); +void common_hal_gnss_get_timestamp(gnss_obj_t *self, timeutils_struct_time_t *tm); +gnss_positionfix_t common_hal_gnss_get_fix(gnss_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_GNSS_H diff --git a/shared-bindings/gnss/PositionFix 2.c b/shared-bindings/gnss/PositionFix 2.c new file mode 100644 index 000000000..e60611d70 --- /dev/null +++ b/shared-bindings/gnss/PositionFix 2.c @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/gnss/PositionFix.h" + +//| class PositionFix: +//| """Position fix mode""" +//| +//| def __init__(self) -> None: +//| """Enum-like class to define the position fix mode.""" +//| +//| INVALID: PositionFix +//| """No measurement.""" +//| +//| FIX_2D: PositionFix +//| """2D fix.""" +//| +//| FIX_3D: PositionFix +//| """3D fix.""" +//| +const mp_obj_type_t gnss_positionfix_type; + +const gnss_positionfix_obj_t gnss_positionfix_invalid_obj = { + { &gnss_positionfix_type }, +}; + +const gnss_positionfix_obj_t gnss_positionfix_fix2d_obj = { + { &gnss_positionfix_type }, +}; + +const gnss_positionfix_obj_t gnss_positionfix_fix3d_obj = { + { &gnss_positionfix_type }, +}; + +gnss_positionfix_t gnss_positionfix_obj_to_type(mp_obj_t obj) { + gnss_positionfix_t posfix = POSITIONFIX_INVALID; + if (obj == MP_ROM_PTR(&gnss_positionfix_fix2d_obj)) { + posfix = POSITIONFIX_2D; + } else if (obj == MP_ROM_PTR(&gnss_positionfix_fix3d_obj)) { + posfix = POSITIONFIX_3D; + } + return posfix; +} + +mp_obj_t gnss_positionfix_type_to_obj(gnss_positionfix_t posfix) { + switch (posfix) { + case POSITIONFIX_2D: + return (mp_obj_t)MP_ROM_PTR(&gnss_positionfix_fix2d_obj); + case POSITIONFIX_3D: + return (mp_obj_t)MP_ROM_PTR(&gnss_positionfix_fix3d_obj); + case POSITIONFIX_INVALID: + default: + return (mp_obj_t)MP_ROM_PTR(&gnss_positionfix_invalid_obj); + } +} + +STATIC const mp_rom_map_elem_t gnss_positionfix_locals_dict_table[] = { + {MP_ROM_QSTR(MP_QSTR_INVALID), MP_ROM_PTR(&gnss_positionfix_invalid_obj)}, + {MP_ROM_QSTR(MP_QSTR_FIX_2D), MP_ROM_PTR(&gnss_positionfix_fix2d_obj)}, + {MP_ROM_QSTR(MP_QSTR_FIX_3D), MP_ROM_PTR(&gnss_positionfix_fix3d_obj)}, +}; +STATIC MP_DEFINE_CONST_DICT(gnss_positionfix_locals_dict, gnss_positionfix_locals_dict_table); + +STATIC void gnss_positionfix_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + qstr posfix = MP_QSTR_INVALID; + if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_positionfix_fix2d_obj)) { + posfix = MP_QSTR_FIX_2D; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_positionfix_fix3d_obj)) { + posfix = MP_QSTR_FIX_3D; + } + mp_printf(print, "%q.%q.%q", MP_QSTR_gnss, MP_QSTR_PositionFix, posfix); +} + +const mp_obj_type_t gnss_positionfix_type = { + { &mp_type_type }, + .name = MP_QSTR_PositionFix, + .print = gnss_positionfix_print, + .locals_dict = (mp_obj_t)&gnss_positionfix_locals_dict, +}; diff --git a/shared-bindings/gnss/PositionFix 2.h b/shared-bindings/gnss/PositionFix 2.h new file mode 100644 index 000000000..34090872c --- /dev/null +++ b/shared-bindings/gnss/PositionFix 2.h @@ -0,0 +1,28 @@ +// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation +// +// SPDX-License-Identifier: MIT + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_POSITIONFIX_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_POSITIONFIX_H + +#include "py/obj.h" + +typedef enum { + POSITIONFIX_INVALID, + POSITIONFIX_2D, + POSITIONFIX_3D, +} gnss_positionfix_t; + +const mp_obj_type_t gnss_positionfix_type; + +gnss_positionfix_t gnss_positionfix_obj_to_type(mp_obj_t obj); +mp_obj_t gnss_positionfix_type_to_obj(gnss_positionfix_t mode); + +typedef struct { + mp_obj_base_t base; +} gnss_positionfix_obj_t; +extern const gnss_positionfix_obj_t gnss_positionfix_invalid_obj; +extern const gnss_positionfix_obj_t gnss_positionfix_fix2d_obj; +extern const gnss_positionfix_obj_t gnss_positionfix_fix3d_obj; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_POSITIONFIX_H diff --git a/shared-bindings/gnss/SatelliteSystem 2.c b/shared-bindings/gnss/SatelliteSystem 2.c new file mode 100644 index 000000000..7d66727b8 --- /dev/null +++ b/shared-bindings/gnss/SatelliteSystem 2.c @@ -0,0 +1,113 @@ +// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/gnss/SatelliteSystem.h" + +//| class SatelliteSystem: +//| """Satellite system type""" +//| +//| def __init__(self) -> None: +//| """Enum-like class to define the satellite system type.""" +//| +//| GPS: SatelliteSystem +//| """Global Positioning System.""" +//| +//| GLONASS: SatelliteSystem +//| """GLObal NAvigation Satellite System.""" +//| +//| SBAS: SatelliteSystem +//| """Satellite Based Augmentation System.""" +//| +//| QZSS_L1CA: SatelliteSystem +//| """Quasi-Zenith Satellite System L1C/A.""" +//| +//| QZSS_L1S: SatelliteSystem +//| """Quasi-Zenith Satellite System L1S.""" +//| +const mp_obj_type_t gnss_satellitesystem_type; + +const gnss_satellitesystem_obj_t gnss_satellitesystem_gps_obj = { + { &gnss_satellitesystem_type }, +}; + +const gnss_satellitesystem_obj_t gnss_satellitesystem_glonass_obj = { + { &gnss_satellitesystem_type }, +}; + +const gnss_satellitesystem_obj_t gnss_satellitesystem_sbas_obj = { + { &gnss_satellitesystem_type }, +}; + +const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1ca_obj = { + { &gnss_satellitesystem_type }, +}; + +const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1s_obj = { + { &gnss_satellitesystem_type }, +}; + +gnss_satellitesystem_t gnss_satellitesystem_obj_to_type(mp_obj_t obj) { + if (obj == MP_ROM_PTR(&gnss_satellitesystem_gps_obj)) { + return SATELLITESYSTEM_GPS; + } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_glonass_obj)) { + return SATELLITESYSTEM_GLONASS; + } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_sbas_obj)) { + return SATELLITESYSTEM_SBAS; + } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj)) { + return SATELLITESYSTEM_QZSS_L1CA; + } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj)) { + return SATELLITESYSTEM_QZSS_L1S; + } + return SATELLITESYSTEM_NONE; +} + +mp_obj_t gnss_satellitesystem_type_to_obj(gnss_satellitesystem_t system) { + switch (system) { + case SATELLITESYSTEM_GPS: + return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_gps_obj); + case SATELLITESYSTEM_GLONASS: + return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_glonass_obj); + case SATELLITESYSTEM_SBAS: + return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_sbas_obj); + case SATELLITESYSTEM_QZSS_L1CA: + return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj); + case SATELLITESYSTEM_QZSS_L1S: + return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj); + case SATELLITESYSTEM_NONE: + default: + return (mp_obj_t)MP_ROM_PTR(&mp_const_none_obj); + } +} + +STATIC const mp_rom_map_elem_t gnss_satellitesystem_locals_dict_table[] = { + {MP_ROM_QSTR(MP_QSTR_GPS), MP_ROM_PTR(&gnss_satellitesystem_gps_obj)}, + {MP_ROM_QSTR(MP_QSTR_GLONASS), MP_ROM_PTR(&gnss_satellitesystem_glonass_obj)}, + {MP_ROM_QSTR(MP_QSTR_SBAS), MP_ROM_PTR(&gnss_satellitesystem_sbas_obj)}, + {MP_ROM_QSTR(MP_QSTR_QZSS_L1CA), MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj)}, + {MP_ROM_QSTR(MP_QSTR_QZSS_L1S), MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj)}, +}; +STATIC MP_DEFINE_CONST_DICT(gnss_satellitesystem_locals_dict, gnss_satellitesystem_locals_dict_table); + +STATIC void gnss_satellitesystem_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + qstr system = MP_QSTR_None; + if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_gps_obj)) { + system = MP_QSTR_GPS; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_glonass_obj)) { + system = MP_QSTR_GLONASS; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_sbas_obj)) { + system = MP_QSTR_SBAS; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj)) { + system = MP_QSTR_QZSS_L1CA; + } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj)) { + system = MP_QSTR_QZSS_L1S; + } + mp_printf(print, "%q.%q.%q", MP_QSTR_gnss, MP_QSTR_SatelliteSystem, system); +} + +const mp_obj_type_t gnss_satellitesystem_type = { + { &mp_type_type }, + .name = MP_QSTR_SatelliteSystem, + .print = gnss_satellitesystem_print, + .locals_dict = (mp_obj_t)&gnss_satellitesystem_locals_dict, +}; diff --git a/shared-bindings/gnss/SatelliteSystem 2.h b/shared-bindings/gnss/SatelliteSystem 2.h new file mode 100644 index 000000000..17f155002 --- /dev/null +++ b/shared-bindings/gnss/SatelliteSystem 2.h @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation +// +// SPDX-License-Identifier: MIT + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_SATELLITESYSTEM_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_SATELLITESYSTEM_H + +#include "py/obj.h" + +typedef enum { + SATELLITESYSTEM_NONE = 0, + SATELLITESYSTEM_GPS = (1U << 0), + SATELLITESYSTEM_GLONASS = (1U << 1), + SATELLITESYSTEM_SBAS = (1U << 2), + SATELLITESYSTEM_QZSS_L1CA = (1U << 3), + SATELLITESYSTEM_QZSS_L1S = (1U << 4), +} gnss_satellitesystem_t; + +const mp_obj_type_t gnss_satellitesystem_type; + +gnss_satellitesystem_t gnss_satellitesystem_obj_to_type(mp_obj_t obj); +mp_obj_t gnss_satellitesystem_type_to_obj(gnss_satellitesystem_t mode); + +typedef struct { + mp_obj_base_t base; +} gnss_satellitesystem_obj_t; +extern const gnss_satellitesystem_obj_t gnss_satellitesystem_gps_obj; +extern const gnss_satellitesystem_obj_t gnss_satellitesystem_glonass_obj; +extern const gnss_satellitesystem_obj_t gnss_satellitesystem_sbas_obj; +extern const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1ca_obj; +extern const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1s_obj; + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_SATELLITESYSTEM_H diff --git a/shared-bindings/gnss/__init__ 2.c b/shared-bindings/gnss/__init__ 2.c new file mode 100644 index 000000000..4b0d312ae --- /dev/null +++ b/shared-bindings/gnss/__init__ 2.c @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/runtime.h" +#include "py/mphal.h" +#include "shared-bindings/gnss/GNSS.h" +#include "shared-bindings/gnss/SatelliteSystem.h" +#include "shared-bindings/gnss/PositionFix.h" +#include "shared-bindings/util.h" + +//| """Global Navigation Satellite System +//| +//| The `gnss` module contains classes to control the GNSS and acquire positioning information.""" +//| +STATIC const mp_rom_map_elem_t gnss_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gnss) }, + { MP_ROM_QSTR(MP_QSTR_GNSS), MP_ROM_PTR(&gnss_type) }, + + // Enum-like Classes. + { MP_ROM_QSTR(MP_QSTR_SatelliteSystem), MP_ROM_PTR(&gnss_satellitesystem_type) }, + { MP_ROM_QSTR(MP_QSTR_PositionFix), MP_ROM_PTR(&gnss_positionfix_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(gnss_module_globals, gnss_module_globals_table); + +const mp_obj_module_t gnss_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&gnss_module_globals, +}; diff --git a/shared-bindings/i2cperipheral/I2CPeripheral 2.c b/shared-bindings/i2cperipheral/I2CPeripheral 2.c new file mode 100644 index 000000000..b5ac861b4 --- /dev/null +++ b/shared-bindings/i2cperipheral/I2CPeripheral 2.c @@ -0,0 +1,436 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Noralf Trønnes + * + * 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 "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/i2cperipheral/I2CPeripheral.h" +#include "shared-bindings/time/__init__.h" +#include "shared-bindings/util.h" + +#include "lib/utils/buffer_helper.h" +#include "lib/utils/context_manager_helpers.h" +#include "lib/utils/interrupt_char.h" + +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +STATIC mp_obj_t mp_obj_new_i2cperipheral_i2c_peripheral_request(i2cperipheral_i2c_peripheral_obj_t *peripheral, uint8_t address, bool is_read, bool is_restart) { + i2cperipheral_i2c_peripheral_request_obj_t *self = m_new_obj(i2cperipheral_i2c_peripheral_request_obj_t); + self->base.type = &i2cperipheral_i2c_peripheral_request_type; + self->peripheral = peripheral; + self->address = address; + self->is_read = is_read; + self->is_restart = is_restart; + return (mp_obj_t)self; +} + +//| class I2CPeripheral: +//| """Two wire serial protocol peripheral""" +//| +//| def __init__(self, scl: microcontroller.Pin, sda: microcontroller.Pin, addresses: Sequence[int], smbus: bool = False) -> None: +//| """I2C is a two-wire protocol for communicating between devices. +//| This implements the peripheral (sensor, secondary) side. +//| +//| :param ~microcontroller.Pin scl: The clock pin +//| :param ~microcontroller.Pin sda: The data pin +//| :param addresses: The I2C addresses to respond to (how many is hw dependent). +//| :type addresses: list[int] +//| :param bool smbus: Use SMBUS timings if the hardware supports it""" +//| ... +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + i2cperipheral_i2c_peripheral_obj_t *self = m_new_obj(i2cperipheral_i2c_peripheral_obj_t); + self->base.type = &i2cperipheral_i2c_peripheral_type; + enum { ARG_scl, ARG_sda, ARG_addresses, ARG_smbus }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_addresses, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_smbus, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mcu_pin_obj_t* scl = validate_obj_is_free_pin(args[ARG_scl].u_obj); + const mcu_pin_obj_t* sda = validate_obj_is_free_pin(args[ARG_sda].u_obj); + + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(args[ARG_addresses].u_obj, &iter_buf); + mp_obj_t item; + uint8_t *addresses = NULL; + unsigned int i = 0; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + mp_int_t value; + if (!mp_obj_get_int_maybe(item, &value)) { + mp_raise_TypeError_varg(translate("can't convert %q to %q"), MP_QSTR_address, MP_QSTR_int); + } + if (value < 0x00 || value > 0x7f) { + mp_raise_ValueError(translate("address out of bounds")); + } + addresses = m_renew(uint8_t, addresses, i, i + 1); + addresses[i++] = value; + } + if (i == 0) { + mp_raise_ValueError(translate("addresses is empty")); + } + + common_hal_i2cperipheral_i2c_peripheral_construct(self, scl, sda, addresses, i, args[ARG_smbus].u_bool); + return (mp_obj_t)self; +} + +//| def deinit(self) -> None: +//| """Releases control of the underlying hardware so other classes can use it.""" +//| ... +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_obj_deinit(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_type)); + i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_i2cperipheral_i2c_peripheral_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cperipheral_i2c_peripheral_deinit_obj, i2cperipheral_i2c_peripheral_obj_deinit); + +//| def __enter__(self) -> I2CPeripheral: +//| """No-op used in Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware on context exit. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_obj___exit__(size_t n_args, const mp_obj_t *args) { + mp_check_self(MP_OBJ_IS_TYPE(args[0], &i2cperipheral_i2c_peripheral_type)); + i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(args[0]); + common_hal_i2cperipheral_i2c_peripheral_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral___exit___obj, 4, 4, i2cperipheral_i2c_peripheral_obj___exit__); + +//| def request(self, timeout: float = -1) -> I2CPeripheralRequest: +//| """Wait for an I2C request. +//| +//| :param float timeout: Timeout in seconds. Zero means wait forever, a negative value means check once +//| :return: I2C Slave Request or None if timeout=-1 and there's no request +//| :rtype: ~i2cperipheral.I2CPeripheralRequest""" +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &i2cperipheral_i2c_peripheral_type)); + i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + if(common_hal_i2cperipheral_i2c_peripheral_deinited(self)) { + raise_deinited_error(); + } + enum { ARG_timeout }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + #if MICROPY_PY_BUILTINS_FLOAT + float f = mp_obj_get_float(args[ARG_timeout].u_obj) * 1000; + int timeout_ms = (int)f; + #else + int timeout_ms = mp_obj_get_int(args[ARG_timeout].u_obj) * 1000; + #endif + + bool forever = false; + uint64_t timeout_end = 0; + if (timeout_ms == 0) { + forever = true; + } else if (timeout_ms > 0) { + timeout_end = common_hal_time_monotonic() + timeout_ms; + } + + int last_error = 0; + + do { + uint8_t address; + bool is_read; + bool is_restart; + + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + return mp_const_none; + } + + int status = common_hal_i2cperipheral_i2c_peripheral_is_addressed(self, &address, &is_read, &is_restart); + if (status < 0) { + // On error try one more time before bailing out + if (last_error) { + mp_raise_OSError(last_error); + } + last_error = -status; + mp_hal_delay_ms(10); + continue; + } + + last_error = 0; + + if (status == 0) { + mp_hal_delay_us(10); + continue; + } + + return mp_obj_new_i2cperipheral_i2c_peripheral_request(self, address, is_read, is_restart); + } while (forever || common_hal_time_monotonic() < timeout_end); + + if (timeout_ms > 0) { + mp_raise_OSError(MP_ETIMEDOUT); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(i2cperipheral_i2c_peripheral_request_obj, 1, i2cperipheral_i2c_peripheral_request); + +STATIC const mp_rom_map_elem_t i2cperipheral_i2c_peripheral_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&i2cperipheral_i2c_peripheral___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_request), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_obj) }, + +}; + +STATIC MP_DEFINE_CONST_DICT(i2cperipheral_i2c_peripheral_locals_dict, i2cperipheral_i2c_peripheral_locals_dict_table); + +const mp_obj_type_t i2cperipheral_i2c_peripheral_type = { + { &mp_type_type }, + .name = MP_QSTR_I2CPeripheral, + .make_new = i2cperipheral_i2c_peripheral_make_new, + .locals_dict = (mp_obj_dict_t*)&i2cperipheral_i2c_peripheral_locals_dict, +}; + +//| class I2CPeripheralRequest: +//| +//| def __init__(self, peripheral: i2cperipheral.I2CPeripheral, address: int, is_read: bool, is_restart: bool) -> None: +//| """Information about an I2C transfer request +//| This cannot be instantiated directly, but is returned by :py:meth:`I2CPeripheral.request`. +//| +//| :param peripheral: The I2CPeripheral object receiving this request +//| :param address: I2C address +//| :param is_read: True if the main peripheral is requesting data +//| :param is_restart: Repeated Start Condition""" +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + mp_arg_check_num(n_args, kw_args, 4, 4, false); + return mp_obj_new_i2cperipheral_i2c_peripheral_request(args[0], mp_obj_get_int(args[1]), mp_obj_is_true(args[2]), mp_obj_is_true(args[3])); +} + +//| def __enter__(self) -> I2CPeripheralRequest: +//| """No-op used in Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Close the request.""" +//| ... +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_obj___exit__(size_t n_args, const mp_obj_t *args) { + mp_check_self(MP_OBJ_IS_TYPE(args[0], &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(args[0]); + common_hal_i2cperipheral_i2c_peripheral_close(self->peripheral); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral_request___exit___obj, 4, 4, i2cperipheral_i2c_peripheral_request_obj___exit__); + +//| address: int +//| """The I2C address of the request.""" +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_address(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(self->address); +} +MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_address_obj, i2cperipheral_i2c_peripheral_request_get_address); + +//| is_read: bool +//| """The I2C main controller is reading from this peripheral.""" +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_is_read(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(self->is_read); +} +MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_is_read_obj, i2cperipheral_i2c_peripheral_request_get_is_read); + +//| is_restart: bool +//| """Is Repeated Start Condition.""" +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_is_restart(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(self->is_restart); +} +MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_is_restart_obj, i2cperipheral_i2c_peripheral_request_get_is_restart); + +//| def read(self, n: int = -1, ack: bool = True) -> bytearray: +//| """Read data. +//| If ack=False, the caller is responsible for calling :py:meth:`I2CPeripheralRequest.ack`. +//| +//| :param n: Number of bytes to read (negative means all) +//| :param ack: Whether or not to send an ACK after the n'th byte +//| :return: Bytes read""" +//| ... +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + enum { ARG_n, ARG_ack }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_n, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_ack, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if (self->is_read) { + mp_raise_OSError(MP_EACCES); + } + + int n = args[ARG_n].u_int; + if (n == 0) { + return mp_obj_new_bytearray(0, NULL); + } + bool ack = args[ARG_ack].u_bool; + + int i = 0; + uint8_t *buffer = NULL; + uint64_t timeout_end = common_hal_time_monotonic() + 10 * 1000; + while (common_hal_time_monotonic() < timeout_end) { + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + break; + } + + uint8_t data; + int num = common_hal_i2cperipheral_i2c_peripheral_read_byte(self->peripheral, &data); + if (num == 0) { + break; + } + + buffer = m_renew(uint8_t, buffer, i, i + 1); + buffer[i++] = data; + if (i == n) { + if (ack) { + common_hal_i2cperipheral_i2c_peripheral_ack(self->peripheral, true); + } + break; + } + common_hal_i2cperipheral_i2c_peripheral_ack(self->peripheral, true); + } + + return mp_obj_new_bytearray(i, buffer); +} +MP_DEFINE_CONST_FUN_OBJ_KW(i2cperipheral_i2c_peripheral_request_read_obj, 1, i2cperipheral_i2c_peripheral_request_read); + +//| def write(self, buffer: ReadableBuffer) -> int: +//| """Write the data contained in buffer. +//| +//| :param ~_typing.ReadableBuffer buffer: Write out the data in this buffer +//| :return: Number of bytes written""" +//| ... +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_write(mp_obj_t self_in, mp_obj_t buf_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (!self->is_read) { + mp_raise_OSError(MP_EACCES); + } + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + + for (size_t i = 0; i < bufinfo.len; i++) { + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + break; + } + + int num = common_hal_i2cperipheral_i2c_peripheral_write_byte(self->peripheral, ((uint8_t *)(bufinfo.buf))[i]); + if (num == 0) { + return mp_obj_new_int(i); + } + } + + return mp_obj_new_int(bufinfo.len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(i2cperipheral_i2c_peripheral_request_write_obj, i2cperipheral_i2c_peripheral_request_write); + +//| def ack(self, ack: bool = True) -> None: +//| """Acknowledge or Not Acknowledge last byte received. +//| Use together with :py:meth:`I2CPeripheralRequest.read` ack=False. +//| +//| :param ack: Whether to send an ACK or NACK""" +//| ... +//| +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_ack(uint n_args, const mp_obj_t *args) { + mp_check_self(MP_OBJ_IS_TYPE(args[0], &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(args[0]); + bool ack = (n_args == 1) ? true : mp_obj_is_true(args[1]); + + if (self->is_read) { + mp_raise_OSError(MP_EACCES); + } + + common_hal_i2cperipheral_i2c_peripheral_ack(self->peripheral, ack); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral_request_ack_obj, 1, 2, i2cperipheral_i2c_peripheral_request_ack); + +STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_close(mp_obj_t self_in) { + mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); + i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_i2cperipheral_i2c_peripheral_close(self->peripheral); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(i2cperipheral_i2c_peripheral_request_close_obj, i2cperipheral_i2c_peripheral_request_close); + +STATIC const mp_rom_map_elem_t i2cperipheral_i2c_peripheral_request_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_read), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_is_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_is_restart), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_is_restart_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_ack), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_ack_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_close_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(i2cperipheral_i2c_peripheral_request_locals_dict, i2cperipheral_i2c_peripheral_request_locals_dict_table); + +const mp_obj_type_t i2cperipheral_i2c_peripheral_request_type = { + { &mp_type_type }, + .name = MP_QSTR_I2CPeripheralRequest, + .make_new = i2cperipheral_i2c_peripheral_request_make_new, + .locals_dict = (mp_obj_dict_t*)&i2cperipheral_i2c_peripheral_request_locals_dict, +}; diff --git a/shared-bindings/i2cperipheral/I2CPeripheral 2.h b/shared-bindings/i2cperipheral/I2CPeripheral 2.h new file mode 100644 index 000000000..3035cfbfe --- /dev/null +++ b/shared-bindings/i2cperipheral/I2CPeripheral 2.h @@ -0,0 +1,60 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Noralf Trønnes + * + * 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_SHARED_BINDINGS_BUSIO_I2C_SLAVE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_SLAVE_H + +#include "py/obj.h" + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/i2cperipheral/I2CPeripheral.h" + +typedef struct { + mp_obj_base_t base; + i2cperipheral_i2c_peripheral_obj_t *peripheral; + uint16_t address; + bool is_read; + bool is_restart; +} i2cperipheral_i2c_peripheral_request_obj_t; + +extern const mp_obj_type_t i2cperipheral_i2c_peripheral_request_type; + +extern const mp_obj_type_t i2cperipheral_i2c_peripheral_type; + +extern void common_hal_i2cperipheral_i2c_peripheral_construct(i2cperipheral_i2c_peripheral_obj_t *self, + const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, + uint8_t *addresses, unsigned int num_addresses, bool smbus); +extern void common_hal_i2cperipheral_i2c_peripheral_deinit(i2cperipheral_i2c_peripheral_obj_t *self); +extern bool common_hal_i2cperipheral_i2c_peripheral_deinited(i2cperipheral_i2c_peripheral_obj_t *self); + +extern int common_hal_i2cperipheral_i2c_peripheral_is_addressed(i2cperipheral_i2c_peripheral_obj_t *self, + uint8_t *address, bool *is_read, bool *is_restart); +extern int common_hal_i2cperipheral_i2c_peripheral_read_byte(i2cperipheral_i2c_peripheral_obj_t *self, uint8_t *data); +extern int common_hal_i2cperipheral_i2c_peripheral_write_byte(i2cperipheral_i2c_peripheral_obj_t *self, uint8_t data); +extern void common_hal_i2cperipheral_i2c_peripheral_ack(i2cperipheral_i2c_peripheral_obj_t *self, bool ack); +extern void common_hal_i2cperipheral_i2c_peripheral_close(i2cperipheral_i2c_peripheral_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_SLAVE_H diff --git a/shared-bindings/i2cperipheral/__init__ 2.c b/shared-bindings/i2cperipheral/__init__ 2.c new file mode 100644 index 000000000..e2cb8509d --- /dev/null +++ b/shared-bindings/i2cperipheral/__init__ 2.c @@ -0,0 +1,106 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Noralf Trønnes + * + * 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 + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +//#include "shared-bindings/i2cperipheral/__init__.h" +#include "shared-bindings/i2cperipheral/I2CPeripheral.h" + +#include "py/runtime.h" + +//| """Two wire serial protocol peripheral +//| +//| The `i2cperipheral` module contains classes to support an I2C peripheral. +//| +//| Example emulating a peripheral with 2 addresses (read and write):: +//| +//| import board +//| from i2cperipheral import I2CPeripheral +//| +//| regs = [0] * 16 +//| index = 0 +//| +//| with I2CPeripheral(board.SCL, board.SDA, (0x40, 0x41)) as device: +//| while True: +//| r = device.request() +//| if not r: +//| # Maybe do some housekeeping +//| continue +//| with r: # Closes the transfer if necessary by sending a NACK or feeding dummy bytes +//| if r.address == 0x40: +//| if not r.is_read: # Main write which is Selected read +//| b = r.read(1) +//| if not b or b[0] > 15: +//| break +//| index = b[0] +//| b = r.read(1) +//| if b: +//| regs[index] = b[0] +//| elif r.is_restart: # Combined transfer: This is the Main read message +//| n = r.write(bytes([regs[index]])) +//| #else: +//| # A read transfer is not supported in this example +//| # If the microcontroller tries, it will get 0xff byte(s) by the ctx manager (r.close()) +//| elif r.address == 0x41: +//| if not r.is_read: +//| b = r.read(1) +//| if b and b[0] == 0xde: +//| # do something +//| pass +//| +//| This example sets up an I2C device that can be accessed from Linux like this:: +//| +//| $ i2cget -y 1 0x40 0x01 +//| 0x00 +//| $ i2cset -y 1 0x40 0x01 0xaa +//| $ i2cget -y 1 0x40 0x01 +//| 0xaa +//| +//| .. warning:: +//| I2CPeripheral makes use of clock stretching in order to slow down +//| the host. +//| Make sure the I2C host supports this. +//| +//| Raspberry Pi in particular does not support this with its I2C hw block. +//| This can be worked around by using the ``i2c-gpio`` bit banging driver. +//| Since the RPi firmware uses the hw i2c, it's not possible to emulate a HAT eeprom.""" +//| + +STATIC const mp_rom_map_elem_t i2cperipheral_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_i2cperipheral) }, + { MP_ROM_QSTR(MP_QSTR_I2CPeripheral), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(i2cperipheral_module_globals, i2cperipheral_module_globals_table); + +const mp_obj_module_t i2cperipheral_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&i2cperipheral_module_globals, +}; diff --git a/shared-bindings/memorymonitor/AllocationAlarm 2.c b/shared-bindings/memorymonitor/AllocationAlarm 2.c new file mode 100644 index 000000000..7de8c1287 --- /dev/null +++ b/shared-bindings/memorymonitor/AllocationAlarm 2.c @@ -0,0 +1,137 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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 + +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/runtime0.h" +#include "shared-bindings/memorymonitor/AllocationAlarm.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| class AllocationAlarm: +//| +//| def __init__(self, *, minimum_block_count: int = 1) -> None: +//| """Throw an exception when an allocation of ``minimum_block_count`` or more blocks +//| occurs while active. +//| +//| Track allocations:: +//| +//| import memorymonitor +//| +//| aa = memorymonitor.AllocationAlarm(minimum_block_count=2) +//| x = 2 +//| # Should not allocate any blocks. +//| with aa: +//| x = 5 +//| +//| # Should throw an exception when allocating storage for the 20 bytes. +//| with aa: +//| x = bytearray(20) +//| +//| """ +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationalarm_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_minimum_block_count }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_minimum_block_count, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_int_t minimum_block_count = args[ARG_minimum_block_count].u_int; + if (minimum_block_count < 1) { + mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_minimum_block_count); + } + + memorymonitor_allocationalarm_obj_t *self = m_new_obj(memorymonitor_allocationalarm_obj_t); + self->base.type = &memorymonitor_allocationalarm_type; + + common_hal_memorymonitor_allocationalarm_construct(self, minimum_block_count); + + return MP_OBJ_FROM_PTR(self); +} + +//| def ignore(self, count: int) -> AllocationAlarm: +//| """Sets the number of applicable allocations to ignore before raising the exception. +//| Automatically set back to zero at context exit. +//| +//| Use it within a ``with`` block:: +//| +//| # Will not alarm because the bytearray allocation will be ignored. +//| with aa.ignore(2): +//| x = bytearray(20) +//| """ +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationalarm_obj_ignore(mp_obj_t self_in, mp_obj_t count_obj) { + mp_int_t count = mp_obj_get_int(count_obj); + if (count < 0) { + mp_raise_ValueError_varg(translate("%q must be >= 0"), MP_QSTR_count); + } + common_hal_memorymonitor_allocationalarm_set_ignore(self_in, count); + return self_in; +} +MP_DEFINE_CONST_FUN_OBJ_2(memorymonitor_allocationalarm_ignore_obj, memorymonitor_allocationalarm_obj_ignore); + +//| def __enter__(self) -> AllocationAlarm: +//| """Enables the alarm.""" +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationalarm_obj___enter__(mp_obj_t self_in) { + common_hal_memorymonitor_allocationalarm_resume(self_in); + return self_in; +} +MP_DEFINE_CONST_FUN_OBJ_1(memorymonitor_allocationalarm___enter___obj, memorymonitor_allocationalarm_obj___enter__); + +//| def __exit__(self) -> None: +//| """Automatically disables the allocation alarm when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationalarm_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_memorymonitor_allocationalarm_set_ignore(args[0], 0); + common_hal_memorymonitor_allocationalarm_pause(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(memorymonitor_allocationalarm___exit___obj, 4, 4, memorymonitor_allocationalarm_obj___exit__); + +STATIC const mp_rom_map_elem_t memorymonitor_allocationalarm_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_ignore), MP_ROM_PTR(&memorymonitor_allocationalarm_ignore_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&memorymonitor_allocationalarm___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&memorymonitor_allocationalarm___exit___obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(memorymonitor_allocationalarm_locals_dict, memorymonitor_allocationalarm_locals_dict_table); + +const mp_obj_type_t memorymonitor_allocationalarm_type = { + { &mp_type_type }, + .name = MP_QSTR_AllocationAlarm, + .make_new = memorymonitor_allocationalarm_make_new, + .locals_dict = (mp_obj_dict_t*)&memorymonitor_allocationalarm_locals_dict, +}; diff --git a/shared-bindings/memorymonitor/AllocationAlarm 2.h b/shared-bindings/memorymonitor/AllocationAlarm 2.h new file mode 100644 index 000000000..304b9c5a7 --- /dev/null +++ b/shared-bindings/memorymonitor/AllocationAlarm 2.h @@ -0,0 +1,39 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONALARM_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONALARM_H + +#include "shared-module/memorymonitor/AllocationAlarm.h" + +extern const mp_obj_type_t memorymonitor_allocationalarm_type; + +void common_hal_memorymonitor_allocationalarm_construct(memorymonitor_allocationalarm_obj_t* self, size_t minimum_block_count); +void common_hal_memorymonitor_allocationalarm_pause(memorymonitor_allocationalarm_obj_t* self); +void common_hal_memorymonitor_allocationalarm_resume(memorymonitor_allocationalarm_obj_t* self); +void common_hal_memorymonitor_allocationalarm_set_ignore(memorymonitor_allocationalarm_obj_t* self, mp_int_t count); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONALARM_H diff --git a/shared-bindings/memorymonitor/AllocationSize 2.c b/shared-bindings/memorymonitor/AllocationSize 2.c new file mode 100644 index 000000000..b35bae360 --- /dev/null +++ b/shared-bindings/memorymonitor/AllocationSize 2.c @@ -0,0 +1,183 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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 + +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/runtime0.h" +#include "shared-bindings/memorymonitor/AllocationSize.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| class AllocationSize: +//| +//| def __init__(self) -> None: +//| """Tracks the number of allocations in power of two buckets. +//| +//| It will have 16 16-bit buckets to track allocation counts. It is total allocations +//| meaning frees are ignored. Reallocated memory is counted twice, at allocation and when +//| reallocated with the larger size. +//| +//| The buckets are measured in terms of blocks which is the finest granularity of the heap. +//| This means bucket 0 will count all allocations less than or equal to the number of bytes +//| per block, typically 16. Bucket 2 will be less than or equal to 4 blocks. See +//| `bytes_per_block` to convert blocks to bytes. +//| +//| Multiple AllocationSizes can be used to track different code boundaries. +//| +//| Track allocations:: +//| +//| import memorymonitor +//| +//| mm = memorymonitor.AllocationSize() +//| with mm: +//| print("hello world" * 3) +//| +//| for bucket, count in enumerate(mm): +//| print("<", 2 ** bucket, count) +//| +//| """ +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationsize_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + memorymonitor_allocationsize_obj_t *self = m_new_obj(memorymonitor_allocationsize_obj_t); + self->base.type = &memorymonitor_allocationsize_type; + + common_hal_memorymonitor_allocationsize_construct(self); + + return MP_OBJ_FROM_PTR(self); +} + +//| def __enter__(self) -> AllocationSize: +//| """Clears counts and resumes tracking.""" +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationsize_obj___enter__(mp_obj_t self_in) { + common_hal_memorymonitor_allocationsize_clear(self_in); + common_hal_memorymonitor_allocationsize_resume(self_in); + return self_in; +} +MP_DEFINE_CONST_FUN_OBJ_1(memorymonitor_allocationsize___enter___obj, memorymonitor_allocationsize_obj___enter__); + +//| def __exit__(self) -> None: +//| """Automatically pauses allocation tracking when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationsize_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_memorymonitor_allocationsize_pause(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(memorymonitor_allocationsize___exit___obj, 4, 4, memorymonitor_allocationsize_obj___exit__); + +//| bytes_per_block: int +//| """Number of bytes per block""" +//| +STATIC mp_obj_t memorymonitor_allocationsize_obj_get_bytes_per_block(mp_obj_t self_in) { + memorymonitor_allocationsize_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return MP_OBJ_NEW_SMALL_INT(common_hal_memorymonitor_allocationsize_get_bytes_per_block(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(memorymonitor_allocationsize_get_bytes_per_block_obj, memorymonitor_allocationsize_obj_get_bytes_per_block); + +const mp_obj_property_t memorymonitor_allocationsize_bytes_per_block_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&memorymonitor_allocationsize_get_bytes_per_block_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| def __len__(self) -> int: +//| """Returns the number of allocation buckets. +//| +//| This allows you to:: +//| +//| mm = memorymonitor.AllocationSize() +//| print(len(mm))""" +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationsize_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + memorymonitor_allocationsize_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint16_t len = common_hal_memorymonitor_allocationsize_get_len(self); + switch (op) { + case MP_UNARY_OP_BOOL: return mp_obj_new_bool(len != 0); + case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(len); + default: return MP_OBJ_NULL; // op not supported + } +} + +//| def __getitem__(self, index: int) -> Optional[int]: +//| """Returns the allocation count for the given bucket. +//| +//| This allows you to:: +//| +//| mm = memorymonitor.AllocationSize() +//| print(mm[0])""" +//| ... +//| +STATIC mp_obj_t memorymonitor_allocationsize_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t value) { + if (value == mp_const_none) { + // delete item + mp_raise_AttributeError(translate("Cannot delete values")); + } else { + memorymonitor_allocationsize_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (MP_OBJ_IS_TYPE(index_obj, &mp_type_slice)) { + mp_raise_NotImplementedError(translate("Slices not supported")); + } else { + size_t index = mp_get_index(&memorymonitor_allocationsize_type, common_hal_memorymonitor_allocationsize_get_len(self), index_obj, false); + if (value == MP_OBJ_SENTINEL) { + // load + return MP_OBJ_NEW_SMALL_INT(common_hal_memorymonitor_allocationsize_get_item(self, index)); + } else { + mp_raise_AttributeError(translate("Read-only")); + } + } + } + return mp_const_none; +} + +STATIC const mp_rom_map_elem_t memorymonitor_allocationsize_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&memorymonitor_allocationsize___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&memorymonitor_allocationsize___exit___obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_bytes_per_block), MP_ROM_PTR(&memorymonitor_allocationsize_bytes_per_block_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(memorymonitor_allocationsize_locals_dict, memorymonitor_allocationsize_locals_dict_table); + +const mp_obj_type_t memorymonitor_allocationsize_type = { + { &mp_type_type }, + .name = MP_QSTR_AllocationSize, + .make_new = memorymonitor_allocationsize_make_new, + .subscr = memorymonitor_allocationsize_subscr, + .unary_op = memorymonitor_allocationsize_unary_op, + .getiter = mp_obj_new_generic_iterator, + .locals_dict = (mp_obj_dict_t*)&memorymonitor_allocationsize_locals_dict, +}; diff --git a/shared-bindings/memorymonitor/AllocationSize 2.h b/shared-bindings/memorymonitor/AllocationSize 2.h new file mode 100644 index 000000000..bcd9514bf --- /dev/null +++ b/shared-bindings/memorymonitor/AllocationSize 2.h @@ -0,0 +1,42 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONSIZE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONSIZE_H + +#include "shared-module/memorymonitor/AllocationSize.h" + +extern const mp_obj_type_t memorymonitor_allocationsize_type; + +extern void common_hal_memorymonitor_allocationsize_construct(memorymonitor_allocationsize_obj_t* self); +extern void common_hal_memorymonitor_allocationsize_pause(memorymonitor_allocationsize_obj_t* self); +extern void common_hal_memorymonitor_allocationsize_resume(memorymonitor_allocationsize_obj_t* self); +extern void common_hal_memorymonitor_allocationsize_clear(memorymonitor_allocationsize_obj_t* self); +extern size_t common_hal_memorymonitor_allocationsize_get_bytes_per_block(memorymonitor_allocationsize_obj_t* self); +extern uint16_t common_hal_memorymonitor_allocationsize_get_len(memorymonitor_allocationsize_obj_t* self); +extern uint16_t common_hal_memorymonitor_allocationsize_get_item(memorymonitor_allocationsize_obj_t* self, int16_t index); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONSIZE_H diff --git a/shared-bindings/memorymonitor/__init__ 2.c b/shared-bindings/memorymonitor/__init__ 2.c new file mode 100644 index 000000000..c101ba5e0 --- /dev/null +++ b/shared-bindings/memorymonitor/__init__ 2.c @@ -0,0 +1,76 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft + * + * 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 + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/memorymonitor/__init__.h" +#include "shared-bindings/memorymonitor/AllocationAlarm.h" +#include "shared-bindings/memorymonitor/AllocationSize.h" + +//| """Memory monitoring helpers""" +//| + +//| class AllocationError(Exception): +//| """Catchall exception for allocation related errors.""" +//| ... +MP_DEFINE_MEMORYMONITOR_EXCEPTION(AllocationError, Exception) + +NORETURN void mp_raise_memorymonitor_AllocationError(const compressed_string_t* fmt, ...) { + va_list argptr; + va_start(argptr,fmt); + mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_memorymonitor_AllocationError, fmt, argptr); + va_end(argptr); + nlr_raise(exception); +} + +STATIC const mp_rom_map_elem_t memorymonitor_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_memorymonitor) }, + { MP_ROM_QSTR(MP_QSTR_AllocationAlarm), MP_ROM_PTR(&memorymonitor_allocationalarm_type) }, + { MP_ROM_QSTR(MP_QSTR_AllocationSize), MP_ROM_PTR(&memorymonitor_allocationsize_type) }, + + // Errors + { MP_ROM_QSTR(MP_QSTR_AllocationError), MP_ROM_PTR(&mp_type_memorymonitor_AllocationError) }, +}; + +STATIC MP_DEFINE_CONST_DICT(memorymonitor_module_globals, memorymonitor_module_globals_table); + +void memorymonitor_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { + mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS; + bool is_subclass = kind & PRINT_EXC_SUBCLASS; + if (!is_subclass && (k == PRINT_EXC)) { + mp_print_str(print, qstr_str(MP_OBJ_QSTR_VALUE(memorymonitor_module_globals_table[0].value))); + mp_print_str(print, "."); + } + mp_obj_exception_print(print, o_in, kind); +} + +const mp_obj_module_t memorymonitor_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&memorymonitor_module_globals, +}; diff --git a/shared-bindings/memorymonitor/__init__ 2.h b/shared-bindings/memorymonitor/__init__ 2.h new file mode 100644 index 000000000..60fcdc3f6 --- /dev/null +++ b/shared-bindings/memorymonitor/__init__ 2.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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_SHARED_BINDINGS_MEMORYMONITOR___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR___INIT___H + +#include "py/obj.h" + + +void memorymonitor_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); + +#define MP_DEFINE_MEMORYMONITOR_EXCEPTION(exc_name, base_name) \ +const mp_obj_type_t mp_type_memorymonitor_ ## exc_name = { \ + { &mp_type_type }, \ + .name = MP_QSTR_ ## exc_name, \ + .print = memorymonitor_exception_print, \ + .make_new = mp_obj_exception_make_new, \ + .attr = mp_obj_exception_attr, \ + .parent = &mp_type_ ## base_name, \ +}; + +extern const mp_obj_type_t mp_type_memorymonitor_AllocationError; + +NORETURN void mp_raise_memorymonitor_AllocationError(const compressed_string_t* msg, ...); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR___INIT___H diff --git a/shared-bindings/sdcardio/SDCard 2.c b/shared-bindings/sdcardio/SDCard 2.c new file mode 100644 index 000000000..975f8b095 --- /dev/null +++ b/shared-bindings/sdcardio/SDCard 2.c @@ -0,0 +1,183 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/objarray.h" + +#include "shared-bindings/sdcardio/SDCard.h" +#include "shared-module/sdcardio/SDCard.h" +#include "common-hal/busio/SPI.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "supervisor/flash.h" + +//| class SDCard: +//| """SD Card Block Interface +//| +//| Controls an SD card over SPI. This built-in module has higher read +//| performance than the library adafruit_sdcard, but it is only compatible with +//| `busio.SPI`, not `bitbangio.SPI`. Usually an SDCard object is used +//| with ``storage.VfsFat`` to allow file I/O to an SD card.""" +//| +//| def __init__(self, bus: busio.SPI, cs: microcontroller.Pin, baudrate: int = 8000000) -> None: +//| """Construct an SPI SD Card object with the given properties +//| +//| :param busio.SPI spi: The SPI bus +//| :param microcontroller.Pin cs: The chip select connected to the card +//| :param int baudrate: The SPI data rate to use after card setup +//| +//| Note that during detection and configuration, a hard-coded low baudrate is used. +//| Data transfers use the specified baurate (rounded down to one that is supported by +//| the microcontroller) +//| +//| Example usage: +//| +//| .. code-block:: python +//| +//| import os +//| +//| import board +//| import sdcardio +//| import storage +//| +//| sd = sdcardio.SDCard(board.SPI(), board.SD_CS) +//| vfs = storage.VfsFat(sd) +//| storage.mount(vfs, '/sd') +//| os.listdir('/sd')""" + +STATIC mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_spi, ARG_cs, ARG_baudrate, ARG_sdio, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_spi, MP_ARG_OBJ, {.u_obj = mp_const_none } }, + { MP_QSTR_cs, MP_ARG_OBJ, {.u_obj = mp_const_none } }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 8000000} }, + { MP_QSTR_sdio, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_int = 8000000} }, + }; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi].u_obj); + mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj); + + sdcardio_sdcard_obj_t *self = m_new_obj(sdcardio_sdcard_obj_t); + self->base.type = &sdcardio_SDCard_type; + + common_hal_sdcardio_sdcard_construct(self, spi, cs, args[ARG_baudrate].u_int); + + return self; +} + + +//| def count(self) -> int: +//| """Returns the total number of sectors +//| +//| Due to technical limitations, this is a function and not a property. +//| +//| :return: The number of 512-byte blocks, as a number""" +//| +mp_obj_t sdcardio_sdcard_count(mp_obj_t self_in) { + sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t*)self_in; + return mp_obj_new_int_from_ull(common_hal_sdcardio_sdcard_get_blockcount(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_count_obj, sdcardio_sdcard_count); + +//| def deinit(self) -> None: +//| """Disable permanently. +//| +//| :return: None""" +//| +mp_obj_t sdcardio_sdcard_deinit(mp_obj_t self_in) { + sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t*)self_in; + common_hal_sdcardio_sdcard_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_deinit_obj, sdcardio_sdcard_deinit); + + +//| def readblocks(self, start_block: int, buf: WriteableBuffer) -> None: +//| +//| """Read one or more blocks from the card +//| +//| :param int start_block: The block to start reading from +//| :param ~_typing.WriteableBuffer buf: The buffer to write into. Length must be multiple of 512. +//| +//| :return: None""" +//| + +mp_obj_t sdcardio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { + uint32_t start_block = mp_obj_get_int(start_block_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); + sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t*)self_in; + int result = common_hal_sdcardio_sdcard_readblocks(self, start_block, &bufinfo); + if (result < 0) { + mp_raise_OSError(-result); + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_readblocks_obj, sdcardio_sdcard_readblocks); + +//| def writeblocks(self, start_block: int, buf: ReadableBuffer) -> None: +//| +//| """Write one or more blocks to the card +//| +//| :param int start_block: The block to start writing from +//| :param ~_typing.ReadableBuffer buf: The buffer to read from. Length must be multiple of 512. +//| +//| :return: None""" +//| + +mp_obj_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { + uint32_t start_block = mp_obj_get_int(start_block_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t*)self_in; + int result = common_hal_sdcardio_sdcard_writeblocks(self, start_block, &bufinfo); + if (result < 0) { + mp_raise_OSError(-result); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_writeblocks_obj, sdcardio_sdcard_writeblocks); + +STATIC const mp_rom_map_elem_t sdcardio_sdcard_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&sdcardio_sdcard_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sdcardio_sdcard_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&sdcardio_sdcard_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&sdcardio_sdcard_writeblocks_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(sdcardio_sdcard_locals_dict, sdcardio_sdcard_locals_dict_table); + +const mp_obj_type_t sdcardio_SDCard_type = { + { &mp_type_type }, + .name = MP_QSTR_SDCard, + .make_new = sdcardio_sdcard_make_new, + .locals_dict = (mp_obj_dict_t*)&sdcardio_sdcard_locals_dict, +}; diff --git a/shared-bindings/sdcardio/SDCard 2.h b/shared-bindings/sdcardio/SDCard 2.h new file mode 100644 index 000000000..5986d5b81 --- /dev/null +++ b/shared-bindings/sdcardio/SDCard 2.h @@ -0,0 +1,30 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017, 2018 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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. + */ + +#pragma once + +extern const mp_obj_type_t sdcardio_SDCard_type; diff --git a/shared-bindings/sdcardio/__init__ 2.c b/shared-bindings/sdcardio/__init__ 2.c new file mode 100644 index 000000000..746aa5588 --- /dev/null +++ b/shared-bindings/sdcardio/__init__ 2.c @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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 + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/sdcardio/SDCard.h" + +//| """Interface to an SD card via the SPI bus""" + +STATIC const mp_rom_map_elem_t sdcardio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdcardio) }, + { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&sdcardio_SDCard_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(sdcardio_module_globals, sdcardio_module_globals_table); + +const mp_obj_module_t sdcardio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&sdcardio_module_globals, +}; diff --git a/shared-bindings/sdcardio/__init__ 2.h b/shared-bindings/sdcardio/__init__ 2.h new file mode 100644 index 000000000..e69de29bb diff --git a/shared-bindings/sdioio/SDCard 2.c b/shared-bindings/sdioio/SDCard 2.c new file mode 100644 index 000000000..aba414cd6 --- /dev/null +++ b/shared-bindings/sdioio/SDCard 2.c @@ -0,0 +1,296 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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. + */ + +// This file contains all of the Python API definitions for the +// sdioio.SDCard class. + +#include + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/sdioio/SDCard.h" +#include "shared-bindings/util.h" + +#include "lib/utils/buffer_helper.h" +#include "lib/utils/context_manager_helpers.h" +#include "py/mperrno.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + +//| class SDCard: +//| """SD Card Block Interface with SDIO +//| +//| Controls an SD card over SDIO. SDIO is a parallel protocol designed +//| for SD cards. It uses a clock pin, a command pin, and 1 or 4 +//| data pins. It can be operated at a high frequency such as +//| 25MHz. Usually an SDCard object is used with ``storage.VfsFat`` +//| to allow file I/O to an SD card.""" +//| +//| def __init__(self, clock: microcontroller.Pin, command: microcontroller.Pin, data: Sequence[microcontroller.Pin], frequency: int) -> None: +//| """Construct an SDIO SD Card object with the given properties +//| +//| :param ~microcontroller.Pin clock: the pin to use for the clock. +//| :param ~microcontroller.Pin command: the pin to use for the command. +//| :param data: A sequence of pins to use for data. +//| :param frequency: The frequency of the bus in Hz +//| +//| Example usage: +//| +//| .. code-block:: python +//| +//| import os +//| +//| import board +//| import sdioio +//| import storage +//| +//| sd = sdioio.SDCard( +//| clock=board.SDIO_CLOCK, +//| command=board.SDIO_COMMAND, +//| data=board.SDIO_DATA, +//| frequency=25000000) +//| vfs = storage.VfsFat(sd) +//| storage.mount(vfs, '/sd') +//| os.listdir('/sd')""" +//| ... +//| + +STATIC mp_obj_t sdioio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + sdioio_sdcard_obj_t *self = m_new_obj(sdioio_sdcard_obj_t); + self->base.type = &sdioio_SDCard_type; + enum { ARG_clock, ARG_command, ARG_data, ARG_frequency, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ }, + { MP_QSTR_command, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ }, + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ }, + { MP_QSTR_frequency, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT }, + }; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mcu_pin_obj_t* clock = validate_obj_is_free_pin(args[ARG_clock].u_obj); + const mcu_pin_obj_t* command = validate_obj_is_free_pin(args[ARG_command].u_obj); + mcu_pin_obj_t *data_pins[4]; + uint8_t num_data; + validate_list_is_free_pins(MP_QSTR_data, data_pins, MP_ARRAY_SIZE(data_pins), args[ARG_data].u_obj, &num_data); + + common_hal_sdioio_sdcard_construct(self, clock, command, num_data, data_pins, args[ARG_frequency].u_int); + return MP_OBJ_FROM_PTR(self); +} + +STATIC void check_for_deinit(sdioio_sdcard_obj_t *self) { + if (common_hal_sdioio_sdcard_deinited(self)) { + raise_deinited_error(); + } +} + +//| def configure(self, frequency: int = 0, width: int = 0) -> None: +//| """Configures the SDIO bus. +//| +//| :param int frequency: the desired clock rate in Hertz. The actual clock rate may be higher or lower due to the granularity of available clock settings. Check the `frequency` attribute for the actual clock rate. +//| :param int width: the number of data lines to use. Must be 1 or 4 and must also not exceed the number of data lines at construction +//| +//| .. note:: Leaving a value unspecified or 0 means the current setting is kept""" +//| +STATIC mp_obj_t sdioio_sdcard_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_frequency, ARG_width, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t frequency = args[ARG_frequency].u_int; + if (frequency < 0) { + mp_raise_ValueError_varg(translate("Invalid %q"), MP_QSTR_baudrate); + } + + uint8_t width = args[ARG_width].u_int; + if (width != 0 && width != 1 && width != 4) { + mp_raise_ValueError_varg(translate("Invalid %q"), MP_QSTR_width); + } + + if (!common_hal_sdioio_sdcard_configure(self, frequency, width)) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(sdioio_sdcard_configure_obj, 1, sdioio_sdcard_configure); + +//| def count(self) -> int: +//| """Returns the total number of sectors +//| +//| Due to technical limitations, this is a function and not a property. +//| +//| :return: The number of 512-byte blocks, as a number""" +//| +STATIC mp_obj_t sdioio_sdcard_count(mp_obj_t self_in) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_sdioio_sdcard_get_count(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_count_obj, sdioio_sdcard_count); + +//| def readblocks(self, start_block: int, buf: WriteableBuffer) -> None: +//| +//| """Read one or more blocks from the card +//| +//| :param int start_block: The block to start reading from +//| :param ~_typing.WriteableBuffer buf: The buffer to write into. Length must be multiple of 512. +//| +//| :return: None""" +mp_obj_t sdioio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { + uint32_t start_block = mp_obj_get_int(start_block_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); + sdioio_sdcard_obj_t *self = (sdioio_sdcard_obj_t*)self_in; + int result = common_hal_sdioio_sdcard_readblocks(self, start_block, &bufinfo); + if (result < 0) { + mp_raise_OSError(-result); + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_3(sdioio_sdcard_readblocks_obj, sdioio_sdcard_readblocks); + +//| def writeblocks(self, start_block: int, buf: ReadableBuffer) -> None: +//| +//| """Write one or more blocks to the card +//| +//| :param int start_block: The block to start writing from +//| :param ~_typing.ReadableBuffer buf: The buffer to read from. Length must be multiple of 512. +//| +//| :return: None""" +//| +mp_obj_t sdioio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { + uint32_t start_block = mp_obj_get_int(start_block_in); + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + sdioio_sdcard_obj_t *self = (sdioio_sdcard_obj_t*)self_in; + int result = common_hal_sdioio_sdcard_writeblocks(self, start_block, &bufinfo); + if (result < 0) { + mp_raise_OSError(-result); + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_3(sdioio_sdcard_writeblocks_obj, sdioio_sdcard_writeblocks); + +//| @property +//| def frequency(self) -> int: +//| """The actual SDIO bus frequency. This may not match the frequency +//| requested due to internal limitations.""" +//| ... +//| +STATIC mp_obj_t sdioio_sdcard_obj_get_frequency(mp_obj_t self_in) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_sdioio_sdcard_get_frequency(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_get_frequency_obj, sdioio_sdcard_obj_get_frequency); + +const mp_obj_property_t sdioio_sdcard_frequency_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&sdioio_sdcard_get_frequency_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| @property +//| def width(self) -> int: +//| """The actual SDIO bus width, in bits""" +//| ... +//| +STATIC mp_obj_t sdioio_sdcard_obj_get_width(mp_obj_t self_in) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_sdioio_sdcard_get_width(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_get_width_obj, sdioio_sdcard_obj_get_width); + +const mp_obj_property_t sdioio_sdcard_width_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&sdioio_sdcard_get_width_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| def deinit(self) -> None: +//| """Disable permanently. +//| +//| :return: None""" +STATIC mp_obj_t sdioio_sdcard_obj_deinit(mp_obj_t self_in) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_sdioio_sdcard_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_deinit_obj, sdioio_sdcard_obj_deinit); + +//| def __enter__(self) -> SDCard: +//| """No-op used by Context Managers. +//| Provided by context manager helper.""" +//| ... +//| + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t sdioio_sdcard_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_sdioio_sdcard_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(sdioio_sdcard_obj___exit___obj, 4, 4, sdioio_sdcard_obj___exit__); + +STATIC const mp_rom_map_elem_t sdioio_sdcard_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sdioio_sdcard_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&sdioio_sdcard_obj___exit___obj) }, + + { MP_ROM_QSTR(MP_QSTR_configure), MP_ROM_PTR(&sdioio_sdcard_configure_obj) }, + { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&sdioio_sdcard_frequency_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&sdioio_sdcard_width_obj) }, + + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&sdioio_sdcard_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&sdioio_sdcard_readblocks_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&sdioio_sdcard_writeblocks_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(sdioio_sdcard_locals_dict, sdioio_sdcard_locals_dict_table); + +const mp_obj_type_t sdioio_SDCard_type = { + { &mp_type_type }, + .name = MP_QSTR_SDCard, + .make_new = sdioio_sdcard_make_new, + .locals_dict = (mp_obj_dict_t*)&sdioio_sdcard_locals_dict, +}; diff --git a/shared-bindings/sdioio/SDCard 2.h b/shared-bindings/sdioio/SDCard 2.h new file mode 100644 index 000000000..7f62ee7a6 --- /dev/null +++ b/shared-bindings/sdioio/SDCard 2.h @@ -0,0 +1,66 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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_SHARED_BINDINGS_BUSIO_SDIO_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SDIO_H + +#include "py/obj.h" + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/sdioio/SDCard.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t sdioio_SDCard_type; + +// Construct an underlying SDIO object. +extern void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, + const mcu_pin_obj_t * clock, const mcu_pin_obj_t * command, + uint8_t num_data, mcu_pin_obj_t ** data, uint32_t frequency); + +extern void common_hal_sdioio_sdcard_deinit(sdioio_sdcard_obj_t *self); +extern bool common_hal_sdioio_sdcard_deinited(sdioio_sdcard_obj_t *self); + +extern bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t baudrate, uint8_t width); + +extern void common_hal_sdioio_sdcard_unlock(sdioio_sdcard_obj_t *self); + +// Return actual SDIO bus frequency. +uint32_t common_hal_sdioio_sdcard_get_frequency(sdioio_sdcard_obj_t* self); + +// Return SDIO bus width. +uint8_t common_hal_sdioio_sdcard_get_width(sdioio_sdcard_obj_t* self); + +// Return number of device blocks +uint32_t common_hal_sdioio_sdcard_get_count(sdioio_sdcard_obj_t* self); + +// Read or write blocks +int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t* self, uint32_t start_block, mp_buffer_info_t *bufinfo); +int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t* self, uint32_t start_block, mp_buffer_info_t *bufinfo); + +// This is used by the supervisor to claim SDIO devices indefinitely. +extern void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SDIO_H diff --git a/shared-bindings/sdioio/__init__ 2.c b/shared-bindings/sdioio/__init__ 2.c new file mode 100644 index 000000000..b88e5c3a9 --- /dev/null +++ b/shared-bindings/sdioio/__init__ 2.c @@ -0,0 +1,47 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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 + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/sdioio/SDCard.h" + +//| """Interface to an SD card via the SDIO bus""" + +STATIC const mp_rom_map_elem_t sdioio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdio) }, + { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&sdioio_SDCard_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(sdioio_module_globals, sdioio_module_globals_table); + +const mp_obj_module_t sdioio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&sdioio_module_globals, +}; diff --git a/shared-bindings/sdioio/__init__ 2.h b/shared-bindings/sdioio/__init__ 2.h new file mode 100644 index 000000000..e69de29bb diff --git a/shared-module/memorymonitor/AllocationAlarm 2.c b/shared-module/memorymonitor/AllocationAlarm 2.c new file mode 100644 index 000000000..35f4e4c63 --- /dev/null +++ b/shared-module/memorymonitor/AllocationAlarm 2.c @@ -0,0 +1,94 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-bindings/memorymonitor/__init__.h" +#include "shared-bindings/memorymonitor/AllocationAlarm.h" + +#include "py/gc.h" +#include "py/mpstate.h" +#include "py/runtime.h" + +void common_hal_memorymonitor_allocationalarm_construct(memorymonitor_allocationalarm_obj_t* self, size_t minimum_block_count) { + self->minimum_block_count = minimum_block_count; + self->next = NULL; + self->previous = NULL; +} + +void common_hal_memorymonitor_allocationalarm_set_ignore(memorymonitor_allocationalarm_obj_t* self, mp_int_t count) { + self->count = count; +} + +void common_hal_memorymonitor_allocationalarm_pause(memorymonitor_allocationalarm_obj_t* self) { + // Check to make sure we aren't already paused. We can be if we're exiting from an exception we + // caused. + if (self->previous == NULL) { + return; + } + *self->previous = self->next; + self->next = NULL; + self->previous = NULL; +} + +void common_hal_memorymonitor_allocationalarm_resume(memorymonitor_allocationalarm_obj_t* self) { + if (self->previous != NULL) { + mp_raise_RuntimeError(translate("Already running")); + } + self->next = MP_STATE_VM(active_allocationalarms); + self->previous = (memorymonitor_allocationalarm_obj_t**) &MP_STATE_VM(active_allocationalarms); + if (self->next != NULL) { + self->next->previous = &self->next; + } + MP_STATE_VM(active_allocationalarms) = self; +} + +void memorymonitor_allocationalarms_allocation(size_t block_count) { + memorymonitor_allocationalarm_obj_t* alarm = MP_OBJ_TO_PTR(MP_STATE_VM(active_allocationalarms)); + size_t alert_count = 0; + while (alarm != NULL) { + // Hold onto next in case we remove the alarm from the list. + memorymonitor_allocationalarm_obj_t* next = alarm->next; + if (block_count >= alarm->minimum_block_count) { + if (alarm->count > 0) { + alarm->count--; + } else { + // Uncomment the breakpoint below if you want to use a C debugger to figure out the C + // call stack for an allocation. + // asm("bkpt"); + // Pause now because we may alert when throwing the exception too. + common_hal_memorymonitor_allocationalarm_pause(alarm); + alert_count++; + } + } + alarm = next; + } + if (alert_count > 0) { + mp_raise_memorymonitor_AllocationError(translate("Attempt to allocate %d blocks"), block_count); + } +} + +void memorymonitor_allocationalarms_reset(void) { + MP_STATE_VM(active_allocationalarms) = NULL; +} diff --git a/shared-module/memorymonitor/AllocationAlarm 2.h b/shared-module/memorymonitor/AllocationAlarm 2.h new file mode 100644 index 000000000..172c24f6c --- /dev/null +++ b/shared-module/memorymonitor/AllocationAlarm 2.h @@ -0,0 +1,51 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONALARM_H +#define MICROPY_INCLUDED_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONALARM_H + +#include +#include + +#include "py/obj.h" + +typedef struct _memorymonitor_allocationalarm_obj_t memorymonitor_allocationalarm_obj_t; + +#define ALLOCATION_SIZE_BUCKETS 16 + +typedef struct _memorymonitor_allocationalarm_obj_t { + mp_obj_base_t base; + size_t minimum_block_count; + mp_int_t count; + // Store the location that points to us so we can remove ourselves. + memorymonitor_allocationalarm_obj_t** previous; + memorymonitor_allocationalarm_obj_t* next; +} memorymonitor_allocationalarm_obj_t; + +void memorymonitor_allocationalarms_allocation(size_t block_count); +void memorymonitor_allocationalarms_reset(void); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONALARM_H diff --git a/shared-module/memorymonitor/AllocationSize 2.c b/shared-module/memorymonitor/AllocationSize 2.c new file mode 100644 index 000000000..c28e65592 --- /dev/null +++ b/shared-module/memorymonitor/AllocationSize 2.c @@ -0,0 +1,91 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-bindings/memorymonitor/AllocationSize.h" + +#include "py/gc.h" +#include "py/mpstate.h" +#include "py/runtime.h" + +void common_hal_memorymonitor_allocationsize_construct(memorymonitor_allocationsize_obj_t* self) { + common_hal_memorymonitor_allocationsize_clear(self); + self->next = NULL; + self->previous = NULL; +} + +void common_hal_memorymonitor_allocationsize_pause(memorymonitor_allocationsize_obj_t* self) { + *self->previous = self->next; + self->next = NULL; + self->previous = NULL; +} + +void common_hal_memorymonitor_allocationsize_resume(memorymonitor_allocationsize_obj_t* self) { + if (self->previous != NULL) { + mp_raise_RuntimeError(translate("Already running")); + } + self->next = MP_STATE_VM(active_allocationsizes); + self->previous = (memorymonitor_allocationsize_obj_t**) &MP_STATE_VM(active_allocationsizes); + if (self->next != NULL) { + self->next->previous = &self->next; + } + MP_STATE_VM(active_allocationsizes) = self; +} + +void common_hal_memorymonitor_allocationsize_clear(memorymonitor_allocationsize_obj_t* self) { + for (size_t i = 0; i < ALLOCATION_SIZE_BUCKETS; i++) { + self->buckets[i] = 0; + } +} + +uint16_t common_hal_memorymonitor_allocationsize_get_len(memorymonitor_allocationsize_obj_t* self) { + return ALLOCATION_SIZE_BUCKETS; +} + +size_t common_hal_memorymonitor_allocationsize_get_bytes_per_block(memorymonitor_allocationsize_obj_t* self) { + return BYTES_PER_BLOCK; +} + +uint16_t common_hal_memorymonitor_allocationsize_get_item(memorymonitor_allocationsize_obj_t* self, int16_t index) { + return self->buckets[index]; +} + +void memorymonitor_allocationsizes_track_allocation(size_t block_count) { + memorymonitor_allocationsize_obj_t* as = MP_OBJ_TO_PTR(MP_STATE_VM(active_allocationsizes)); + size_t power_of_two = 0; + block_count >>= 1; + while (block_count != 0) { + power_of_two++; + block_count >>= 1; + } + while (as != NULL) { + as->buckets[power_of_two]++; + as = as->next; + } +} + +void memorymonitor_allocationsizes_reset(void) { + MP_STATE_VM(active_allocationsizes) = NULL; +} diff --git a/shared-module/memorymonitor/AllocationSize 2.h b/shared-module/memorymonitor/AllocationSize 2.h new file mode 100644 index 000000000..3baab2213 --- /dev/null +++ b/shared-module/memorymonitor/AllocationSize 2.h @@ -0,0 +1,51 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONSIZE_H +#define MICROPY_INCLUDED_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONSIZE_H + +#include +#include + +#include "py/obj.h" + +typedef struct _memorymonitor_allocationsize_obj_t memorymonitor_allocationsize_obj_t; + +#define ALLOCATION_SIZE_BUCKETS 16 + +typedef struct _memorymonitor_allocationsize_obj_t { + mp_obj_base_t base; + uint16_t buckets[ALLOCATION_SIZE_BUCKETS]; + // Store the location that points to us so we can remove ourselves. + memorymonitor_allocationsize_obj_t** previous; + memorymonitor_allocationsize_obj_t* next; + bool paused; +} memorymonitor_allocationsize_obj_t; + +void memorymonitor_allocationsizes_track_allocation(size_t block_count); +void memorymonitor_allocationsizes_reset(void); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONSIZE_H diff --git a/shared-module/memorymonitor/__init__ 2.c b/shared-module/memorymonitor/__init__ 2.c new file mode 100644 index 000000000..6cb424153 --- /dev/null +++ b/shared-module/memorymonitor/__init__ 2.c @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft + * + * 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 "shared-module/memorymonitor/__init__.h" +#include "shared-module/memorymonitor/AllocationAlarm.h" +#include "shared-module/memorymonitor/AllocationSize.h" + +void memorymonitor_track_allocation(size_t block_count) { + memorymonitor_allocationalarms_allocation(block_count); + memorymonitor_allocationsizes_track_allocation(block_count); +} + +void memorymonitor_reset(void) { + memorymonitor_allocationalarms_reset(); + memorymonitor_allocationsizes_reset(); +} diff --git a/shared-module/memorymonitor/__init__ 2.h b/shared-module/memorymonitor/__init__ 2.h new file mode 100644 index 000000000..f47f6434b --- /dev/null +++ b/shared-module/memorymonitor/__init__ 2.h @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries + * + * 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_MEMORYMONITOR___INIT___H +#define MICROPY_INCLUDED_MEMORYMONITOR___INIT___H + +#include + +void memorymonitor_track_allocation(size_t block_count); +void memorymonitor_reset(void); + +#endif // MICROPY_INCLUDED_MEMORYMONITOR___INIT___H diff --git a/shared-module/sdcardio/SDCard 2.c b/shared-module/sdcardio/SDCard 2.c new file mode 100644 index 000000000..9e861279d --- /dev/null +++ b/shared-module/sdcardio/SDCard 2.c @@ -0,0 +1,466 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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. + */ + +// This implementation largely follows the structure of adafruit_sdcard.py + +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/time/__init__.h" +#include "shared-bindings/util.h" +#include "shared-module/sdcardio/SDCard.h" + +#include "py/mperrno.h" + +#if 0 +#define DEBUG_PRINT(...) ((void)mp_printf(&mp_plat_print, ## __VA_ARGS__)) +#else +#define DEBUG_PRINT(...) ((void)0) +#endif + +#define CMD_TIMEOUT (200) + +#define R1_IDLE_STATE (1<<0) +#define R1_ILLEGAL_COMMAND (1<<2) + +#define TOKEN_CMD25 (0xFC) +#define TOKEN_STOP_TRAN (0xFD) +#define TOKEN_DATA (0xFE) + +STATIC bool lock_and_configure_bus(sdcardio_sdcard_obj_t *self) { + if (!common_hal_busio_spi_try_lock(self->bus)) { + return false; + } + common_hal_busio_spi_configure(self->bus, self->baudrate, 0, 0, 8); + common_hal_digitalio_digitalinout_set_value(&self->cs, false); + return true; +} + +STATIC void lock_bus_or_throw(sdcardio_sdcard_obj_t *self) { + if (!lock_and_configure_bus(self)) { + mp_raise_OSError(EAGAIN); + } +} + +STATIC void clock_card(sdcardio_sdcard_obj_t *self, int bytes) { + uint8_t buf[] = {0xff}; + common_hal_digitalio_digitalinout_set_value(&self->cs, true); + for (int i=0; ibus, buf, 1); + } +} + +STATIC void extraclock_and_unlock_bus(sdcardio_sdcard_obj_t *self) { + clock_card(self, 1); + common_hal_busio_spi_unlock(self->bus); +} + +static uint8_t CRC7(const uint8_t* data, uint8_t n) { + uint8_t crc = 0; + for (uint8_t i = 0; i < n; i++) { + uint8_t d = data[i]; + for (uint8_t j = 0; j < 8; j++) { + crc <<= 1; + if ((d & 0x80) ^ (crc & 0x80)) { + crc ^= 0x09; + } + d <<= 1; + } + } + return (crc << 1) | 1; +} + +#define READY_TIMEOUT_NS (300 * 1000 * 1000) // 300ms +STATIC void wait_for_ready(sdcardio_sdcard_obj_t *self) { + uint64_t deadline = common_hal_time_monotonic_ns() + READY_TIMEOUT_NS; + while (common_hal_time_monotonic_ns() < deadline) { + uint8_t b; + common_hal_busio_spi_read(self->bus, &b, 1, 0xff); + if (b == 0xff) { + break; + } + } +} + +// In Python API, defaults are response=None, data_block=True, wait=True +STATIC int cmd(sdcardio_sdcard_obj_t *self, int cmd, int arg, void *response_buf, size_t response_len, bool data_block, bool wait) { + DEBUG_PRINT("cmd % 3d [%02x] arg=% 11d [%08x] len=%d%s%s\n", cmd, cmd, arg, arg, response_len, data_block ? " data" : "", wait ? " wait" : ""); + uint8_t cmdbuf[6]; + cmdbuf[0] = cmd | 0x40; + cmdbuf[1] = (arg >> 24) & 0xff; + cmdbuf[2] = (arg >> 16) & 0xff; + cmdbuf[3] = (arg >> 8) & 0xff; + cmdbuf[4] = arg & 0xff; + cmdbuf[5] = CRC7(cmdbuf, 5); + + if (wait) { + wait_for_ready(self); + } + + common_hal_busio_spi_write(self->bus, cmdbuf, sizeof(cmdbuf)); + + // Wait for the response (response[7] == 0) + bool response_received = false; + for (int i=0; ibus, cmdbuf, 1, 0xff); + if ((cmdbuf[0] & 0x80) == 0) { + response_received = true; + break; + } + } + + if (!response_received) { + return -EIO; + } + + if (response_buf) { + + if (data_block) { + cmdbuf[1] = 0xff; + do { + // Wait for the start block byte + common_hal_busio_spi_read(self->bus, cmdbuf+1, 1, 0xff); + } while (cmdbuf[1] != 0xfe); + } + + common_hal_busio_spi_read(self->bus, response_buf, response_len, 0xff); + + if (data_block) { + // Read and discard the CRC-CCITT checksum + common_hal_busio_spi_read(self->bus, cmdbuf+1, 2, 0xff); + } + + } + + return cmdbuf[0]; +} + +STATIC int block_cmd(sdcardio_sdcard_obj_t *self, int cmd_, int block, void *response_buf, size_t response_len, bool data_block, bool wait) { + return cmd(self, cmd_, block * self->cdv, response_buf, response_len, true, true); +} + +STATIC bool cmd_nodata(sdcardio_sdcard_obj_t* self, int cmd, int response) { + uint8_t cmdbuf[2] = {cmd, 0xff}; + + common_hal_busio_spi_write(self->bus, cmdbuf, sizeof(cmdbuf)); + + // Wait for the response (response[7] == response) + for (int i=0; ibus, cmdbuf, 1, 0xff); + if (cmdbuf[0] == response) { + return 0; + } + } + return -EIO; +} + +STATIC const compressed_string_t *init_card_v1(sdcardio_sdcard_obj_t *self) { + for (int i=0; icdv = 1; + } + return NULL; + } + } + return translate("timeout waiting for v2 card"); +} + +STATIC const compressed_string_t *init_card(sdcardio_sdcard_obj_t *self) { + clock_card(self, 10); + + common_hal_digitalio_digitalinout_set_value(&self->cs, false); + + // CMD0: init card: should return _R1_IDLE_STATE (allow 5 attempts) + { + bool reached_idle_state = false; + for (int i=0; i<5; i++) { + if (cmd(self, 0, 0, NULL, 0, true, true) == R1_IDLE_STATE) { + reached_idle_state = true; + break; + } + } + if (!reached_idle_state) { + return translate("no SD card"); + } + } + + // CMD8: determine card version + { + uint8_t rb7[4]; + int response = cmd(self, 8, 0x1AA, rb7, sizeof(rb7), false, true); + if (response == R1_IDLE_STATE) { + const compressed_string_t *result =init_card_v2(self); + if (result != NULL) { + return result; + } + } else if (response == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) { + const compressed_string_t *result =init_card_v1(self); + if (result != NULL) { + return result; + } + } else { + return translate("couldn't determine SD card version"); + } + } + + // CMD9: get number of sectors + { + uint8_t csd[16]; + int response = cmd(self, 9, 0, csd, sizeof(csd), true, true); + if (response != 0) { + return translate("no response from SD card"); + } + int csd_version = (csd[0] & 0xC0) >> 6; + if (csd_version >= 2) { + return translate("SD card CSD format not supported"); + } + + if (csd_version == 1) { + self->sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024; + } else { + uint32_t block_length = 1 << (csd[5] & 0xF); + uint32_t c_size = ((csd[6] & 0x3) << 10) | (csd[7] << 2) | ((csd[8] & 0xC) >> 6); + uint32_t mult = 1 << (((csd[9] & 0x3) << 1 | (csd[10] & 0x80) >> 7) + 2); + self->sectors = block_length / 512 * mult * (c_size + 1); + } + } + + // CMD16: set block length to 512 bytes + { + int response = cmd(self, 16, 512, NULL, 0, true, true); + if (response != 0) { + return translate("can't set 512 block size"); + } + } + + return NULL; +} + +void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, mcu_pin_obj_t *cs, int baudrate) { + self->bus = bus; + common_hal_digitalio_digitalinout_construct(&self->cs, cs); + common_hal_digitalio_digitalinout_switch_to_output(&self->cs, true, DRIVE_MODE_PUSH_PULL); + + self->cdv = 512; + self->sectors = 0; + self->baudrate = 250000; + + lock_bus_or_throw(self); + const compressed_string_t *result = init_card(self); + extraclock_and_unlock_bus(self); + + if (result != NULL) { + common_hal_digitalio_digitalinout_deinit(&self->cs); + mp_raise_OSError_msg(result); + } + + self->baudrate = baudrate; +} + +void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self) { + if (!self->bus) { + return; + } + self->bus = 0; + common_hal_digitalio_digitalinout_deinit(&self->cs); +} + +void common_hal_sdcardio_check_for_deinit(sdcardio_sdcard_obj_t *self) { + if (!self->bus) { + raise_deinited_error(); + } +} + +int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self) { + common_hal_sdcardio_check_for_deinit(self); + return self->sectors; +} + +int readinto(sdcardio_sdcard_obj_t *self, void *buf, size_t size) { + uint8_t aux[2] = {0, 0}; + while (aux[0] != 0xfe) { + common_hal_busio_spi_read(self->bus, aux, 1, 0xff); + } + + common_hal_busio_spi_read(self->bus, buf, size, 0xff); + + // Read checksum and throw it away + common_hal_busio_spi_read(self->bus, aux, sizeof(aux), 0xff); + return 0; +} + +int readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { + uint32_t nblocks = buf->len / 512; + if (nblocks == 1) { + // Use CMD17 to read a single block + return block_cmd(self, 17, start_block, buf->buf, buf->len, true, true); + } else { + // Use CMD18 to read multiple blocks + int r = block_cmd(self, 18, start_block, NULL, 0, true, true); + if (r < 0) { + return r; + } + + uint8_t *ptr = buf->buf; + while (nblocks--) { + r = readinto(self, ptr, 512); + if (r < 0) { + return r; + } + ptr += 512; + } + + // End the multi-block read + r = cmd(self, 12, 0, NULL, 0, true, false); + + // Return first status 0 or last before card ready (0xff) + while (r != 0) { + uint8_t single_byte; + common_hal_busio_spi_read(self->bus, &single_byte, 1, 0xff); + if (single_byte & 0x80) { + return r; + } + r = single_byte; + } + } + return 0; +} + +int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { + common_hal_sdcardio_check_for_deinit(self); + if (buf->len % 512 != 0) { + mp_raise_ValueError(translate("Buffer length must be a multiple of 512")); + } + + lock_and_configure_bus(self); + int r = readblocks(self, start_block, buf); + extraclock_and_unlock_bus(self); + return r; +} + +int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t size) { + wait_for_ready(self); + + uint8_t cmd[2]; + cmd[0] = token; + + common_hal_busio_spi_write(self->bus, cmd, 1); + common_hal_busio_spi_write(self->bus, buf, size); + + cmd[0] = cmd[1] = 0xff; + common_hal_busio_spi_write(self->bus, cmd, 2); + + // Check the response + // This differs from the traditional adafruit_sdcard handling, + // but adafruit_sdcard also ignored the return value of SDCard._write(!) + // so nobody noticed + // + // + // Response is as follows: + // x x x 0 STAT 1 + // 7 6 5 4 3..1 0 + // with STATUS 010 indicating "data accepted", and other status bit + // combinations indicating failure. + // In practice, I was seeing cmd[0] as 0xe5, indicating success + for (int i=0; ibus, cmd, 1, 0xff); + DEBUG_PRINT("i=%02d cmd[0] = 0x%02x\n", i, cmd[0]); + if ((cmd[0] & 0b00010001) == 0b00000001) { + if ((cmd[0] & 0x1f) != 0x5) { + return -EIO; + } else { + break; + } + } + } + + // Wait for the write to finish + do { + common_hal_busio_spi_read(self->bus, cmd, 1, 0xff); + } while (cmd[0] == 0); + + // Success + return 0; +} + +int writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { + common_hal_sdcardio_check_for_deinit(self); + uint32_t nblocks = buf->len / 512; + if (nblocks == 1) { + // Use CMD24 to write a single block + int r = block_cmd(self, 24, start_block, NULL, 0, true, true); + if (r < 0) { + return r; + } + r = _write(self, TOKEN_DATA, buf->buf, buf->len); + if (r < 0) { + return r; + } + } else { + // Use CMD25 to write multiple block + int r = block_cmd(self, 25, start_block, NULL, 0, true, true); + if (r < 0) { + return r; + } + + uint8_t *ptr = buf->buf; + while (nblocks--) { + r = _write(self, TOKEN_CMD25, ptr, 512); + if (r < 0) { + return r; + } + ptr += 512; + } + + cmd_nodata(self, TOKEN_STOP_TRAN, 0); + } + return 0; +} + +int common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { + common_hal_sdcardio_check_for_deinit(self); + if (buf->len % 512 != 0) { + mp_raise_ValueError(translate("Buffer length must be a multiple of 512")); + } + lock_and_configure_bus(self); + int r = writeblocks(self, start_block, buf); + extraclock_and_unlock_bus(self); + return r; +} diff --git a/shared-module/sdcardio/SDCard 2.h b/shared-module/sdcardio/SDCard 2.h new file mode 100644 index 000000000..76c906029 --- /dev/null +++ b/shared-module/sdcardio/SDCard 2.h @@ -0,0 +1,51 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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. + */ + +#pragma once + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/objarray.h" + +#include "common-hal/busio/SPI.h" +#include "common-hal/digitalio/DigitalInOut.h" + +typedef struct { + mp_obj_base_t base; + busio_spi_obj_t *bus; + digitalio_digitalinout_obj_t cs; + int cdv; + int baudrate; + uint32_t sectors; +} sdcardio_sdcard_obj_t; + +void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *spi, mcu_pin_obj_t *cs, int baudrate); +void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self); +void common_hal_sdcardio_sdcard_check_for_deinit(sdcardio_sdcard_obj_t *self); +int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self); +int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); +int common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); diff --git a/shared-module/sdcardio/__init__ 2.c b/shared-module/sdcardio/__init__ 2.c new file mode 100644 index 000000000..e69de29bb diff --git a/shared-module/sdcardio/__init__ 2.h b/shared-module/sdcardio/__init__ 2.h new file mode 100644 index 000000000..e69de29bb diff --git a/supervisor/background_callback 2.h b/supervisor/background_callback 2.h new file mode 100644 index 000000000..535dd656b --- /dev/null +++ b/supervisor/background_callback 2.h @@ -0,0 +1,87 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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 CIRCUITPY_INCLUDED_SUPERVISOR_BACKGROUND_CALLBACK_H +#define CIRCUITPY_INCLUDED_SUPERVISOR_BACKGROUND_CALLBACK_H + +/** Background callbacks are a linked list of tasks to call in the background. + * + * Include a member of type `background_callback_t` inside an object + * which needs to queue up background work, and zero-initialize it. + * + * To schedule the work, use background_callback_add, with fun as the + * function to call and data pointing to the object itself. + * + * Next time run_background_tasks_if_tick is called, the callback will + * be run and removed from the linked list. + * + * Queueing a task that is already queued does nothing. Unconditionally + * re-queueing it from its own background task will cause it to run during the + * very next background-tasks invocation, leading to a CircuitPython freeze, so + * don't do that. + * + * background_callback_add can be called from interrupt context. + */ +typedef void (*background_callback_fun)(void *data); +typedef struct background_callback { + background_callback_fun fun; + void *data; + struct background_callback *next; + struct background_callback *prev; +} background_callback_t; + +/* Add a background callback for which 'fun' and 'data' were previously set */ +void background_callback_add_core(background_callback_t *cb); + +/* Add a background callback to the given function with the given data. When + * the callback involves an object on the GC heap, the 'data' must be a pointer + * to that object itself, not an internal pointer. Otherwise, it can be the + * case that no other references to the object itself survive, and the object + * becomes garbage collected while an outstanding background callback still + * exists. + */ +void background_callback_add(background_callback_t *cb, background_callback_fun fun, void *data); + +/* Run all background callbacks. Normally, this is done by the supervisor + * whenever the list is non-empty */ +void background_callback_run_all(void); + +/* During soft reset, remove all pending callbacks and clear the critical section flag */ +void background_callback_reset(void); + +/* Sometimes background callbacks must be blocked. Use these functions to + * bracket the section of code where this is the case. These calls nest, and + * begins must be balanced with ends. + */ +void background_callback_begin_critical_section(void); +void background_callback_end_critical_section(void); + +/* + * Background callbacks may stop objects from being collected + */ +void background_callback_gc_collect(void); + +#endif diff --git a/supervisor/shared/background_callback 2.c b/supervisor/shared/background_callback 2.c new file mode 100644 index 000000000..8e12dd362 --- /dev/null +++ b/supervisor/shared/background_callback 2.c @@ -0,0 +1,138 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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 + +#include "py/gc.h" +#include "py/mpconfig.h" +#include "supervisor/background_callback.h" +#include "supervisor/shared/tick.h" +#include "shared-bindings/microcontroller/__init__.h" + +STATIC volatile background_callback_t *callback_head, *callback_tail; + +#define CALLBACK_CRITICAL_BEGIN (common_hal_mcu_disable_interrupts()) +#define CALLBACK_CRITICAL_END (common_hal_mcu_enable_interrupts()) + +void background_callback_add_core(background_callback_t *cb) { + CALLBACK_CRITICAL_BEGIN; + if (cb->prev || callback_head == cb) { + CALLBACK_CRITICAL_END; + return; + } + cb->next = 0; + cb->prev = (background_callback_t*)callback_tail; + if (callback_tail) { + callback_tail->next = cb; + cb->prev = (background_callback_t*)callback_tail; + } + if (!callback_head) { + callback_head = cb; + } + callback_tail = cb; + CALLBACK_CRITICAL_END; +} + +void background_callback_add(background_callback_t *cb, background_callback_fun fun, void *data) { + cb->fun = fun; + cb->data = data; + background_callback_add_core(cb); +} + +static bool in_background_callback; +void background_callback_run_all() { + if (!callback_head) { + return; + } + CALLBACK_CRITICAL_BEGIN; + if (in_background_callback) { + CALLBACK_CRITICAL_END; + return; + } + in_background_callback = true; + background_callback_t *cb = (background_callback_t*)callback_head; + callback_head = NULL; + callback_tail = NULL; + while (cb) { + background_callback_t *next = cb->next; + cb->next = cb->prev = NULL; + background_callback_fun fun = cb->fun; + void *data = cb->data; + CALLBACK_CRITICAL_END; + // Leave the critical section in order to run the callback function + if (fun) { + fun(data); + } + CALLBACK_CRITICAL_BEGIN; + cb = next; + } + in_background_callback = false; + CALLBACK_CRITICAL_END; +} + +void background_callback_begin_critical_section() { + CALLBACK_CRITICAL_BEGIN; +} + +void background_callback_end_critical_section() { + CALLBACK_CRITICAL_END; +} + +void background_callback_reset() { + CALLBACK_CRITICAL_BEGIN; + background_callback_t *cb = (background_callback_t*)callback_head; + while(cb) { + background_callback_t *next = cb->next; + memset(cb, 0, sizeof(*cb)); + cb = next; + } + callback_head = NULL; + callback_tail = NULL; + in_background_callback = false; + CALLBACK_CRITICAL_END; +} + +void background_callback_gc_collect(void) { + // We don't enter the callback critical section here. We rely on + // gc_collect_ptr _NOT_ entering background callbacks, so it is not + // possible for the list to be cleared. + // + // However, it is possible for the list to be extended. We make the + // minor assumption that no newly added callback is for a + // collectable object. That is, we only plug the hole where an + // object becomes collectable AFTER it is added but before the + // callback is run, not the hole where an object was ALREADY + // collectable but adds a background task for itself. + // + // It's necessary to traverse the whole list here, as the callbacks + // themselves can be in non-gc memory, and some of the cb->data + // objects themselves might be in non-gc memory. + background_callback_t *cb = (background_callback_t*)callback_head; + while(cb) { + gc_collect_ptr(cb->data); + cb = cb->next; + } +} -- cgit v1.2.3 From 4ba9ff892c2176d4aeefe1a8287cdb899acf5da1 Mon Sep 17 00:00:00 2001 From: Margaret Matocha Date: Mon, 10 Aug 2020 11:04:56 -0500 Subject: Added bitmap.blit function for copying slices of bitmaps --- shared-bindings/displayio/Bitmap.c | 62 +++++++++++++++++++++++++++++++++++++- shared-bindings/displayio/Bitmap.h | 2 ++ shared-module/displayio/Bitmap.c | 31 +++++++++++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Bitmap.c b/shared-bindings/displayio/Bitmap.c index 0a45bbdfd..56c6007f0 100644 --- a/shared-bindings/displayio/Bitmap.c +++ b/shared-bindings/displayio/Bitmap.c @@ -172,7 +172,66 @@ STATIC mp_obj_t bitmap_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t val return mp_const_none; } -//| def fill(self, value: int) -> None: +//| def blit(self, x: int, y: int, source_bitmap: bitmap, x1: int, y1: int, x2: int, y2:int) -> Any: +//| """Inserts the source_bitmap region defined by rectangular boundaries +//| (x1,y1) and (x2,y2) into the bitmap at the specified (x,y) location. +//| :param int x: Horizontal pixel location in bitmap where source_bitmap upper-left +//| corner will be placed +//| :param int y: Vertical pixel location in bitmap where source_bitmap upper-left +//| corner will be placed +//| :param bitmap source_bitmap: Source bitmap that contains the graphical region to be copied +//| : param x1: Minimum x-value for rectangular bounding box to be copied from the source bitmap +//| : param y1: Minimum y-value for rectangular bounding box to be copied from the source bitmap +//| : param x2: Maximum x-value for rectangular bounding box to be copied from the source bitmap +//| : param y2: Maximum y-value for rectangular bounding box to be copied from the source bitmap +//| +//| ... +//| + +STATIC mp_obj_t displayio_bitmap_obj_blit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args){ + + // Consider improving the input checking. + + displayio_bitmap_t *self = MP_OBJ_TO_PTR(pos_args[0]); + int16_t x = mp_obj_get_int(pos_args[1]); + int16_t y = mp_obj_get_int(pos_args[2]); + displayio_bitmap_t *source = MP_OBJ_TO_PTR(pos_args[3]); + int16_t x1 = mp_obj_get_int(pos_args[4]); + int16_t y1 = mp_obj_get_int(pos_args[5]); + int16_t x2 = mp_obj_get_int(pos_args[6]); + int16_t y2 = mp_obj_get_int(pos_args[7]); + + if ( (x<0) || (y<0) || (x > self-> width) || (y > self->height) ) { + mp_raise_ValueError(translate("(x,y): out of range of target bitmap")); + } + if ( (x1 < 0) || (x1 > source->width) || + (y1 < 0) || (y1 > source->height) || + (x2 < 0) || (x2 > source->width) || + (y2 < 0) || (y2 > source->height) ) { + mp_raise_ValueError(translate("(x1,y1) or (x2,y2): out of range of source bitmap")); + } + + // Ensure x1 < x2 and y1 < y2 + if (x1 > x2) { + int16_t temp=x2; + x2=x1; + x1=temp; + } + if (y1 > y2) { + int16_t temp=y2; + y2=y1; + y1=temp; + } + + common_hal_displayio_bitmap_blit(self, x, y, source, x1, y1, x2, y2); + + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(displayio_bitmap_blit_obj, 8, displayio_bitmap_obj_blit); +// requires 8 parameters + +//| def fill(self, value: Any) -> Any: //| """Fills the bitmap with the supplied palette index value.""" //| ... //| @@ -192,6 +251,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_bitmap_fill_obj, displayio_bitmap_obj_fill); STATIC const mp_rom_map_elem_t displayio_bitmap_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_bitmap_height_obj) }, { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_bitmap_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_blit), MP_ROM_PTR(&displayio_bitmap_blit_obj) }, { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&displayio_bitmap_fill_obj) }, }; diff --git a/shared-bindings/displayio/Bitmap.h b/shared-bindings/displayio/Bitmap.h index 46c337329..8225af6c6 100644 --- a/shared-bindings/displayio/Bitmap.h +++ b/shared-bindings/displayio/Bitmap.h @@ -40,6 +40,8 @@ uint16_t common_hal_displayio_bitmap_get_height(displayio_bitmap_t *self); uint16_t common_hal_displayio_bitmap_get_width(displayio_bitmap_t *self); uint32_t common_hal_displayio_bitmap_get_bits_per_value(displayio_bitmap_t *self); void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *bitmap, int16_t x, int16_t y, uint32_t value); +void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16_t y, displayio_bitmap_t *source, + int16_t x1, int16_t y1, int16_t x2, int16_t y2); uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *bitmap, int16_t x, int16_t y); void common_hal_displayio_bitmap_fill(displayio_bitmap_t *bitmap, uint32_t value); diff --git a/shared-module/displayio/Bitmap.c b/shared-module/displayio/Bitmap.c index 8bcda6086..dde346ad3 100644 --- a/shared-module/displayio/Bitmap.c +++ b/shared-module/displayio/Bitmap.c @@ -105,6 +105,37 @@ uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *self, int16_t return 0; } +void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16_t y, displayio_bitmap_t *source, + int16_t x1, int16_t y1, int16_t x2, int16_t y2) { + // Copy complete "source" bitmap into "self" bitmap at location x,y in the "self" + // Add a boolean to determine if all values are copied, or only if non-zero + // Default is copy all values, but for text glyphs this should copy only non-zero values + + if (self->read_only) { + mp_raise_RuntimeError(translate("Read-only object")); + } + + // If this value is encountered in the source bitmap, it will not be copied (for text glyphs) + // This should be added as an optional parameter, and if it is `None`, then all pixels are copied + uint32_t skip_value=0; + + // simplest version - use internal functions for get/set pixels + for (uint16_t i=0; i<= (x2-x1) ; i++) { + if ( (x+i >= 0) && (x+i < self->width) ) { + for (uint16_t j=0; j<= (y2-y1) ; j++){ + if ((y+j >= 0) && (y+j < self->height) ) { + uint32_t value = common_hal_displayio_bitmap_get_pixel(source, x1+i, y1+j); + if ( (value != skip_value) ) { + common_hal_displayio_bitmap_set_pixel(self, x+i, y+j, value); + } + } + } + } + } + +} + + void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *self, int16_t x, int16_t y, uint32_t value) { if (self->read_only) { mp_raise_RuntimeError(translate("Read-only object")); -- cgit v1.2.3 From 824f47d6e99d85b2b604db524c9e9178e0a99ceb Mon Sep 17 00:00:00 2001 From: Margaret Matocha Date: Wed, 12 Aug 2020 21:50:17 -0500 Subject: Added bitmap.blit function for bitmap slice copy --- shared-bindings/displayio/Bitmap.c | 100 +++++++++++++++++++++++++++---------- shared-bindings/displayio/Bitmap.h | 3 +- shared-module/displayio/Bitmap.c | 16 +++--- 3 files changed, 84 insertions(+), 35 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Bitmap.c b/shared-bindings/displayio/Bitmap.c index 56c6007f0..af9f6c3c8 100644 --- a/shared-bindings/displayio/Bitmap.c +++ b/shared-bindings/displayio/Bitmap.c @@ -172,7 +172,7 @@ STATIC mp_obj_t bitmap_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t val return mp_const_none; } -//| def blit(self, x: int, y: int, source_bitmap: bitmap, x1: int, y1: int, x2: int, y2:int) -> Any: +//| def blit(self, x: int, y: int, source_bitmap: bitmap, x1: int, y1: int, x2: int, y2: int, skip_index: int) -> Any: //| """Inserts the source_bitmap region defined by rectangular boundaries //| (x1,y1) and (x2,y2) into the bitmap at the specified (x,y) location. //| :param int x: Horizontal pixel location in bitmap where source_bitmap upper-left @@ -180,34 +180,74 @@ STATIC mp_obj_t bitmap_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t val //| :param int y: Vertical pixel location in bitmap where source_bitmap upper-left //| corner will be placed //| :param bitmap source_bitmap: Source bitmap that contains the graphical region to be copied -//| : param x1: Minimum x-value for rectangular bounding box to be copied from the source bitmap -//| : param y1: Minimum y-value for rectangular bounding box to be copied from the source bitmap -//| : param x2: Maximum x-value for rectangular bounding box to be copied from the source bitmap -//| : param y2: Maximum y-value for rectangular bounding box to be copied from the source bitmap -//| +//| : param int x1: Minimum x-value for rectangular bounding box to be copied from the source bitmap +//| : param int y1: Minimum y-value for rectangular bounding box to be copied from the source bitmap +//| : param int x2: Maximum x-value for rectangular bounding box to be copied from the source bitmap +//| : param int y2: Maximum y-value for rectangular bounding box to be copied from the source bitmap +//| : param int skip_index: bitmap palette index in the source that will not be copied, set `None` to copy all pixels //| ... //| STATIC mp_obj_t displayio_bitmap_obj_blit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args){ + enum {ARG_x, ARG_y, ARG_source, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_skip_index}; + static const mp_arg_t allowed_args[] = { + {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_source, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_x1, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + {MP_QSTR_y1, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + {MP_QSTR_x2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->width + {MP_QSTR_y2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->height + {MP_QSTR_skip_index, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj=mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + displayio_bitmap_t *self = MP_OBJ_TO_PTR(pos_args[0]); //******* + + int16_t x = args[ARG_x].u_int; + int16_t y = args[ARG_y].u_int; + + displayio_bitmap_t *source = MP_OBJ_TO_PTR(args[ARG_source].u_obj); + + int16_t x1, y1; + // if x1 or y1 is None, then set as the zero-point of the bitmap + if ( args[ARG_x1].u_obj == mp_const_none ) { + x1 = 0; + } else { + x1 = mp_obj_get_int(args[ARG_x1].u_obj); + } + //int16_t y1; + if ( args[ARG_y1].u_obj == mp_const_none ) { + y1 = 0; + } else { + y1 = mp_obj_get_int(args[ARG_y1].u_obj); + } + + int16_t x2, y2; + // if x2 or y2 is None, then set as the maximum size of the source bitmap + if ( args[ARG_x2].u_obj == mp_const_none ) { + x2 = source->width-1; + } else { + x2 = mp_obj_get_int(args[ARG_x2].u_obj); + } + //int16_t y2; + if ( args[ARG_y2].u_obj == mp_const_none ) { + y2 = source->height-1; + } else { + y2 = mp_obj_get_int(args[ARG_y2].u_obj); + } - // Consider improving the input checking. - - displayio_bitmap_t *self = MP_OBJ_TO_PTR(pos_args[0]); - int16_t x = mp_obj_get_int(pos_args[1]); - int16_t y = mp_obj_get_int(pos_args[2]); - displayio_bitmap_t *source = MP_OBJ_TO_PTR(pos_args[3]); - int16_t x1 = mp_obj_get_int(pos_args[4]); - int16_t y1 = mp_obj_get_int(pos_args[5]); - int16_t x2 = mp_obj_get_int(pos_args[6]); - int16_t y2 = mp_obj_get_int(pos_args[7]); - if ( (x<0) || (y<0) || (x > self-> width) || (y > self->height) ) { + // Check x,y are within self (target) bitmap boundary + if ( (x < 0) || (y < 0) || (x >= self->width) || (y >= self->height) ) { mp_raise_ValueError(translate("(x,y): out of range of target bitmap")); } - if ( (x1 < 0) || (x1 > source->width) || - (y1 < 0) || (y1 > source->height) || - (x2 < 0) || (x2 > source->width) || - (y2 < 0) || (y2 > source->height) ) { + // Check x1,y1,x2,y2 are within source bitmap boundary + if ( (x1 < 0) || (x1 >= source->width) || + (y1 < 0) || (y1 >= source->height) || + (x2 < 0) || (x2 >= source->width) || + (y2 < 0) || (y2 >= source->height) ) { mp_raise_ValueError(translate("(x1,y1) or (x2,y2): out of range of source bitmap")); } @@ -223,13 +263,23 @@ STATIC mp_obj_t displayio_bitmap_obj_blit(size_t n_args, const mp_obj_t *pos_arg y1=temp; } - common_hal_displayio_bitmap_blit(self, x, y, source, x1, y1, x2, y2); + uint32_t skip_index; + bool skip_index_none; // flag whether skip_value was None + + if (args[ARG_skip_index].u_obj == mp_const_none ) { + skip_index = 0; + skip_index_none = true; + } else { + skip_index = mp_obj_get_int(args[ARG_skip_index].u_obj); + skip_index_none = false; + } + + common_hal_displayio_bitmap_blit(self, x, y, source, x1, y1, x2, y2, skip_index, skip_index_none); return mp_const_none; } - -MP_DEFINE_CONST_FUN_OBJ_KW(displayio_bitmap_blit_obj, 8, displayio_bitmap_obj_blit); -// requires 8 parameters +MP_DEFINE_CONST_FUN_OBJ_KW(displayio_bitmap_blit_obj, 4, displayio_bitmap_obj_blit); +// `displayio_bitmap_obj_blit` requires at least 4 arguments //| def fill(self, value: Any) -> Any: //| """Fills the bitmap with the supplied palette index value.""" diff --git a/shared-bindings/displayio/Bitmap.h b/shared-bindings/displayio/Bitmap.h index 8225af6c6..cf75f3d76 100644 --- a/shared-bindings/displayio/Bitmap.h +++ b/shared-bindings/displayio/Bitmap.h @@ -41,7 +41,8 @@ uint16_t common_hal_displayio_bitmap_get_width(displayio_bitmap_t *self); uint32_t common_hal_displayio_bitmap_get_bits_per_value(displayio_bitmap_t *self); void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *bitmap, int16_t x, int16_t y, uint32_t value); void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16_t y, displayio_bitmap_t *source, - int16_t x1, int16_t y1, int16_t x2, int16_t y2); + int16_t x1, int16_t y1, int16_t x2, int16_t y2, + uint32_t skip_index, bool skip_index_none); uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *bitmap, int16_t x, int16_t y); void common_hal_displayio_bitmap_fill(displayio_bitmap_t *bitmap, uint32_t value); diff --git a/shared-module/displayio/Bitmap.c b/shared-module/displayio/Bitmap.c index dde346ad3..dbcba6b58 100644 --- a/shared-module/displayio/Bitmap.c +++ b/shared-module/displayio/Bitmap.c @@ -106,26 +106,24 @@ uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *self, int16_t } void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16_t y, displayio_bitmap_t *source, - int16_t x1, int16_t y1, int16_t x2, int16_t y2) { + int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint32_t skip_index, bool skip_index_none) { // Copy complete "source" bitmap into "self" bitmap at location x,y in the "self" // Add a boolean to determine if all values are copied, or only if non-zero - // Default is copy all values, but for text glyphs this should copy only non-zero values + // + // If skip_value is encountered in the source bitmap, it will not be copied. + // If skip_value is `None`, then all pixels are copied. if (self->read_only) { mp_raise_RuntimeError(translate("Read-only object")); } - // If this value is encountered in the source bitmap, it will not be copied (for text glyphs) - // This should be added as an optional parameter, and if it is `None`, then all pixels are copied - uint32_t skip_value=0; - // simplest version - use internal functions for get/set pixels - for (uint16_t i=0; i<= (x2-x1) ; i++) { + for (int16_t i=0; i<= (x2-x1) ; i++) { if ( (x+i >= 0) && (x+i < self->width) ) { - for (uint16_t j=0; j<= (y2-y1) ; j++){ + for (int16_t j=0; j<= (y2-y1) ; j++){ if ((y+j >= 0) && (y+j < self->height) ) { uint32_t value = common_hal_displayio_bitmap_get_pixel(source, x1+i, y1+j); - if ( (value != skip_value) ) { + if ( (skip_index_none) || (value != skip_index) ) { // write if skip_value_none is True common_hal_displayio_bitmap_set_pixel(self, x+i, y+j, value); } } -- cgit v1.2.3 From a66ef32da2fee0077f7917071294fa54b689e2e9 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Thu, 13 Aug 2020 17:03:06 -0500 Subject: Added inclusive indexing for x2,y2, fixed default value handling for x1,y1, added bitmap palette comparison --- locale/circuitpython.pot | 40 +++++++++++++++++++++++++++++++-- shared-bindings/displayio/Bitmap.c | 45 +++++++++++++++----------------------- shared-module/displayio/Bitmap.c | 4 ++-- 3 files changed, 58 insertions(+), 31 deletions(-) (limited to 'shared-module') diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index a1b286e2e..3eb5b1ced 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-14 09:36-0400\n" +"POT-Creation-Date: 2020-08-14 13:10-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -82,6 +82,8 @@ msgstr "" msgid "%q list must be a list" msgstr "" +#: shared-bindings/memorymonitor/AllocationAlarm 3.c +#: shared-bindings/memorymonitor/AllocationAlarm 4.c #: shared-bindings/memorymonitor/AllocationAlarm.c msgid "%q must be >= 0" msgstr "" @@ -89,6 +91,8 @@ msgstr "" #: shared-bindings/_bleio/CharacteristicBuffer.c #: shared-bindings/_bleio/PacketBuffer.c shared-bindings/displayio/Group.c #: shared-bindings/displayio/Shape.c +#: shared-bindings/memorymonitor/AllocationAlarm 3.c +#: shared-bindings/memorymonitor/AllocationAlarm 4.c #: shared-bindings/memorymonitor/AllocationAlarm.c #: shared-bindings/vectorio/Circle.c shared-bindings/vectorio/Rectangle.c msgid "%q must be >= 1" @@ -252,6 +256,14 @@ msgstr "" msgid "'yield' outside function" msgstr "" +#: shared-bindings/displayio/Bitmap.c +msgid "(x,y): out of range of target bitmap" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +msgid "(x1,y1) or (x2,y2): out of range of source bitmap" +msgstr "" + #: py/compile.c msgid "*x must be assignment target" msgstr "" @@ -306,6 +318,7 @@ msgstr "" msgid "All timers for this pin are in use" msgstr "" +#: ports/atmel-samd/common-hal/_pew/PewPew 2.c #: ports/atmel-samd/common-hal/_pew/PewPew.c #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c @@ -322,7 +335,11 @@ msgstr "" msgid "Already advertising." msgstr "" +#: shared-module/memorymonitor/AllocationAlarm 3.c +#: shared-module/memorymonitor/AllocationAlarm 4.c #: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize 3.c +#: shared-module/memorymonitor/AllocationSize 4.c #: shared-module/memorymonitor/AllocationSize.c msgid "Already running" msgstr "" @@ -362,6 +379,8 @@ msgstr "" msgid "At most %d %q may be specified (not %d)" msgstr "" +#: shared-module/memorymonitor/AllocationAlarm 3.c +#: shared-module/memorymonitor/AllocationAlarm 4.c #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -491,6 +510,12 @@ msgid "Can't set CCCD on local Characteristic" msgstr "" #: shared-bindings/displayio/Bitmap.c +msgid "Cannot blit: source palette too large." +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize 3.c +#: shared-bindings/memorymonitor/AllocationSize 4.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c msgid "Cannot delete values" @@ -1014,6 +1039,7 @@ msgstr "" #: ports/atmel-samd/common-hal/busio/I2C.c #: ports/atmel-samd/common-hal/busio/SPI.c #: ports/atmel-samd/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/i2cperipheral/I2CPeripheral 2.c #: ports/atmel-samd/common-hal/i2cperipheral/I2CPeripheral.c #: ports/cxd56/common-hal/busio/I2C.c ports/cxd56/common-hal/busio/SPI.c #: ports/cxd56/common-hal/busio/UART.c ports/cxd56/common-hal/sdioio/SDCard.c @@ -1370,6 +1396,8 @@ msgstr "" msgid "Random number generation error" msgstr "" +#: shared-bindings/memorymonitor/AllocationSize 3.c +#: shared-bindings/memorymonitor/AllocationSize 4.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c msgid "Read-only" @@ -1462,6 +1490,8 @@ msgstr "" #: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c #: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize 3.c +#: shared-bindings/memorymonitor/AllocationSize 4.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c msgid "Slices not supported" @@ -1791,10 +1821,14 @@ msgstr "" msgid "address %08x is not aligned to %d bytes" msgstr "" +#: shared-bindings/i2cperipheral/I2CPeripheral 3.c +#: shared-bindings/i2cperipheral/I2CPeripheral 4.c #: shared-bindings/i2cperipheral/I2CPeripheral.c msgid "address out of bounds" msgstr "" +#: shared-bindings/i2cperipheral/I2CPeripheral 3.c +#: shared-bindings/i2cperipheral/I2CPeripheral 4.c #: shared-bindings/i2cperipheral/I2CPeripheral.c msgid "addresses is empty" msgstr "" @@ -1957,7 +1991,9 @@ msgstr "" msgid "can't assign to expression" msgstr "" -#: py/obj.c py/objint.c shared-bindings/i2cperipheral/I2CPeripheral.c +#: py/obj.c py/objint.c shared-bindings/i2cperipheral/I2CPeripheral 3.c +#: shared-bindings/i2cperipheral/I2CPeripheral 4.c +#: shared-bindings/i2cperipheral/I2CPeripheral.c msgid "can't convert %q to %q" msgstr "" diff --git a/shared-bindings/displayio/Bitmap.c b/shared-bindings/displayio/Bitmap.c index af9f6c3c8..5852f1a70 100644 --- a/shared-bindings/displayio/Bitmap.c +++ b/shared-bindings/displayio/Bitmap.c @@ -172,7 +172,7 @@ STATIC mp_obj_t bitmap_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t val return mp_const_none; } -//| def blit(self, x: int, y: int, source_bitmap: bitmap, x1: int, y1: int, x2: int, y2: int, skip_index: int) -> Any: +//| def blit(self, x: int, y: int, source_bitmap: bitmap, *, x1: int, y1: int, x2: int, y2: int, skip_index: int) -> Any: //| """Inserts the source_bitmap region defined by rectangular boundaries //| (x1,y1) and (x2,y2) into the bitmap at the specified (x,y) location. //| :param int x: Horizontal pixel location in bitmap where source_bitmap upper-left @@ -193,9 +193,9 @@ STATIC mp_obj_t displayio_bitmap_obj_blit(size_t n_args, const mp_obj_t *pos_arg static const mp_arg_t allowed_args[] = { {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT}, {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT}, - {MP_QSTR_source, MP_ARG_REQUIRED | MP_ARG_OBJ}, - {MP_QSTR_x1, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - {MP_QSTR_y1, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + {MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_x1, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = 0} }, + {MP_QSTR_y1, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = 0} }, {MP_QSTR_x2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->width {MP_QSTR_y2, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to source->height {MP_QSTR_skip_index, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj=mp_const_none} }, @@ -203,51 +203,42 @@ STATIC mp_obj_t displayio_bitmap_obj_blit(size_t n_args, const mp_obj_t *pos_arg mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - displayio_bitmap_t *self = MP_OBJ_TO_PTR(pos_args[0]); //******* + displayio_bitmap_t *self = MP_OBJ_TO_PTR(pos_args[0]); int16_t x = args[ARG_x].u_int; int16_t y = args[ARG_y].u_int; displayio_bitmap_t *source = MP_OBJ_TO_PTR(args[ARG_source].u_obj); - int16_t x1, y1; - // if x1 or y1 is None, then set as the zero-point of the bitmap - if ( args[ARG_x1].u_obj == mp_const_none ) { - x1 = 0; - } else { - x1 = mp_obj_get_int(args[ARG_x1].u_obj); - } - //int16_t y1; - if ( args[ARG_y1].u_obj == mp_const_none ) { - y1 = 0; - } else { - y1 = mp_obj_get_int(args[ARG_y1].u_obj); + // ensure that the target bitmap (self) has at least as many `bits_per_value` as the source + if (self->bits_per_value < source->bits_per_value) { + mp_raise_ValueError(translate("Cannot blit: source palette too large.")); } - - int16_t x2, y2; + + int16_t x1, y1, x2, y2; // if x2 or y2 is None, then set as the maximum size of the source bitmap if ( args[ARG_x2].u_obj == mp_const_none ) { - x2 = source->width-1; + x2 = source->width; } else { x2 = mp_obj_get_int(args[ARG_x2].u_obj); } //int16_t y2; if ( args[ARG_y2].u_obj == mp_const_none ) { - y2 = source->height-1; + y2 = source->height; } else { y2 = mp_obj_get_int(args[ARG_y2].u_obj); } // Check x,y are within self (target) bitmap boundary - if ( (x < 0) || (y < 0) || (x >= self->width) || (y >= self->height) ) { + if ( (x < 0) || (y < 0) || (x > self->width) || (y > self->height) ) { mp_raise_ValueError(translate("(x,y): out of range of target bitmap")); } // Check x1,y1,x2,y2 are within source bitmap boundary - if ( (x1 < 0) || (x1 >= source->width) || - (y1 < 0) || (y1 >= source->height) || - (x2 < 0) || (x2 >= source->width) || - (y2 < 0) || (y2 >= source->height) ) { + if ( (x1 < 0) || (x1 > source->width) || + (y1 < 0) || (y1 > source->height) || + (x2 < 0) || (x2 > source->width) || + (y2 < 0) || (y2 > source->height) ) { mp_raise_ValueError(translate("(x1,y1) or (x2,y2): out of range of source bitmap")); } @@ -272,7 +263,7 @@ STATIC mp_obj_t displayio_bitmap_obj_blit(size_t n_args, const mp_obj_t *pos_arg } else { skip_index = mp_obj_get_int(args[ARG_skip_index].u_obj); skip_index_none = false; - } + } common_hal_displayio_bitmap_blit(self, x, y, source, x1, y1, x2, y2, skip_index, skip_index_none); diff --git a/shared-module/displayio/Bitmap.c b/shared-module/displayio/Bitmap.c index dbcba6b58..7de9e9755 100644 --- a/shared-module/displayio/Bitmap.c +++ b/shared-module/displayio/Bitmap.c @@ -118,9 +118,9 @@ void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16 } // simplest version - use internal functions for get/set pixels - for (int16_t i=0; i<= (x2-x1) ; i++) { + for (int16_t i=0; i < (x2-x1) ; i++) { if ( (x+i >= 0) && (x+i < self->width) ) { - for (int16_t j=0; j<= (y2-y1) ; j++){ + for (int16_t j=0; j < (y2-y1) ; j++){ if ((y+j >= 0) && (y+j < self->height) ) { uint32_t value = common_hal_displayio_bitmap_get_pixel(source, x1+i, y1+j); if ( (skip_index_none) || (value != skip_index) ) { // write if skip_value_none is True -- cgit v1.2.3 From b1fce9e933275cd9d945ec46c3ea8eaa350e6a67 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Thu, 13 Aug 2020 19:56:45 -0500 Subject: Deleted trailing whitespace --- shared-bindings/displayio/Bitmap.c | 13 ++++++------- shared-bindings/displayio/Bitmap.h | 4 ++-- shared-module/displayio/Bitmap.c | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Bitmap.c b/shared-bindings/displayio/Bitmap.c index 5852f1a70..9479dc1a5 100644 --- a/shared-bindings/displayio/Bitmap.c +++ b/shared-bindings/displayio/Bitmap.c @@ -184,7 +184,8 @@ STATIC mp_obj_t bitmap_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t val //| : param int y1: Minimum y-value for rectangular bounding box to be copied from the source bitmap //| : param int x2: Maximum x-value for rectangular bounding box to be copied from the source bitmap //| : param int y2: Maximum y-value for rectangular bounding box to be copied from the source bitmap -//| : param int skip_index: bitmap palette index in the source that will not be copied, set `None` to copy all pixels +//| : param int skip_index: bitmap palette index in the source that will not be copied, +//| set `None` to copy all pixels""" //| ... //| @@ -229,19 +230,17 @@ STATIC mp_obj_t displayio_bitmap_obj_blit(size_t n_args, const mp_obj_t *pos_arg y2 = mp_obj_get_int(args[ARG_y2].u_obj); } - // Check x,y are within self (target) bitmap boundary if ( (x < 0) || (y < 0) || (x > self->width) || (y > self->height) ) { mp_raise_ValueError(translate("(x,y): out of range of target bitmap")); } // Check x1,y1,x2,y2 are within source bitmap boundary - if ( (x1 < 0) || (x1 > source->width) || - (y1 < 0) || (y1 > source->height) || + if ( (x1 < 0) || (x1 > source->width) || + (y1 < 0) || (y1 > source->height) || (x2 < 0) || (x2 > source->width) || (y2 < 0) || (y2 > source->height) ) { mp_raise_ValueError(translate("(x1,y1) or (x2,y2): out of range of source bitmap")); } - // Ensure x1 < x2 and y1 < y2 if (x1 > x2) { int16_t temp=x2; @@ -254,7 +253,7 @@ STATIC mp_obj_t displayio_bitmap_obj_blit(size_t n_args, const mp_obj_t *pos_arg y1=temp; } - uint32_t skip_index; + uint32_t skip_index; bool skip_index_none; // flag whether skip_value was None if (args[ARG_skip_index].u_obj == mp_const_none ) { @@ -263,7 +262,7 @@ STATIC mp_obj_t displayio_bitmap_obj_blit(size_t n_args, const mp_obj_t *pos_arg } else { skip_index = mp_obj_get_int(args[ARG_skip_index].u_obj); skip_index_none = false; - } + } common_hal_displayio_bitmap_blit(self, x, y, source, x1, y1, x2, y2, skip_index, skip_index_none); diff --git a/shared-bindings/displayio/Bitmap.h b/shared-bindings/displayio/Bitmap.h index cf75f3d76..00cd98b0a 100644 --- a/shared-bindings/displayio/Bitmap.h +++ b/shared-bindings/displayio/Bitmap.h @@ -40,8 +40,8 @@ uint16_t common_hal_displayio_bitmap_get_height(displayio_bitmap_t *self); uint16_t common_hal_displayio_bitmap_get_width(displayio_bitmap_t *self); uint32_t common_hal_displayio_bitmap_get_bits_per_value(displayio_bitmap_t *self); void common_hal_displayio_bitmap_set_pixel(displayio_bitmap_t *bitmap, int16_t x, int16_t y, uint32_t value); -void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16_t y, displayio_bitmap_t *source, - int16_t x1, int16_t y1, int16_t x2, int16_t y2, +void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16_t y, displayio_bitmap_t *source, + int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint32_t skip_index, bool skip_index_none); uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *bitmap, int16_t x, int16_t y); void common_hal_displayio_bitmap_fill(displayio_bitmap_t *bitmap, uint32_t value); diff --git a/shared-module/displayio/Bitmap.c b/shared-module/displayio/Bitmap.c index 7de9e9755..e581d849d 100644 --- a/shared-module/displayio/Bitmap.c +++ b/shared-module/displayio/Bitmap.c @@ -110,7 +110,7 @@ void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16 // Copy complete "source" bitmap into "self" bitmap at location x,y in the "self" // Add a boolean to determine if all values are copied, or only if non-zero // - // If skip_value is encountered in the source bitmap, it will not be copied. + // If skip_value is encountered in the source bitmap, it will not be copied. // If skip_value is `None`, then all pixels are copied. if (self->read_only) { -- cgit v1.2.3 From ba5dedc1df768bfac05db844f6220c4756c24223 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Thu, 13 Aug 2020 20:57:17 -0500 Subject: deleted whitespace --- shared-module/displayio/Bitmap.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Bitmap.c b/shared-module/displayio/Bitmap.c index e581d849d..b470cecc3 100644 --- a/shared-module/displayio/Bitmap.c +++ b/shared-module/displayio/Bitmap.c @@ -105,11 +105,10 @@ uint32_t common_hal_displayio_bitmap_get_pixel(displayio_bitmap_t *self, int16_t return 0; } -void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16_t y, displayio_bitmap_t *source, - int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint32_t skip_index, bool skip_index_none) { +void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16_t y, displayio_bitmap_t *source, + int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint32_t skip_index, bool skip_index_none) { // Copy complete "source" bitmap into "self" bitmap at location x,y in the "self" // Add a boolean to determine if all values are copied, or only if non-zero - // // If skip_value is encountered in the source bitmap, it will not be copied. // If skip_value is `None`, then all pixels are copied. -- cgit v1.2.3 From fc1347ac2a0b467c1cbd9ac4a8ecf117bcdbb96a Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Thu, 13 Aug 2020 20:58:29 -0500 Subject: deleted whitespace --- shared-module/displayio/Bitmap.c | 1 - 1 file changed, 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Bitmap.c b/shared-module/displayio/Bitmap.c index b470cecc3..2f87a8944 100644 --- a/shared-module/displayio/Bitmap.c +++ b/shared-module/displayio/Bitmap.c @@ -129,7 +129,6 @@ void common_hal_displayio_bitmap_blit(displayio_bitmap_t *self, int16_t x, int16 } } } - } -- cgit v1.2.3 From 1ccd2e234f336872b646ba978ac139dcdc7dc84f Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Aug 2020 10:48:23 -0500 Subject: allocate_display_bus: fix bug where in-use bus would be returned --- shared-module/displayio/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 5afcba35e..8049be5b4 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -398,7 +398,7 @@ primary_display_t *allocate_display_or_raise(void) { } primary_display_t *allocate_display_bus(void) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - mp_const_obj_t display_type = displays[i].display.base.type; + mp_const_obj_t display_type = displays[i].bus_base.type; if (display_type == NULL || display_type == &mp_type_NoneType) { return &displays[i]; } -- cgit v1.2.3 From 6425a411ca7e53b8cdc6c8399c6cd717f39e25fe Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Aug 2020 21:07:24 -0500 Subject: Update shared-module/displayio/__init__.c Co-authored-by: Scott Shawcroft --- shared-module/displayio/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 8049be5b4..73626ce15 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -398,7 +398,7 @@ primary_display_t *allocate_display_or_raise(void) { } primary_display_t *allocate_display_bus(void) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - mp_const_obj_t display_type = displays[i].bus_base.type; + mp_const_obj_t display_bus_type = displays[i].bus_base.type; if (display_type == NULL || display_type == &mp_type_NoneType) { return &displays[i]; } -- cgit v1.2.3 From 6d2d36db3d161fefadd52cc1f2d5a9da99bb2dc9 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 17 Aug 2020 21:09:21 -0500 Subject: Finish implementing scott's suggestion --- shared-module/displayio/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 73626ce15..295af3e7c 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -399,7 +399,7 @@ primary_display_t *allocate_display_or_raise(void) { primary_display_t *allocate_display_bus(void) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { mp_const_obj_t display_bus_type = displays[i].bus_base.type; - if (display_type == NULL || display_type == &mp_type_NoneType) { + if (display_bus_type == NULL || display_bus_type == &mp_type_NoneType) { return &displays[i]; } } -- cgit v1.2.3 From b542c1486fd16636c697f5e295413e4895302165 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 18 Aug 2020 09:31:03 -0500 Subject: reset_board_buses: need to check if sharpdisplay uses SPI bus --- shared-module/board/__init__.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 2c9139d8a..d981aada4 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -39,6 +39,11 @@ #include "shared-module/displayio/__init__.h" #endif +#if CIRCUITPY_SHARPDISPLAY +#include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" +#include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" +#endif + #if BOARD_I2C // Statically allocate the I2C object so it can live past the end of the heap and into the next VM. // That way it can be used by built-in I2CDisplay displays and be accessible through board.I2C(). @@ -148,12 +153,19 @@ void reset_board_busses(void) { bool display_using_spi = false; #if CIRCUITPY_DISPLAYIO for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - if (displays[i].fourwire_bus.bus == spi_singleton) { + mp_const_obj_t bus_type = displays[i].bus_base.type; + if (bus_type == &displayio_fourwire_type && displays[i].fourwire_bus.bus == spi_singleton) { display_using_spi = true; break; } - } + #if CIRCUITPY_SHARPDISPLAY + if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type && displays[i].sharpdisplay.bus == spi_singleton) { + display_using_spi = true; + break; + } + #endif #endif + } if (!display_using_spi) { spi_singleton = NULL; } -- cgit v1.2.3 From 0bec39118f24ca2d6c1dd8df889da5a77e28c52a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 18 Aug 2020 09:31:49 -0500 Subject: displayio: Don't need to specialcase reset of sharpdisplay framebuffer .. for the case where the bus was not in use --- shared-module/displayio/__init__.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 5afcba35e..13c7c231d 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -186,11 +186,7 @@ void reset_displays(void) { #if CIRCUITPY_SHARPDISPLAY } else if (displays[i].bus_base.type == &sharpdisplay_framebuffer_type) { sharpdisplay_framebuffer_obj_t * sharp = &displays[i].sharpdisplay; - if(any_display_uses_this_framebuffer(&sharp->base)) { - common_hal_sharpdisplay_framebuffer_reset(sharp); - } else { - common_hal_sharpdisplay_framebuffer_deinit(sharp); - } + common_hal_sharpdisplay_framebuffer_reset(sharp); #endif } else { // Not an active display bus. -- cgit v1.2.3 From 9e66f71a31644c4c9d4af4e339e4077f4469f9be Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 18 Aug 2020 10:03:45 -0500 Subject: Fix build error for \!DISPLAY --- shared-module/board/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index d981aada4..265c6517f 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -164,8 +164,8 @@ void reset_board_busses(void) { break; } #endif - #endif } + #endif if (!display_using_spi) { spi_singleton = NULL; } -- cgit v1.2.3 From f2f18da1893275a19cda2ad19cb6754527817bf8 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 18 Aug 2020 10:59:55 -0500 Subject: Fix build error for !SHARPDISPLAY --- shared-module/displayio/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 13c7c231d..4a6428ea0 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -26,7 +26,7 @@ primary_display_t displays[CIRCUITPY_DISPLAY_LIMIT]; -#if CIRCUITPY_RGBMATRIX || CIRCUITPY_SHARPDISPLAY +#if CIRCUITPY_RGBMATRIX STATIC bool any_display_uses_this_framebuffer(mp_obj_base_t *obj) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { if (displays[i].display_base.type == &framebufferio_framebufferdisplay_type) { -- cgit v1.2.3 From 6857f984269149b46d1cd4283506420f341b2601 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 18 Aug 2020 13:08:33 -0700 Subject: Split pulseio.PWMOut into pwmio This gives us better granularity when implementing new ports because PWMOut is commonly implemented before PulseIn and PulseOut. Fixes #3211 --- ports/atmel-samd/common-hal/pulseio/PWMOut.c | 489 -------------------- ports/atmel-samd/common-hal/pulseio/PWMOut.h | 44 -- ports/atmel-samd/common-hal/pulseio/PulseOut.c | 2 +- ports/atmel-samd/common-hal/pwmio/PWMOut.c | 489 ++++++++++++++++++++ ports/atmel-samd/common-hal/pwmio/PWMOut.h | 44 ++ ports/atmel-samd/common-hal/pwmio/__init__.c | 1 + ports/atmel-samd/supervisor/port.c | 4 +- ports/cxd56/common-hal/pulseio/PWMOut.c | 159 ------- ports/cxd56/common-hal/pulseio/PWMOut.h | 48 -- ports/cxd56/common-hal/pulseio/PulseOut.c | 2 +- ports/cxd56/common-hal/pwmio/PWMOut.c | 159 +++++++ ports/cxd56/common-hal/pwmio/PWMOut.h | 48 ++ ports/cxd56/common-hal/pwmio/__init__.c | 1 + ports/cxd56/supervisor/port.c | 4 +- ports/esp32s2/common-hal/pulseio/PWMOut.c | 208 --------- ports/esp32s2/common-hal/pulseio/PWMOut.h | 45 -- ports/esp32s2/common-hal/pulseio/PulseOut.c | 4 +- ports/esp32s2/common-hal/pulseio/PulseOut.h | 4 +- ports/esp32s2/common-hal/pwmio/PWMOut.c | 208 +++++++++ ports/esp32s2/common-hal/pwmio/PWMOut.h | 45 ++ ports/esp32s2/common-hal/pwmio/__init__.c | 1 + ports/esp32s2/supervisor/port.c | 4 +- ports/mimxrt10xx/common-hal/pulseio/PWMOut.c | 551 ----------------------- ports/mimxrt10xx/common-hal/pulseio/PWMOut.h | 44 -- ports/mimxrt10xx/common-hal/pulseio/PulseOut.c | 2 +- ports/mimxrt10xx/common-hal/pwmio/PWMOut.c | 551 +++++++++++++++++++++++ ports/mimxrt10xx/common-hal/pwmio/PWMOut.h | 44 ++ ports/mimxrt10xx/common-hal/pwmio/__init__.c | 1 + ports/mimxrt10xx/supervisor/port.c | 4 +- ports/nrf/common-hal/audiopwmio/PWMAudioOut.c | 2 +- ports/nrf/common-hal/pulseio/PWMOut.c | 312 ------------- ports/nrf/common-hal/pulseio/PWMOut.h | 49 -- ports/nrf/common-hal/pulseio/PulseOut.c | 4 +- ports/nrf/common-hal/pulseio/PulseOut.h | 4 +- ports/nrf/common-hal/pwmio/PWMOut.c | 312 +++++++++++++ ports/nrf/common-hal/pwmio/PWMOut.h | 49 ++ ports/nrf/common-hal/pwmio/__init__.c | 1 + ports/nrf/supervisor/port.c | 7 +- ports/stm/common-hal/pulseio/PWMOut.c | 304 ------------- ports/stm/common-hal/pulseio/PWMOut.h | 51 --- ports/stm/common-hal/pulseio/PulseOut.c | 6 +- ports/stm/common-hal/pulseio/PulseOut.h | 4 +- ports/stm/common-hal/pwmio/PWMOut.c | 304 +++++++++++++ ports/stm/common-hal/pwmio/PWMOut.h | 51 +++ ports/stm/common-hal/pwmio/__init__.c | 1 + ports/stm/supervisor/port.c | 14 +- py/circuitpy_defns.mk | 10 +- py/circuitpy_mpconfig.h | 16 +- py/circuitpy_mpconfig.mk | 15 +- shared-bindings/pulseio/PWMOut.c | 245 ---------- shared-bindings/pulseio/PWMOut.h | 58 --- shared-bindings/pulseio/PulseOut.c | 15 +- shared-bindings/pulseio/PulseOut.h | 4 +- shared-bindings/pulseio/__init__.c | 27 +- shared-bindings/pwmio/PWMOut.c | 245 ++++++++++ shared-bindings/pwmio/PWMOut.h | 58 +++ shared-bindings/pwmio/__init__.c | 73 +++ shared-bindings/pwmio/__init__.h | 34 ++ shared-module/displayio/Display.c | 16 +- shared-module/displayio/Display.h | 8 +- shared-module/framebufferio/FramebufferDisplay.h | 1 - 61 files changed, 2823 insertions(+), 2687 deletions(-) delete mode 100644 ports/atmel-samd/common-hal/pulseio/PWMOut.c delete mode 100644 ports/atmel-samd/common-hal/pulseio/PWMOut.h create mode 100644 ports/atmel-samd/common-hal/pwmio/PWMOut.c create mode 100644 ports/atmel-samd/common-hal/pwmio/PWMOut.h create mode 100644 ports/atmel-samd/common-hal/pwmio/__init__.c delete mode 100644 ports/cxd56/common-hal/pulseio/PWMOut.c delete mode 100644 ports/cxd56/common-hal/pulseio/PWMOut.h create mode 100644 ports/cxd56/common-hal/pwmio/PWMOut.c create mode 100644 ports/cxd56/common-hal/pwmio/PWMOut.h create mode 100644 ports/cxd56/common-hal/pwmio/__init__.c delete mode 100644 ports/esp32s2/common-hal/pulseio/PWMOut.c delete mode 100644 ports/esp32s2/common-hal/pulseio/PWMOut.h create mode 100644 ports/esp32s2/common-hal/pwmio/PWMOut.c create mode 100644 ports/esp32s2/common-hal/pwmio/PWMOut.h create mode 100644 ports/esp32s2/common-hal/pwmio/__init__.c delete mode 100644 ports/mimxrt10xx/common-hal/pulseio/PWMOut.c delete mode 100644 ports/mimxrt10xx/common-hal/pulseio/PWMOut.h create mode 100644 ports/mimxrt10xx/common-hal/pwmio/PWMOut.c create mode 100644 ports/mimxrt10xx/common-hal/pwmio/PWMOut.h create mode 100644 ports/mimxrt10xx/common-hal/pwmio/__init__.c delete mode 100644 ports/nrf/common-hal/pulseio/PWMOut.c delete mode 100644 ports/nrf/common-hal/pulseio/PWMOut.h create mode 100644 ports/nrf/common-hal/pwmio/PWMOut.c create mode 100644 ports/nrf/common-hal/pwmio/PWMOut.h create mode 100644 ports/nrf/common-hal/pwmio/__init__.c delete mode 100644 ports/stm/common-hal/pulseio/PWMOut.c delete mode 100644 ports/stm/common-hal/pulseio/PWMOut.h create mode 100644 ports/stm/common-hal/pwmio/PWMOut.c create mode 100644 ports/stm/common-hal/pwmio/PWMOut.h create mode 100644 ports/stm/common-hal/pwmio/__init__.c delete mode 100644 shared-bindings/pulseio/PWMOut.c delete mode 100644 shared-bindings/pulseio/PWMOut.h create mode 100644 shared-bindings/pwmio/PWMOut.c create mode 100644 shared-bindings/pwmio/PWMOut.h create mode 100644 shared-bindings/pwmio/__init__.c create mode 100644 shared-bindings/pwmio/__init__.h (limited to 'shared-module') diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.c b/ports/atmel-samd/common-hal/pulseio/PWMOut.c deleted file mode 100644 index e33437dad..000000000 --- a/ports/atmel-samd/common-hal/pulseio/PWMOut.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries - * SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George - * - * 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 - -#include "py/runtime.h" -#include "common-hal/pulseio/PWMOut.h" -#include "shared-bindings/pulseio/PWMOut.h" -#include "shared-bindings/microcontroller/Processor.h" -#include "timer_handler.h" - -#include "atmel_start_pins.h" -#include "hal/utils/include/utils_repeat_macro.h" -#include "samd/timers.h" -#include "supervisor/shared/translate.h" - -#include "samd/pins.h" - -#undef ENABLE - -# define _TCC_SIZE(unused, n) TCC ## n ## _SIZE, -# define TCC_SIZES { REPEAT_MACRO(_TCC_SIZE, 0, TCC_INST_NUM) } - -static uint32_t tcc_periods[TCC_INST_NUM]; -static uint32_t tc_periods[TC_INST_NUM]; - -uint32_t target_tcc_frequencies[TCC_INST_NUM]; -uint8_t tcc_refcount[TCC_INST_NUM]; - -// This bitmask keeps track of which channels of a TCC are currently claimed. -#ifdef SAMD21 -uint8_t tcc_channels[3]; // Set by pwmout_reset() to {0xf0, 0xfc, 0xfc} initially. -#endif -#ifdef SAM_D5X_E5X -uint8_t tcc_channels[5]; // Set by pwmout_reset() to {0xc0, 0xf0, 0xf8, 0xfc, 0xfc} initially. -#endif - -static uint8_t never_reset_tc_or_tcc[TC_INST_NUM + TCC_INST_NUM]; - -STATIC void timer_refcount(int index, bool is_tc, int increment) { - if (is_tc) { - never_reset_tc_or_tcc[index] += increment; - } else { - never_reset_tc_or_tcc[TC_INST_NUM + index] += increment; - } -} - -void timer_never_reset(int index, bool is_tc) { - timer_refcount(index, is_tc, 1); -} - -void timer_reset_ok(int index, bool is_tc) { - timer_refcount(index, is_tc, -1); -} - - -void common_hal_pulseio_pwmout_never_reset(pulseio_pwmout_obj_t *self) { - timer_never_reset(self->timer->index, self->timer->is_tc); - - never_reset_pin_number(self->pin->number); -} - -void common_hal_pulseio_pwmout_reset_ok(pulseio_pwmout_obj_t *self) { - timer_reset_ok(self->timer->index, self->timer->is_tc); -} - -void pwmout_reset(void) { - // Reset all timers - for (int i = 0; i < TCC_INST_NUM; i++) { - target_tcc_frequencies[i] = 0; - tcc_refcount[i] = 0; - } - Tcc *tccs[TCC_INST_NUM] = TCC_INSTS; - for (int i = 0; i < TCC_INST_NUM; i++) { - if (never_reset_tc_or_tcc[TC_INST_NUM + i] > 0) { - continue; - } - // Disable the module before resetting it. - if (tccs[i]->CTRLA.bit.ENABLE == 1) { - tccs[i]->CTRLA.bit.ENABLE = 0; - while (tccs[i]->SYNCBUSY.bit.ENABLE == 1) { - } - } - uint8_t mask = 0xff; - for (uint8_t j = 0; j < tcc_cc_num[i]; j++) { - mask <<= 1; - } - tcc_channels[i] = mask; - tccs[i]->CTRLA.bit.SWRST = 1; - while (tccs[i]->CTRLA.bit.SWRST == 1) { - } - } - Tc *tcs[TC_INST_NUM] = TC_INSTS; - for (int i = 0; i < TC_INST_NUM; i++) { - if (never_reset_tc_or_tcc[i] > 0) { - continue; - } - tcs[i]->COUNT16.CTRLA.bit.SWRST = 1; - while (tcs[i]->COUNT16.CTRLA.bit.SWRST == 1) { - } - } -} - -static uint8_t tcc_channel(const pin_timer_t* t) { - // For the SAMD51 this hardcodes the use of OTMX == 0x0, the output matrix mapping, which uses - // SAMD21-style modulo mapping. - return t->wave_output % tcc_cc_num[t->index]; -} - -bool channel_ok(const pin_timer_t* t) { - uint8_t channel_bit = 1 << tcc_channel(t); - return (!t->is_tc && ((tcc_channels[t->index] & channel_bit) == 0)) || - t->is_tc; -} - -pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, - const mcu_pin_obj_t* pin, - uint16_t duty, - uint32_t frequency, - bool variable_frequency) { - self->pin = pin; - self->variable_frequency = variable_frequency; - self->duty_cycle = duty; - - if (pin->timer[0].index >= TC_INST_NUM && - pin->timer[1].index >= TCC_INST_NUM -#ifdef SAM_D5X_E5X - && pin->timer[2].index >= TCC_INST_NUM -#endif - ) { - return PWMOUT_INVALID_PIN; - } - - if (frequency == 0 || frequency > 6000000) { - return PWMOUT_INVALID_FREQUENCY; - } - - // Figure out which timer we are using. - - // First see if a tcc is already going with the frequency we want and our - // channel is unused. tc's don't have enough channels to share. - const pin_timer_t* timer = NULL; - uint8_t mux_position = 0; - if (!variable_frequency) { - for (uint8_t i = 0; i < TCC_INST_NUM && timer == NULL; i++) { - if (target_tcc_frequencies[i] != frequency) { - continue; - } - for (uint8_t j = 0; j < NUM_TIMERS_PER_PIN && timer == NULL; j++) { - const pin_timer_t* t = &pin->timer[j]; - if (t->index != i || t->is_tc || t->index >= TCC_INST_NUM) { - continue; - } - Tcc* tcc = tcc_insts[t->index]; - if (tcc->CTRLA.bit.ENABLE == 1 && channel_ok(t)) { - timer = t; - mux_position = j; - // Claim channel. - tcc_channels[timer->index] |= (1 << tcc_channel(timer)); - tcc_refcount[timer->index]++; - } - } - } - } - - // No existing timer has been found, so find a new one to use and set it up. - if (timer == NULL) { - // By default, with fixed frequency we want to share a TCC because its likely we'll have - // other outputs at the same frequency. If the frequency is variable then we'll only have - // one output so we start with the TCs to see if they work. - int8_t direction = -1; - uint8_t start = NUM_TIMERS_PER_PIN - 1; - bool found = false; - if (variable_frequency) { - direction = 1; - start = 0; - } - for (int8_t i = start; i >= 0 && i < NUM_TIMERS_PER_PIN && timer == NULL; i += direction) { - const pin_timer_t* t = &pin->timer[i]; - if ((!t->is_tc && t->index >= TCC_INST_NUM) || - (t->is_tc && t->index >= TC_INST_NUM)) { - continue; - } - if (t->is_tc) { - found = true; - Tc* tc = tc_insts[t->index]; - if (tc->COUNT16.CTRLA.bit.ENABLE == 0 && t->wave_output == 1) { - timer = t; - mux_position = i; - } - } else { - Tcc* tcc = tcc_insts[t->index]; - if (tcc->CTRLA.bit.ENABLE == 0 && channel_ok(t)) { - timer = t; - mux_position = i; - } - } - } - - if (timer == NULL) { - if (found) { - return PWMOUT_ALL_TIMERS_ON_PIN_IN_USE; - } - return PWMOUT_ALL_TIMERS_IN_USE; - } - - uint8_t resolution = 0; - if (timer->is_tc) { - resolution = 16; - } else { - // TCC resolution varies so look it up. - const uint8_t _tcc_sizes[TCC_INST_NUM] = TCC_SIZES; - resolution = _tcc_sizes[timer->index]; - } - // First determine the divisor that gets us the highest resolution. - uint32_t system_clock = common_hal_mcu_processor_get_frequency(); - uint32_t top; - uint8_t divisor; - for (divisor = 0; divisor < 8; divisor++) { - top = (system_clock / prescaler[divisor] / frequency) - 1; - if (top < (1u << resolution)) { - break; - } - } - - set_timer_handler(timer->is_tc, timer->index, TC_HANDLER_NO_INTERRUPT); - // We use the zeroeth clock on either port to go full speed. - turn_on_clocks(timer->is_tc, timer->index, 0); - - if (timer->is_tc) { - tc_periods[timer->index] = top; - Tc* tc = tc_insts[timer->index]; - #ifdef SAMD21 - tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | - TC_CTRLA_PRESCALER(divisor) | - TC_CTRLA_WAVEGEN_MPWM; - tc->COUNT16.CC[0].reg = top; - #endif - #ifdef SAM_D5X_E5X - - tc->COUNT16.CTRLA.bit.SWRST = 1; - while (tc->COUNT16.CTRLA.bit.SWRST == 1) { - } - tc_set_enable(tc, false); - tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_PRESCALER(divisor); - tc->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MPWM; - tc->COUNT16.CCBUF[0].reg = top; - tc->COUNT16.CCBUF[1].reg = 0; - #endif - - tc_set_enable(tc, true); - } else { - tcc_periods[timer->index] = top; - Tcc* tcc = tcc_insts[timer->index]; - tcc_set_enable(tcc, false); - tcc->CTRLA.bit.PRESCALER = divisor; - tcc->PER.bit.PER = top; - tcc->WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val; - tcc_set_enable(tcc, true); - target_tcc_frequencies[timer->index] = frequency; - tcc_refcount[timer->index]++; - if (variable_frequency) { - // We're changing frequency so claim all of the channels. - tcc_channels[timer->index] = 0xff; - } else { - tcc_channels[timer->index] |= (1 << tcc_channel(timer)); - } - } - } - - self->timer = timer; - - gpio_set_pin_function(pin->number, GPIO_PIN_FUNCTION_E + mux_position); - - common_hal_pulseio_pwmout_set_duty_cycle(self, duty); - return PWMOUT_OK; -} - -bool common_hal_pulseio_pwmout_deinited(pulseio_pwmout_obj_t* self) { - return self->pin == NULL; -} - -void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) { - if (common_hal_pulseio_pwmout_deinited(self)) { - return; - } - const pin_timer_t* t = self->timer; - if (t->is_tc) { - Tc* tc = tc_insts[t->index]; - tc_set_enable(tc, false); - tc->COUNT16.CTRLA.bit.SWRST = true; - tc_wait_for_sync(tc); - } else { - tcc_refcount[t->index]--; - tcc_channels[t->index] &= ~(1 << tcc_channel(t)); - if (tcc_refcount[t->index] == 0) { - target_tcc_frequencies[t->index] = 0; - Tcc* tcc = tcc_insts[t->index]; - tcc_set_enable(tcc, false); - tcc->CTRLA.bit.SWRST = true; - while (tcc->SYNCBUSY.bit.SWRST != 0) { - /* Wait for sync */ - } - } - } - reset_pin_number(self->pin->number); - self->pin = NULL; -} - -extern void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, uint16_t duty) { - // Store the unadjusted duty cycle. It turns out the the process of adjusting and calculating - // the duty cycle here and reading it back is lossy - the value will decay over time. - // Track it here so that if frequency is changed we can use this value to recalculate the - // proper duty cycle. - // See https://github.com/adafruit/circuitpython/issues/2086 for more details - self->duty_cycle = duty; - - const pin_timer_t* t = self->timer; - if (t->is_tc) { - uint16_t adjusted_duty = tc_periods[t->index] * duty / 0xffff; - #ifdef SAMD21 - tc_insts[t->index]->COUNT16.CC[t->wave_output].reg = adjusted_duty; - #endif - #ifdef SAM_D5X_E5X - Tc* tc = tc_insts[t->index]; - while (tc->COUNT16.SYNCBUSY.bit.CC1 != 0) {} - tc->COUNT16.CCBUF[1].reg = adjusted_duty; - #endif - } else { - uint32_t adjusted_duty = ((uint64_t) tcc_periods[t->index]) * duty / 0xffff; - uint8_t channel = tcc_channel(t); - Tcc* tcc = tcc_insts[t->index]; - - // Write into the CC buffer register, which will be transferred to the - // CC register on an UPDATE (when period is finished). - // Do clock domain syncing as necessary. - - while (tcc->SYNCBUSY.reg != 0) {} - - // Lock out double-buffering while updating the CCB value. - tcc->CTRLBSET.bit.LUPD = 1; - #ifdef SAMD21 - tcc->CCB[channel].reg = adjusted_duty; - #endif - #ifdef SAM_D5X_E5X - tcc->CCBUF[channel].reg = adjusted_duty; - #endif - tcc->CTRLBCLR.bit.LUPD = 1; - } -} - -uint16_t common_hal_pulseio_pwmout_get_duty_cycle(pulseio_pwmout_obj_t* self) { - const pin_timer_t* t = self->timer; - if (t->is_tc) { - Tc* tc = tc_insts[t->index]; - tc_wait_for_sync(tc); - uint16_t cv = tc->COUNT16.CC[t->wave_output].reg; - return cv * 0xffff / tc_periods[t->index]; - } else { - Tcc* tcc = tcc_insts[t->index]; - uint8_t channel = tcc_channel(t); - uint32_t cv = 0; - - while (tcc->SYNCBUSY.bit.CTRLB) {} - - #ifdef SAMD21 - // If CCBV (CCB valid) is set, the CCB value hasn't yet been copied - // to the CC value. - if ((tcc->STATUS.vec.CCBV & (1 << channel)) != 0) { - cv = tcc->CCB[channel].reg; - } else { - cv = tcc->CC[channel].reg; - } - #endif - #ifdef SAM_D5X_E5X - if ((tcc->STATUS.vec.CCBUFV & (1 << channel)) != 0) { - cv = tcc->CCBUF[channel].reg; - } else { - cv = tcc->CC[channel].reg; - } - #endif - - uint32_t duty_cycle = ((uint64_t) cv) * 0xffff / tcc_periods[t->index]; - - return duty_cycle; - } -} - - -void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self, - uint32_t frequency) { - if (frequency == 0 || frequency > 6000000) { - mp_raise_ValueError(translate("Invalid PWM frequency")); - } - const pin_timer_t* t = self->timer; - uint8_t resolution; - if (t->is_tc) { - resolution = 16; - } else { - resolution = 24; - } - uint32_t system_clock = common_hal_mcu_processor_get_frequency(); - uint32_t new_top; - uint8_t new_divisor; - for (new_divisor = 0; new_divisor < 8; new_divisor++) { - new_top = (system_clock / prescaler[new_divisor] / frequency) - 1; - if (new_top < (1u << resolution)) { - break; - } - } - if (t->is_tc) { - Tc* tc = tc_insts[t->index]; - uint8_t old_divisor = tc->COUNT16.CTRLA.bit.PRESCALER; - if (new_divisor != old_divisor) { - tc_set_enable(tc, false); - tc->COUNT16.CTRLA.bit.PRESCALER = new_divisor; - tc_set_enable(tc, true); - } - tc_periods[t->index] = new_top; - #ifdef SAMD21 - tc->COUNT16.CC[0].reg = new_top; - #endif - #ifdef SAM_D5X_E5X - while (tc->COUNT16.SYNCBUSY.reg != 0) {} - tc->COUNT16.CCBUF[0].reg = new_top; - #endif - } else { - Tcc* tcc = tcc_insts[t->index]; - uint8_t old_divisor = tcc->CTRLA.bit.PRESCALER; - if (new_divisor != old_divisor) { - tcc_set_enable(tcc, false); - tcc->CTRLA.bit.PRESCALER = new_divisor; - tcc_set_enable(tcc, true); - } - while (tcc->SYNCBUSY.reg != 0) {} - tcc_periods[t->index] = new_top; - #ifdef SAMD21 - tcc->PERB.bit.PERB = new_top; - #endif - #ifdef SAM_D5X_E5X - tcc->PERBUF.bit.PERBUF = new_top; - #endif - } - - common_hal_pulseio_pwmout_set_duty_cycle(self, self->duty_cycle); -} - -uint32_t common_hal_pulseio_pwmout_get_frequency(pulseio_pwmout_obj_t* self) { - uint32_t system_clock = common_hal_mcu_processor_get_frequency(); - const pin_timer_t* t = self->timer; - uint8_t divisor; - uint32_t top; - if (t->is_tc) { - divisor = tc_insts[t->index]->COUNT16.CTRLA.bit.PRESCALER; - top = tc_periods[t->index]; - } else { - divisor = tcc_insts[t->index]->CTRLA.bit.PRESCALER; - top = tcc_periods[t->index]; - } - return (system_clock / prescaler[divisor]) / (top + 1); -} - -bool common_hal_pulseio_pwmout_get_variable_frequency(pulseio_pwmout_obj_t* self) { - return self->variable_frequency; -} diff --git a/ports/atmel-samd/common-hal/pulseio/PWMOut.h b/ports/atmel-samd/common-hal/pulseio/PWMOut.h deleted file mode 100644 index 09abda819..000000000 --- a/ports/atmel-samd/common-hal/pulseio/PWMOut.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries - * - * 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_ATMEL_SAMD_COMMON_HAL_PULSEIO_PWMOUT_H -#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PWMOUT_H - -#include "common-hal/microcontroller/Pin.h" - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - const mcu_pin_obj_t *pin; - const pin_timer_t* timer; - bool variable_frequency; - uint16_t duty_cycle; -} pulseio_pwmout_obj_t; - -void pwmout_reset(void); - -#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PULSEIO_PWMOUT_H diff --git a/ports/atmel-samd/common-hal/pulseio/PulseOut.c b/ports/atmel-samd/common-hal/pulseio/PulseOut.c index e9b2137cb..59714f9b5 100644 --- a/ports/atmel-samd/common-hal/pulseio/PulseOut.c +++ b/ports/atmel-samd/common-hal/pulseio/PulseOut.c @@ -96,7 +96,7 @@ void pulseout_reset() { } void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, - const pulseio_pwmout_obj_t* carrier) { + const pwmio_pwmout_obj_t* carrier) { if (refcount == 0) { // Find a spare timer. Tc *tc = NULL; diff --git a/ports/atmel-samd/common-hal/pwmio/PWMOut.c b/ports/atmel-samd/common-hal/pwmio/PWMOut.c new file mode 100644 index 000000000..2e538ccdc --- /dev/null +++ b/ports/atmel-samd/common-hal/pwmio/PWMOut.c @@ -0,0 +1,489 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George + * + * 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 + +#include "py/runtime.h" +#include "common-hal/pwmio/PWMOut.h" +#include "shared-bindings/pwmio/PWMOut.h" +#include "shared-bindings/microcontroller/Processor.h" +#include "timer_handler.h" + +#include "atmel_start_pins.h" +#include "hal/utils/include/utils_repeat_macro.h" +#include "samd/timers.h" +#include "supervisor/shared/translate.h" + +#include "samd/pins.h" + +#undef ENABLE + +# define _TCC_SIZE(unused, n) TCC ## n ## _SIZE, +# define TCC_SIZES { REPEAT_MACRO(_TCC_SIZE, 0, TCC_INST_NUM) } + +static uint32_t tcc_periods[TCC_INST_NUM]; +static uint32_t tc_periods[TC_INST_NUM]; + +uint32_t target_tcc_frequencies[TCC_INST_NUM]; +uint8_t tcc_refcount[TCC_INST_NUM]; + +// This bitmask keeps track of which channels of a TCC are currently claimed. +#ifdef SAMD21 +uint8_t tcc_channels[3]; // Set by pwmout_reset() to {0xf0, 0xfc, 0xfc} initially. +#endif +#ifdef SAM_D5X_E5X +uint8_t tcc_channels[5]; // Set by pwmout_reset() to {0xc0, 0xf0, 0xf8, 0xfc, 0xfc} initially. +#endif + +static uint8_t never_reset_tc_or_tcc[TC_INST_NUM + TCC_INST_NUM]; + +STATIC void timer_refcount(int index, bool is_tc, int increment) { + if (is_tc) { + never_reset_tc_or_tcc[index] += increment; + } else { + never_reset_tc_or_tcc[TC_INST_NUM + index] += increment; + } +} + +void timer_never_reset(int index, bool is_tc) { + timer_refcount(index, is_tc, 1); +} + +void timer_reset_ok(int index, bool is_tc) { + timer_refcount(index, is_tc, -1); +} + + +void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self) { + timer_never_reset(self->timer->index, self->timer->is_tc); + + never_reset_pin_number(self->pin->number); +} + +void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) { + timer_reset_ok(self->timer->index, self->timer->is_tc); +} + +void pwmout_reset(void) { + // Reset all timers + for (int i = 0; i < TCC_INST_NUM; i++) { + target_tcc_frequencies[i] = 0; + tcc_refcount[i] = 0; + } + Tcc *tccs[TCC_INST_NUM] = TCC_INSTS; + for (int i = 0; i < TCC_INST_NUM; i++) { + if (never_reset_tc_or_tcc[TC_INST_NUM + i] > 0) { + continue; + } + // Disable the module before resetting it. + if (tccs[i]->CTRLA.bit.ENABLE == 1) { + tccs[i]->CTRLA.bit.ENABLE = 0; + while (tccs[i]->SYNCBUSY.bit.ENABLE == 1) { + } + } + uint8_t mask = 0xff; + for (uint8_t j = 0; j < tcc_cc_num[i]; j++) { + mask <<= 1; + } + tcc_channels[i] = mask; + tccs[i]->CTRLA.bit.SWRST = 1; + while (tccs[i]->CTRLA.bit.SWRST == 1) { + } + } + Tc *tcs[TC_INST_NUM] = TC_INSTS; + for (int i = 0; i < TC_INST_NUM; i++) { + if (never_reset_tc_or_tcc[i] > 0) { + continue; + } + tcs[i]->COUNT16.CTRLA.bit.SWRST = 1; + while (tcs[i]->COUNT16.CTRLA.bit.SWRST == 1) { + } + } +} + +static uint8_t tcc_channel(const pin_timer_t* t) { + // For the SAMD51 this hardcodes the use of OTMX == 0x0, the output matrix mapping, which uses + // SAMD21-style modulo mapping. + return t->wave_output % tcc_cc_num[t->index]; +} + +bool channel_ok(const pin_timer_t* t) { + uint8_t channel_bit = 1 << tcc_channel(t); + return (!t->is_tc && ((tcc_channels[t->index] & channel_bit) == 0)) || + t->is_tc; +} + +pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t* self, + const mcu_pin_obj_t* pin, + uint16_t duty, + uint32_t frequency, + bool variable_frequency) { + self->pin = pin; + self->variable_frequency = variable_frequency; + self->duty_cycle = duty; + + if (pin->timer[0].index >= TC_INST_NUM && + pin->timer[1].index >= TCC_INST_NUM +#ifdef SAM_D5X_E5X + && pin->timer[2].index >= TCC_INST_NUM +#endif + ) { + return PWMOUT_INVALID_PIN; + } + + if (frequency == 0 || frequency > 6000000) { + return PWMOUT_INVALID_FREQUENCY; + } + + // Figure out which timer we are using. + + // First see if a tcc is already going with the frequency we want and our + // channel is unused. tc's don't have enough channels to share. + const pin_timer_t* timer = NULL; + uint8_t mux_position = 0; + if (!variable_frequency) { + for (uint8_t i = 0; i < TCC_INST_NUM && timer == NULL; i++) { + if (target_tcc_frequencies[i] != frequency) { + continue; + } + for (uint8_t j = 0; j < NUM_TIMERS_PER_PIN && timer == NULL; j++) { + const pin_timer_t* t = &pin->timer[j]; + if (t->index != i || t->is_tc || t->index >= TCC_INST_NUM) { + continue; + } + Tcc* tcc = tcc_insts[t->index]; + if (tcc->CTRLA.bit.ENABLE == 1 && channel_ok(t)) { + timer = t; + mux_position = j; + // Claim channel. + tcc_channels[timer->index] |= (1 << tcc_channel(timer)); + tcc_refcount[timer->index]++; + } + } + } + } + + // No existing timer has been found, so find a new one to use and set it up. + if (timer == NULL) { + // By default, with fixed frequency we want to share a TCC because its likely we'll have + // other outputs at the same frequency. If the frequency is variable then we'll only have + // one output so we start with the TCs to see if they work. + int8_t direction = -1; + uint8_t start = NUM_TIMERS_PER_PIN - 1; + bool found = false; + if (variable_frequency) { + direction = 1; + start = 0; + } + for (int8_t i = start; i >= 0 && i < NUM_TIMERS_PER_PIN && timer == NULL; i += direction) { + const pin_timer_t* t = &pin->timer[i]; + if ((!t->is_tc && t->index >= TCC_INST_NUM) || + (t->is_tc && t->index >= TC_INST_NUM)) { + continue; + } + if (t->is_tc) { + found = true; + Tc* tc = tc_insts[t->index]; + if (tc->COUNT16.CTRLA.bit.ENABLE == 0 && t->wave_output == 1) { + timer = t; + mux_position = i; + } + } else { + Tcc* tcc = tcc_insts[t->index]; + if (tcc->CTRLA.bit.ENABLE == 0 && channel_ok(t)) { + timer = t; + mux_position = i; + } + } + } + + if (timer == NULL) { + if (found) { + return PWMOUT_ALL_TIMERS_ON_PIN_IN_USE; + } + return PWMOUT_ALL_TIMERS_IN_USE; + } + + uint8_t resolution = 0; + if (timer->is_tc) { + resolution = 16; + } else { + // TCC resolution varies so look it up. + const uint8_t _tcc_sizes[TCC_INST_NUM] = TCC_SIZES; + resolution = _tcc_sizes[timer->index]; + } + // First determine the divisor that gets us the highest resolution. + uint32_t system_clock = common_hal_mcu_processor_get_frequency(); + uint32_t top; + uint8_t divisor; + for (divisor = 0; divisor < 8; divisor++) { + top = (system_clock / prescaler[divisor] / frequency) - 1; + if (top < (1u << resolution)) { + break; + } + } + + set_timer_handler(timer->is_tc, timer->index, TC_HANDLER_NO_INTERRUPT); + // We use the zeroeth clock on either port to go full speed. + turn_on_clocks(timer->is_tc, timer->index, 0); + + if (timer->is_tc) { + tc_periods[timer->index] = top; + Tc* tc = tc_insts[timer->index]; + #ifdef SAMD21 + tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | + TC_CTRLA_PRESCALER(divisor) | + TC_CTRLA_WAVEGEN_MPWM; + tc->COUNT16.CC[0].reg = top; + #endif + #ifdef SAM_D5X_E5X + + tc->COUNT16.CTRLA.bit.SWRST = 1; + while (tc->COUNT16.CTRLA.bit.SWRST == 1) { + } + tc_set_enable(tc, false); + tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_PRESCALER(divisor); + tc->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MPWM; + tc->COUNT16.CCBUF[0].reg = top; + tc->COUNT16.CCBUF[1].reg = 0; + #endif + + tc_set_enable(tc, true); + } else { + tcc_periods[timer->index] = top; + Tcc* tcc = tcc_insts[timer->index]; + tcc_set_enable(tcc, false); + tcc->CTRLA.bit.PRESCALER = divisor; + tcc->PER.bit.PER = top; + tcc->WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val; + tcc_set_enable(tcc, true); + target_tcc_frequencies[timer->index] = frequency; + tcc_refcount[timer->index]++; + if (variable_frequency) { + // We're changing frequency so claim all of the channels. + tcc_channels[timer->index] = 0xff; + } else { + tcc_channels[timer->index] |= (1 << tcc_channel(timer)); + } + } + } + + self->timer = timer; + + gpio_set_pin_function(pin->number, GPIO_PIN_FUNCTION_E + mux_position); + + common_hal_pwmio_pwmout_set_duty_cycle(self, duty); + return PWMOUT_OK; +} + +bool common_hal_pwmio_pwmout_deinited(pwmio_pwmout_obj_t* self) { + return self->pin == NULL; +} + +void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t* self) { + if (common_hal_pwmio_pwmout_deinited(self)) { + return; + } + const pin_timer_t* t = self->timer; + if (t->is_tc) { + Tc* tc = tc_insts[t->index]; + tc_set_enable(tc, false); + tc->COUNT16.CTRLA.bit.SWRST = true; + tc_wait_for_sync(tc); + } else { + tcc_refcount[t->index]--; + tcc_channels[t->index] &= ~(1 << tcc_channel(t)); + if (tcc_refcount[t->index] == 0) { + target_tcc_frequencies[t->index] = 0; + Tcc* tcc = tcc_insts[t->index]; + tcc_set_enable(tcc, false); + tcc->CTRLA.bit.SWRST = true; + while (tcc->SYNCBUSY.bit.SWRST != 0) { + /* Wait for sync */ + } + } + } + reset_pin_number(self->pin->number); + self->pin = NULL; +} + +extern void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t* self, uint16_t duty) { + // Store the unadjusted duty cycle. It turns out the the process of adjusting and calculating + // the duty cycle here and reading it back is lossy - the value will decay over time. + // Track it here so that if frequency is changed we can use this value to recalculate the + // proper duty cycle. + // See https://github.com/adafruit/circuitpython/issues/2086 for more details + self->duty_cycle = duty; + + const pin_timer_t* t = self->timer; + if (t->is_tc) { + uint16_t adjusted_duty = tc_periods[t->index] * duty / 0xffff; + #ifdef SAMD21 + tc_insts[t->index]->COUNT16.CC[t->wave_output].reg = adjusted_duty; + #endif + #ifdef SAM_D5X_E5X + Tc* tc = tc_insts[t->index]; + while (tc->COUNT16.SYNCBUSY.bit.CC1 != 0) {} + tc->COUNT16.CCBUF[1].reg = adjusted_duty; + #endif + } else { + uint32_t adjusted_duty = ((uint64_t) tcc_periods[t->index]) * duty / 0xffff; + uint8_t channel = tcc_channel(t); + Tcc* tcc = tcc_insts[t->index]; + + // Write into the CC buffer register, which will be transferred to the + // CC register on an UPDATE (when period is finished). + // Do clock domain syncing as necessary. + + while (tcc->SYNCBUSY.reg != 0) {} + + // Lock out double-buffering while updating the CCB value. + tcc->CTRLBSET.bit.LUPD = 1; + #ifdef SAMD21 + tcc->CCB[channel].reg = adjusted_duty; + #endif + #ifdef SAM_D5X_E5X + tcc->CCBUF[channel].reg = adjusted_duty; + #endif + tcc->CTRLBCLR.bit.LUPD = 1; + } +} + +uint16_t common_hal_pwmio_pwmout_get_duty_cycle(pwmio_pwmout_obj_t* self) { + const pin_timer_t* t = self->timer; + if (t->is_tc) { + Tc* tc = tc_insts[t->index]; + tc_wait_for_sync(tc); + uint16_t cv = tc->COUNT16.CC[t->wave_output].reg; + return cv * 0xffff / tc_periods[t->index]; + } else { + Tcc* tcc = tcc_insts[t->index]; + uint8_t channel = tcc_channel(t); + uint32_t cv = 0; + + while (tcc->SYNCBUSY.bit.CTRLB) {} + + #ifdef SAMD21 + // If CCBV (CCB valid) is set, the CCB value hasn't yet been copied + // to the CC value. + if ((tcc->STATUS.vec.CCBV & (1 << channel)) != 0) { + cv = tcc->CCB[channel].reg; + } else { + cv = tcc->CC[channel].reg; + } + #endif + #ifdef SAM_D5X_E5X + if ((tcc->STATUS.vec.CCBUFV & (1 << channel)) != 0) { + cv = tcc->CCBUF[channel].reg; + } else { + cv = tcc->CC[channel].reg; + } + #endif + + uint32_t duty_cycle = ((uint64_t) cv) * 0xffff / tcc_periods[t->index]; + + return duty_cycle; + } +} + + +void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t* self, + uint32_t frequency) { + if (frequency == 0 || frequency > 6000000) { + mp_raise_ValueError(translate("Invalid PWM frequency")); + } + const pin_timer_t* t = self->timer; + uint8_t resolution; + if (t->is_tc) { + resolution = 16; + } else { + resolution = 24; + } + uint32_t system_clock = common_hal_mcu_processor_get_frequency(); + uint32_t new_top; + uint8_t new_divisor; + for (new_divisor = 0; new_divisor < 8; new_divisor++) { + new_top = (system_clock / prescaler[new_divisor] / frequency) - 1; + if (new_top < (1u << resolution)) { + break; + } + } + if (t->is_tc) { + Tc* tc = tc_insts[t->index]; + uint8_t old_divisor = tc->COUNT16.CTRLA.bit.PRESCALER; + if (new_divisor != old_divisor) { + tc_set_enable(tc, false); + tc->COUNT16.CTRLA.bit.PRESCALER = new_divisor; + tc_set_enable(tc, true); + } + tc_periods[t->index] = new_top; + #ifdef SAMD21 + tc->COUNT16.CC[0].reg = new_top; + #endif + #ifdef SAM_D5X_E5X + while (tc->COUNT16.SYNCBUSY.reg != 0) {} + tc->COUNT16.CCBUF[0].reg = new_top; + #endif + } else { + Tcc* tcc = tcc_insts[t->index]; + uint8_t old_divisor = tcc->CTRLA.bit.PRESCALER; + if (new_divisor != old_divisor) { + tcc_set_enable(tcc, false); + tcc->CTRLA.bit.PRESCALER = new_divisor; + tcc_set_enable(tcc, true); + } + while (tcc->SYNCBUSY.reg != 0) {} + tcc_periods[t->index] = new_top; + #ifdef SAMD21 + tcc->PERB.bit.PERB = new_top; + #endif + #ifdef SAM_D5X_E5X + tcc->PERBUF.bit.PERBUF = new_top; + #endif + } + + common_hal_pwmio_pwmout_set_duty_cycle(self, self->duty_cycle); +} + +uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t* self) { + uint32_t system_clock = common_hal_mcu_processor_get_frequency(); + const pin_timer_t* t = self->timer; + uint8_t divisor; + uint32_t top; + if (t->is_tc) { + divisor = tc_insts[t->index]->COUNT16.CTRLA.bit.PRESCALER; + top = tc_periods[t->index]; + } else { + divisor = tcc_insts[t->index]->CTRLA.bit.PRESCALER; + top = tcc_periods[t->index]; + } + return (system_clock / prescaler[divisor]) / (top + 1); +} + +bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t* self) { + return self->variable_frequency; +} diff --git a/ports/atmel-samd/common-hal/pwmio/PWMOut.h b/ports/atmel-samd/common-hal/pwmio/PWMOut.h new file mode 100644 index 000000000..1f5e62bae --- /dev/null +++ b/ports/atmel-samd/common-hal/pwmio/PWMOut.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * 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_ATMEL_SAMD_COMMON_HAL_PWMIO_PWMOUT_H +#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PWMIO_PWMOUT_H + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + const mcu_pin_obj_t *pin; + const pin_timer_t* timer; + bool variable_frequency; + uint16_t duty_cycle; +} pwmio_pwmout_obj_t; + +void pwmout_reset(void); + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_PWMIO_PWMOUT_H diff --git a/ports/atmel-samd/common-hal/pwmio/__init__.c b/ports/atmel-samd/common-hal/pwmio/__init__.c new file mode 100644 index 000000000..9e551a107 --- /dev/null +++ b/ports/atmel-samd/common-hal/pwmio/__init__.c @@ -0,0 +1 @@ +// No pwmio module functions. diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 591a85853..6352afb1d 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -59,7 +59,7 @@ #include "common-hal/microcontroller/Pin.h" #include "common-hal/pulseio/PulseIn.h" #include "common-hal/pulseio/PulseOut.h" -#include "common-hal/pulseio/PWMOut.h" +#include "common-hal/pwmio/PWMOut.h" #include "common-hal/ps2io/Ps2.h" #include "common-hal/rtc/RTC.h" @@ -335,6 +335,8 @@ void reset_port(void) { #if CIRCUITPY_PULSEIO pulsein_reset(); pulseout_reset(); +#endif +#if CIRCUITPY_PWMIO pwmout_reset(); #endif diff --git a/ports/cxd56/common-hal/pulseio/PWMOut.c b/ports/cxd56/common-hal/pulseio/PWMOut.c deleted file mode 100644 index 7e0be566b..000000000 --- a/ports/cxd56/common-hal/pulseio/PWMOut.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright 2019 Sony Semiconductor Solutions Corporation - * - * 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 -#include -#include - -#include "py/runtime.h" - -#include "shared-bindings/pulseio/PWMOut.h" - -typedef struct { - const char* devpath; - const mcu_pin_obj_t *pin; - int fd; - bool reset; -} pwmout_dev_t; - -STATIC pwmout_dev_t pwmout_dev[] = { - {"/dev/pwm0", &pin_PWM0, -1, true}, - {"/dev/pwm1", &pin_PWM1, -1, true}, - {"/dev/pwm2", &pin_PWM2, -1, true}, - {"/dev/pwm3", &pin_PWM3, -1, true} -}; - -pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t *self, - const mcu_pin_obj_t *pin, uint16_t duty, uint32_t frequency, - bool variable_frequency) { - self->number = -1; - - for (int i = 0; i < MP_ARRAY_SIZE(pwmout_dev); i++) { - if (pin->number == pwmout_dev[i].pin->number) { - self->number = i; - break; - } - } - - if (self->number < 0) { - return PWMOUT_INVALID_PIN; - } - - if (pwmout_dev[self->number].fd < 0) { - pwmout_dev[self->number].fd = open(pwmout_dev[self->number].devpath, O_RDONLY); - if (pwmout_dev[self->number].fd < 0) { - return PWMOUT_INVALID_PIN; - } - } - - self->info.frequency = frequency; - self->info.duty = duty; - self->variable_frequency = variable_frequency; - - if (ioctl(pwmout_dev[self->number].fd, PWMIOC_SETCHARACTERISTICS, (unsigned long)((uintptr_t)&self->info)) < 0) { - mp_raise_ValueError(translate("Invalid PWM frequency")); - } - ioctl(pwmout_dev[self->number].fd, PWMIOC_START, 0); - - claim_pin(pin); - - self->pin = pin; - - return PWMOUT_OK; -} - -void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t *self) { - if (common_hal_pulseio_pwmout_deinited(self)) { - return; - } - - ioctl(pwmout_dev[self->number].fd, PWMIOC_STOP, 0); - close(pwmout_dev[self->number].fd); - pwmout_dev[self->number].fd = -1; - - reset_pin_number(self->pin->number); - self->pin = NULL; -} - -bool common_hal_pulseio_pwmout_deinited(pulseio_pwmout_obj_t *self) { - return pwmout_dev[self->number].fd < 0; -} - -void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t *self, uint16_t duty) { - self->info.duty = duty; - - ioctl(pwmout_dev[self->number].fd, PWMIOC_SETCHARACTERISTICS, (unsigned long)((uintptr_t)&self->info)); -} - -uint16_t common_hal_pulseio_pwmout_get_duty_cycle(pulseio_pwmout_obj_t *self) { - return self->info.duty; -} - -void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t *self, uint32_t frequency) { - self->info.frequency = frequency; - - if (ioctl(pwmout_dev[self->number].fd, PWMIOC_SETCHARACTERISTICS, (unsigned long)((uintptr_t)&self->info)) < 0) { - mp_raise_ValueError(translate("Invalid PWM frequency")); - } -} - -uint32_t common_hal_pulseio_pwmout_get_frequency(pulseio_pwmout_obj_t *self) { - return self->info.frequency; -} - -bool common_hal_pulseio_pwmout_get_variable_frequency(pulseio_pwmout_obj_t *self) { - return self->variable_frequency; -} - -void common_hal_pulseio_pwmout_never_reset(pulseio_pwmout_obj_t *self) { - never_reset_pin_number(self->pin->number); - - pwmout_dev[self->number].reset = false; -} - -void common_hal_pulseio_pwmout_reset_ok(pulseio_pwmout_obj_t *self) { - pwmout_dev[self->number].reset = true; -} - -void pwmout_reset(void) { - for (int i = 0; i < MP_ARRAY_SIZE(pwmout_dev); i++) { - if (pwmout_dev[i].fd >= 0 && pwmout_dev[i].reset) { - ioctl(pwmout_dev[i].fd, PWMIOC_STOP, 0); - close(pwmout_dev[i].fd); - pwmout_dev[i].fd = -1; - - reset_pin_number(pwmout_dev[i].pin->number); - } - } -} - -void pwmout_start(uint8_t pwm_num) { - ioctl(pwmout_dev[pwm_num].fd, PWMIOC_START, 0); -} - -void pwmout_stop(uint8_t pwm_num) { - ioctl(pwmout_dev[pwm_num].fd, PWMIOC_STOP, 0); -} diff --git a/ports/cxd56/common-hal/pulseio/PWMOut.h b/ports/cxd56/common-hal/pulseio/PWMOut.h deleted file mode 100644 index 694acc4e0..000000000 --- a/ports/cxd56/common-hal/pulseio/PWMOut.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright 2019 Sony Semiconductor Solutions Corporation - * - * 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_CXD56_COMMON_HAL_PULSEIO_PWMOUT_H -#define MICROPY_INCLUDED_CXD56_COMMON_HAL_PULSEIO_PWMOUT_H - -#include - -#include "common-hal/microcontroller/Pin.h" - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - const mcu_pin_obj_t *pin; - struct pwm_info_s info; - bool variable_frequency; - int8_t number; -} pulseio_pwmout_obj_t; - -void pwmout_reset(void); -void pwmout_start(uint8_t pwm_num); -void pwmout_stop(uint8_t pwm_num); - -#endif // MICROPY_INCLUDED_CXD56_COMMON_HAL_PULSEIO_PWMOUT_H diff --git a/ports/cxd56/common-hal/pulseio/PulseOut.c b/ports/cxd56/common-hal/pulseio/PulseOut.c index 21b4c77e5..a0c77b0a3 100644 --- a/ports/cxd56/common-hal/pulseio/PulseOut.c +++ b/ports/cxd56/common-hal/pulseio/PulseOut.c @@ -59,7 +59,7 @@ static bool pulseout_timer_handler(unsigned int *next_interval_us, void *arg) } void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t *self, - const pulseio_pwmout_obj_t *carrier) { + const pwmio_pwmout_obj_t *carrier) { if (pulse_fd < 0) { pulse_fd = open("/dev/timer0", O_RDONLY); } diff --git a/ports/cxd56/common-hal/pwmio/PWMOut.c b/ports/cxd56/common-hal/pwmio/PWMOut.c new file mode 100644 index 000000000..e0eb7abde --- /dev/null +++ b/ports/cxd56/common-hal/pwmio/PWMOut.c @@ -0,0 +1,159 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright 2019 Sony Semiconductor Solutions Corporation + * + * 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 +#include +#include + +#include "py/runtime.h" + +#include "shared-bindings/pwmio/PWMOut.h" + +typedef struct { + const char* devpath; + const mcu_pin_obj_t *pin; + int fd; + bool reset; +} pwmout_dev_t; + +STATIC pwmout_dev_t pwmout_dev[] = { + {"/dev/pwm0", &pin_PWM0, -1, true}, + {"/dev/pwm1", &pin_PWM1, -1, true}, + {"/dev/pwm2", &pin_PWM2, -1, true}, + {"/dev/pwm3", &pin_PWM3, -1, true} +}; + +pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self, + const mcu_pin_obj_t *pin, uint16_t duty, uint32_t frequency, + bool variable_frequency) { + self->number = -1; + + for (int i = 0; i < MP_ARRAY_SIZE(pwmout_dev); i++) { + if (pin->number == pwmout_dev[i].pin->number) { + self->number = i; + break; + } + } + + if (self->number < 0) { + return PWMOUT_INVALID_PIN; + } + + if (pwmout_dev[self->number].fd < 0) { + pwmout_dev[self->number].fd = open(pwmout_dev[self->number].devpath, O_RDONLY); + if (pwmout_dev[self->number].fd < 0) { + return PWMOUT_INVALID_PIN; + } + } + + self->info.frequency = frequency; + self->info.duty = duty; + self->variable_frequency = variable_frequency; + + if (ioctl(pwmout_dev[self->number].fd, PWMIOC_SETCHARACTERISTICS, (unsigned long)((uintptr_t)&self->info)) < 0) { + mp_raise_ValueError(translate("Invalid PWM frequency")); + } + ioctl(pwmout_dev[self->number].fd, PWMIOC_START, 0); + + claim_pin(pin); + + self->pin = pin; + + return PWMOUT_OK; +} + +void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t *self) { + if (common_hal_pwmio_pwmout_deinited(self)) { + return; + } + + ioctl(pwmout_dev[self->number].fd, PWMIOC_STOP, 0); + close(pwmout_dev[self->number].fd); + pwmout_dev[self->number].fd = -1; + + reset_pin_number(self->pin->number); + self->pin = NULL; +} + +bool common_hal_pwmio_pwmout_deinited(pwmio_pwmout_obj_t *self) { + return pwmout_dev[self->number].fd < 0; +} + +void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t *self, uint16_t duty) { + self->info.duty = duty; + + ioctl(pwmout_dev[self->number].fd, PWMIOC_SETCHARACTERISTICS, (unsigned long)((uintptr_t)&self->info)); +} + +uint16_t common_hal_pwmio_pwmout_get_duty_cycle(pwmio_pwmout_obj_t *self) { + return self->info.duty; +} + +void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t *self, uint32_t frequency) { + self->info.frequency = frequency; + + if (ioctl(pwmout_dev[self->number].fd, PWMIOC_SETCHARACTERISTICS, (unsigned long)((uintptr_t)&self->info)) < 0) { + mp_raise_ValueError(translate("Invalid PWM frequency")); + } +} + +uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t *self) { + return self->info.frequency; +} + +bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t *self) { + return self->variable_frequency; +} + +void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self) { + never_reset_pin_number(self->pin->number); + + pwmout_dev[self->number].reset = false; +} + +void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) { + pwmout_dev[self->number].reset = true; +} + +void pwmout_reset(void) { + for (int i = 0; i < MP_ARRAY_SIZE(pwmout_dev); i++) { + if (pwmout_dev[i].fd >= 0 && pwmout_dev[i].reset) { + ioctl(pwmout_dev[i].fd, PWMIOC_STOP, 0); + close(pwmout_dev[i].fd); + pwmout_dev[i].fd = -1; + + reset_pin_number(pwmout_dev[i].pin->number); + } + } +} + +void pwmout_start(uint8_t pwm_num) { + ioctl(pwmout_dev[pwm_num].fd, PWMIOC_START, 0); +} + +void pwmout_stop(uint8_t pwm_num) { + ioctl(pwmout_dev[pwm_num].fd, PWMIOC_STOP, 0); +} diff --git a/ports/cxd56/common-hal/pwmio/PWMOut.h b/ports/cxd56/common-hal/pwmio/PWMOut.h new file mode 100644 index 000000000..d9f3ea389 --- /dev/null +++ b/ports/cxd56/common-hal/pwmio/PWMOut.h @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright 2019 Sony Semiconductor Solutions Corporation + * + * 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_CXD56_COMMON_HAL_PWMIO_PWMOUT_H +#define MICROPY_INCLUDED_CXD56_COMMON_HAL_PWMIO_PWMOUT_H + +#include + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + const mcu_pin_obj_t *pin; + struct pwm_info_s info; + bool variable_frequency; + int8_t number; +} pwmio_pwmout_obj_t; + +void pwmout_reset(void); +void pwmout_start(uint8_t pwm_num); +void pwmout_stop(uint8_t pwm_num); + +#endif // MICROPY_INCLUDED_CXD56_COMMON_HAL_PWMIO_PWMOUT_H diff --git a/ports/cxd56/common-hal/pwmio/__init__.c b/ports/cxd56/common-hal/pwmio/__init__.c new file mode 100644 index 000000000..2bee925bc --- /dev/null +++ b/ports/cxd56/common-hal/pwmio/__init__.c @@ -0,0 +1 @@ +// No pulseio module functions. diff --git a/ports/cxd56/supervisor/port.c b/ports/cxd56/supervisor/port.c index a40d31faf..94eda66dc 100644 --- a/ports/cxd56/supervisor/port.c +++ b/ports/cxd56/supervisor/port.c @@ -41,7 +41,7 @@ #include "common-hal/microcontroller/Pin.h" #include "common-hal/analogio/AnalogIn.h" #include "common-hal/pulseio/PulseOut.h" -#include "common-hal/pulseio/PWMOut.h" +#include "common-hal/pwmio/PWMOut.h" #include "common-hal/busio/UART.h" safe_mode_t port_init(void) { @@ -67,6 +67,8 @@ void reset_port(void) { #endif #if CIRCUITPY_PULSEIO pulseout_reset(); +#endif +#if CIRCUITPY_PWMIO pwmout_reset(); #endif #if CIRCUITPY_BUSIO diff --git a/ports/esp32s2/common-hal/pulseio/PWMOut.c b/ports/esp32s2/common-hal/pulseio/PWMOut.c deleted file mode 100644 index 0ac42852a..000000000 --- a/ports/esp32s2/common-hal/pulseio/PWMOut.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Lucian Copeland for Adafruit Industries - * - * 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 - -#include "common-hal/pulseio/PWMOut.h" -#include "shared-bindings/pulseio/PWMOut.h" -#include "py/runtime.h" -#include "driver/ledc.h" - -#define INDEX_EMPTY 0xFF - -STATIC bool not_first_reset = false; -STATIC uint32_t reserved_timer_freq[LEDC_TIMER_MAX]; -STATIC uint8_t reserved_channels[LEDC_CHANNEL_MAX]; -STATIC bool never_reset_tim[LEDC_TIMER_MAX]; -STATIC bool never_reset_chan[LEDC_CHANNEL_MAX]; - -void pwmout_reset(void) { - for (size_t i = 0; i < LEDC_CHANNEL_MAX; i++ ) { - if (reserved_channels[i] != INDEX_EMPTY && not_first_reset) { - ledc_stop(LEDC_LOW_SPEED_MODE, i, 0); - } - if (!never_reset_chan[i]) { - reserved_channels[i] = INDEX_EMPTY; - } - } - for (size_t i = 0; i < LEDC_TIMER_MAX; i++ ) { - if (reserved_timer_freq[i]) { - ledc_timer_rst(LEDC_LOW_SPEED_MODE, i); - } - if (!never_reset_tim[i]) { - reserved_timer_freq[i] = 0; - } - } - not_first_reset = true; -} - -pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, - const mcu_pin_obj_t* pin, - uint16_t duty, - uint32_t frequency, - bool variable_frequency) { - // Calculate duty cycle - uint32_t duty_bits = 0; - uint32_t interval = LEDC_APB_CLK_HZ/frequency; - for (size_t i = 0; i < 32; i++) { - if(!(interval >> i)) { - duty_bits = i - 1; - break; - } - } - if (duty_bits < 1) { - mp_raise_ValueError(translate("Invalid frequency")); - } else if (duty_bits >= LEDC_TIMER_14_BIT) { - duty_bits = LEDC_TIMER_13_BIT; - } - - // Find a viable timer - size_t timer_index = INDEX_EMPTY; - size_t channel_index = INDEX_EMPTY; - for (size_t i = 0; i < LEDC_TIMER_MAX; i++) { - if ((reserved_timer_freq[i] == frequency) && !variable_frequency) { - //prioritize matched frequencies so we don't needlessly take slots - timer_index = i; - break; - } else if (reserved_timer_freq[i] == 0) { - timer_index = i; - break; - } - } - if (timer_index == INDEX_EMPTY) { - // Running out of timers isn't pin related on ESP32S2 so we can't re-use error messages - mp_raise_ValueError(translate("No more timers available")); - } - - // Find a viable channel - for (size_t i = 0; i < LEDC_CHANNEL_MAX; i++) { - if (reserved_channels[i] == INDEX_EMPTY) { - channel_index = i; - break; - } - } - if (channel_index == INDEX_EMPTY) { - mp_raise_ValueError(translate("No more channels available")); - } - - // Run configuration - self->tim_handle.timer_num = timer_index; - self->tim_handle.duty_resolution = duty_bits; - self->tim_handle.freq_hz = frequency; - self->tim_handle.speed_mode = LEDC_LOW_SPEED_MODE; - self->tim_handle.clk_cfg = LEDC_AUTO_CLK; - - if (ledc_timer_config(&(self->tim_handle)) != ESP_OK) { - mp_raise_ValueError(translate("Could not initialize timer")); - } - - self->chan_handle.channel = channel_index; - self->chan_handle.duty = duty >> (16 - duty_bits); - self->chan_handle.gpio_num = pin->number; - self->chan_handle.speed_mode = LEDC_LOW_SPEED_MODE; // Only LS is allowed on ESP32-S2 - self->chan_handle.hpoint = 0; - self->chan_handle.timer_sel = timer_index; - - if (ledc_channel_config(&(self->chan_handle))) { - mp_raise_ValueError(translate("Could not initialize channel")); - } - - // Make reservations - reserved_timer_freq[timer_index] = frequency; - reserved_channels[channel_index] = timer_index; - - self->variable_frequency = variable_frequency; - self->pin_number = pin->number; - self->deinited = false; - self->duty_resolution = duty_bits; - claim_pin(pin); - - // Set initial duty - common_hal_pulseio_pwmout_set_duty_cycle(self, duty); - - return PWMOUT_OK; -} - -void common_hal_pulseio_pwmout_never_reset(pulseio_pwmout_obj_t *self) { - never_reset_tim[self->tim_handle.timer_num] = true; - never_reset_chan[self->chan_handle.channel] = true; -} - -void common_hal_pulseio_pwmout_reset_ok(pulseio_pwmout_obj_t *self) { - never_reset_tim[self->tim_handle.timer_num] = false; - never_reset_chan[self->chan_handle.channel] = false; -} - -bool common_hal_pulseio_pwmout_deinited(pulseio_pwmout_obj_t* self) { - return self->deinited == true; -} - -void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) { - if (common_hal_pulseio_pwmout_deinited(self)) { - return; - } - - if (reserved_channels[self->chan_handle.channel] != INDEX_EMPTY) { - ledc_stop(LEDC_LOW_SPEED_MODE, self->chan_handle.channel, 0); - } - // Search if any other channel is using the timer - bool taken = false; - for (size_t i =0; i < LEDC_CHANNEL_MAX; i++) { - if (reserved_channels[i] == self->tim_handle.timer_num) { - taken = true; - } - } - // Variable frequency means there's only one channel on the timer - if (!taken || self->variable_frequency) { - if (reserved_timer_freq[self->tim_handle.timer_num] != 0) { - ledc_timer_rst(LEDC_LOW_SPEED_MODE, self->tim_handle.timer_num); - } - reserved_timer_freq[self->tim_handle.timer_num] = 0; - } - reset_pin_number(self->pin_number); - reserved_channels[self->chan_handle.channel] = INDEX_EMPTY; - self->deinited = true; -} - -void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, uint16_t duty) { - ledc_set_duty(LEDC_LOW_SPEED_MODE, self->chan_handle.channel, duty >> (16 - self->duty_resolution)); - ledc_update_duty(LEDC_LOW_SPEED_MODE, self->chan_handle.channel); -} - -uint16_t common_hal_pulseio_pwmout_get_duty_cycle(pulseio_pwmout_obj_t* self) { - return ledc_get_duty(LEDC_LOW_SPEED_MODE, self->chan_handle.channel) << (16 - self->duty_resolution); -} - -void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self, uint32_t frequency) { - ledc_set_freq(LEDC_LOW_SPEED_MODE, self->tim_handle.timer_num, frequency); -} - -uint32_t common_hal_pulseio_pwmout_get_frequency(pulseio_pwmout_obj_t* self) { - return ledc_get_freq(LEDC_LOW_SPEED_MODE, self->tim_handle.timer_num); -} - -bool common_hal_pulseio_pwmout_get_variable_frequency(pulseio_pwmout_obj_t* self) { - return self->variable_frequency; -} diff --git a/ports/esp32s2/common-hal/pulseio/PWMOut.h b/ports/esp32s2/common-hal/pulseio/PWMOut.h deleted file mode 100644 index 90a0c3ed9..000000000 --- a/ports/esp32s2/common-hal/pulseio/PWMOut.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Lucian Copeland for Adafruit Industries - * - * 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_ESP32S2_COMMON_HAL_PULSEIO_PWMOUT_H -#define MICROPY_INCLUDED_ESP32S2_COMMON_HAL_PULSEIO_PWMOUT_H - -#include "common-hal/microcontroller/Pin.h" -#include "driver/ledc.h" - -typedef struct { - mp_obj_base_t base; - ledc_timer_config_t tim_handle; - ledc_channel_config_t chan_handle; - uint16_t pin_number; - uint8_t duty_resolution; - bool variable_frequency: 1; - bool deinited: 1; -} pulseio_pwmout_obj_t; - -void pwmout_reset(void); - -#endif // MICROPY_INCLUDED_ESP32S2_COMMON_HAL_PULSEIO_PWMOUT_H diff --git a/ports/esp32s2/common-hal/pulseio/PulseOut.c b/ports/esp32s2/common-hal/pulseio/PulseOut.c index c448c578d..15eab83dd 100644 --- a/ports/esp32s2/common-hal/pulseio/PulseOut.c +++ b/ports/esp32s2/common-hal/pulseio/PulseOut.c @@ -26,7 +26,7 @@ #include "common-hal/pulseio/PulseOut.h" -#include "shared-bindings/pulseio/PWMOut.h" +#include "shared-bindings/pwmio/PWMOut.h" #include "py/runtime.h" // STATIC void turn_on(pulseio_pulseout_obj_t *pulseout) { @@ -45,7 +45,7 @@ void pulseout_reset() { } void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, - const pulseio_pwmout_obj_t* carrier) { + const pwmio_pwmout_obj_t* carrier) { mp_raise_NotImplementedError(translate("PulseOut not supported on this chip")); } diff --git a/ports/esp32s2/common-hal/pulseio/PulseOut.h b/ports/esp32s2/common-hal/pulseio/PulseOut.h index f465d0079..e58bb0457 100644 --- a/ports/esp32s2/common-hal/pulseio/PulseOut.h +++ b/ports/esp32s2/common-hal/pulseio/PulseOut.h @@ -28,13 +28,13 @@ #define MICROPY_INCLUDED_ESP32S2_COMMON_HAL_PULSEIO_PULSEOUT_H #include "common-hal/microcontroller/Pin.h" -#include "common-hal/pulseio/PWMOut.h" +#include "common-hal/pwmio/PWMOut.h" #include "py/obj.h" typedef struct { mp_obj_base_t base; - pulseio_pwmout_obj_t *pwmout; + pwmio_pwmout_obj_t *pwmout; } pulseio_pulseout_obj_t; void pulseout_reset(void); diff --git a/ports/esp32s2/common-hal/pwmio/PWMOut.c b/ports/esp32s2/common-hal/pwmio/PWMOut.c new file mode 100644 index 000000000..d745b7789 --- /dev/null +++ b/ports/esp32s2/common-hal/pwmio/PWMOut.c @@ -0,0 +1,208 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Lucian Copeland for Adafruit Industries + * + * 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 + +#include "common-hal/pwmio/PWMOut.h" +#include "shared-bindings/pwmio/PWMOut.h" +#include "py/runtime.h" +#include "driver/ledc.h" + +#define INDEX_EMPTY 0xFF + +STATIC bool not_first_reset = false; +STATIC uint32_t reserved_timer_freq[LEDC_TIMER_MAX]; +STATIC uint8_t reserved_channels[LEDC_CHANNEL_MAX]; +STATIC bool never_reset_tim[LEDC_TIMER_MAX]; +STATIC bool never_reset_chan[LEDC_CHANNEL_MAX]; + +void pwmout_reset(void) { + for (size_t i = 0; i < LEDC_CHANNEL_MAX; i++ ) { + if (reserved_channels[i] != INDEX_EMPTY && not_first_reset) { + ledc_stop(LEDC_LOW_SPEED_MODE, i, 0); + } + if (!never_reset_chan[i]) { + reserved_channels[i] = INDEX_EMPTY; + } + } + for (size_t i = 0; i < LEDC_TIMER_MAX; i++ ) { + if (reserved_timer_freq[i]) { + ledc_timer_rst(LEDC_LOW_SPEED_MODE, i); + } + if (!never_reset_tim[i]) { + reserved_timer_freq[i] = 0; + } + } + not_first_reset = true; +} + +pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t* self, + const mcu_pin_obj_t* pin, + uint16_t duty, + uint32_t frequency, + bool variable_frequency) { + // Calculate duty cycle + uint32_t duty_bits = 0; + uint32_t interval = LEDC_APB_CLK_HZ/frequency; + for (size_t i = 0; i < 32; i++) { + if(!(interval >> i)) { + duty_bits = i - 1; + break; + } + } + if (duty_bits < 1) { + mp_raise_ValueError(translate("Invalid frequency")); + } else if (duty_bits >= LEDC_TIMER_14_BIT) { + duty_bits = LEDC_TIMER_13_BIT; + } + + // Find a viable timer + size_t timer_index = INDEX_EMPTY; + size_t channel_index = INDEX_EMPTY; + for (size_t i = 0; i < LEDC_TIMER_MAX; i++) { + if ((reserved_timer_freq[i] == frequency) && !variable_frequency) { + //prioritize matched frequencies so we don't needlessly take slots + timer_index = i; + break; + } else if (reserved_timer_freq[i] == 0) { + timer_index = i; + break; + } + } + if (timer_index == INDEX_EMPTY) { + // Running out of timers isn't pin related on ESP32S2 so we can't re-use error messages + mp_raise_ValueError(translate("No more timers available")); + } + + // Find a viable channel + for (size_t i = 0; i < LEDC_CHANNEL_MAX; i++) { + if (reserved_channels[i] == INDEX_EMPTY) { + channel_index = i; + break; + } + } + if (channel_index == INDEX_EMPTY) { + mp_raise_ValueError(translate("No more channels available")); + } + + // Run configuration + self->tim_handle.timer_num = timer_index; + self->tim_handle.duty_resolution = duty_bits; + self->tim_handle.freq_hz = frequency; + self->tim_handle.speed_mode = LEDC_LOW_SPEED_MODE; + self->tim_handle.clk_cfg = LEDC_AUTO_CLK; + + if (ledc_timer_config(&(self->tim_handle)) != ESP_OK) { + mp_raise_ValueError(translate("Could not initialize timer")); + } + + self->chan_handle.channel = channel_index; + self->chan_handle.duty = duty >> (16 - duty_bits); + self->chan_handle.gpio_num = pin->number; + self->chan_handle.speed_mode = LEDC_LOW_SPEED_MODE; // Only LS is allowed on ESP32-S2 + self->chan_handle.hpoint = 0; + self->chan_handle.timer_sel = timer_index; + + if (ledc_channel_config(&(self->chan_handle))) { + mp_raise_ValueError(translate("Could not initialize channel")); + } + + // Make reservations + reserved_timer_freq[timer_index] = frequency; + reserved_channels[channel_index] = timer_index; + + self->variable_frequency = variable_frequency; + self->pin_number = pin->number; + self->deinited = false; + self->duty_resolution = duty_bits; + claim_pin(pin); + + // Set initial duty + common_hal_pwmio_pwmout_set_duty_cycle(self, duty); + + return PWMOUT_OK; +} + +void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self) { + never_reset_tim[self->tim_handle.timer_num] = true; + never_reset_chan[self->chan_handle.channel] = true; +} + +void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) { + never_reset_tim[self->tim_handle.timer_num] = false; + never_reset_chan[self->chan_handle.channel] = false; +} + +bool common_hal_pwmio_pwmout_deinited(pwmio_pwmout_obj_t* self) { + return self->deinited == true; +} + +void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t* self) { + if (common_hal_pwmio_pwmout_deinited(self)) { + return; + } + + if (reserved_channels[self->chan_handle.channel] != INDEX_EMPTY) { + ledc_stop(LEDC_LOW_SPEED_MODE, self->chan_handle.channel, 0); + } + // Search if any other channel is using the timer + bool taken = false; + for (size_t i =0; i < LEDC_CHANNEL_MAX; i++) { + if (reserved_channels[i] == self->tim_handle.timer_num) { + taken = true; + } + } + // Variable frequency means there's only one channel on the timer + if (!taken || self->variable_frequency) { + if (reserved_timer_freq[self->tim_handle.timer_num] != 0) { + ledc_timer_rst(LEDC_LOW_SPEED_MODE, self->tim_handle.timer_num); + } + reserved_timer_freq[self->tim_handle.timer_num] = 0; + } + reset_pin_number(self->pin_number); + reserved_channels[self->chan_handle.channel] = INDEX_EMPTY; + self->deinited = true; +} + +void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t* self, uint16_t duty) { + ledc_set_duty(LEDC_LOW_SPEED_MODE, self->chan_handle.channel, duty >> (16 - self->duty_resolution)); + ledc_update_duty(LEDC_LOW_SPEED_MODE, self->chan_handle.channel); +} + +uint16_t common_hal_pwmio_pwmout_get_duty_cycle(pwmio_pwmout_obj_t* self) { + return ledc_get_duty(LEDC_LOW_SPEED_MODE, self->chan_handle.channel) << (16 - self->duty_resolution); +} + +void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t* self, uint32_t frequency) { + ledc_set_freq(LEDC_LOW_SPEED_MODE, self->tim_handle.timer_num, frequency); +} + +uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t* self) { + return ledc_get_freq(LEDC_LOW_SPEED_MODE, self->tim_handle.timer_num); +} + +bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t* self) { + return self->variable_frequency; +} diff --git a/ports/esp32s2/common-hal/pwmio/PWMOut.h b/ports/esp32s2/common-hal/pwmio/PWMOut.h new file mode 100644 index 000000000..c489e5a27 --- /dev/null +++ b/ports/esp32s2/common-hal/pwmio/PWMOut.h @@ -0,0 +1,45 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Lucian Copeland for Adafruit Industries + * + * 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_ESP32S2_COMMON_HAL_PWMIO_PWMOUT_H +#define MICROPY_INCLUDED_ESP32S2_COMMON_HAL_PWMIO_PWMOUT_H + +#include "common-hal/microcontroller/Pin.h" +#include "driver/ledc.h" + +typedef struct { + mp_obj_base_t base; + ledc_timer_config_t tim_handle; + ledc_channel_config_t chan_handle; + uint16_t pin_number; + uint8_t duty_resolution; + bool variable_frequency: 1; + bool deinited: 1; +} pwmio_pwmout_obj_t; + +void pwmout_reset(void); + +#endif // MICROPY_INCLUDED_ESP32S2_COMMON_HAL_PWMIO_PWMOUT_H diff --git a/ports/esp32s2/common-hal/pwmio/__init__.c b/ports/esp32s2/common-hal/pwmio/__init__.c new file mode 100644 index 000000000..2bee925bc --- /dev/null +++ b/ports/esp32s2/common-hal/pwmio/__init__.c @@ -0,0 +1 @@ +// No pulseio module functions. diff --git a/ports/esp32s2/supervisor/port.c b/ports/esp32s2/supervisor/port.c index e4767e514..2f430c7e3 100644 --- a/ports/esp32s2/supervisor/port.c +++ b/ports/esp32s2/supervisor/port.c @@ -38,7 +38,7 @@ #include "common-hal/busio/I2C.h" #include "common-hal/busio/SPI.h" #include "common-hal/busio/UART.h" -#include "common-hal/pulseio/PWMOut.h" +#include "common-hal/pwmio/PWMOut.h" #include "supervisor/memory.h" #include "supervisor/shared/tick.h" @@ -65,7 +65,7 @@ void reset_port(void) { // A larger delay so the idle task can run and do any IDF cleanup needed. vTaskDelay(4); -#if CIRCUITPY_PULSEIO +#if CIRCUITPY_PWMIO pwmout_reset(); #endif #if CIRCUITPY_BUSIO diff --git a/ports/mimxrt10xx/common-hal/pulseio/PWMOut.c b/ports/mimxrt10xx/common-hal/pulseio/PWMOut.c deleted file mode 100644 index 50dd477ea..000000000 --- a/ports/mimxrt10xx/common-hal/pulseio/PWMOut.c +++ /dev/null @@ -1,551 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries - * SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George - * Copyright (c) 2019 Artur Pacholec - * - * 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 - -#include "py/runtime.h" -#include "common-hal/pulseio/PWMOut.h" -#include "shared-bindings/pulseio/PWMOut.h" -#include "shared-bindings/microcontroller/Processor.h" - -#include "fsl_pwm.h" - -#include "supervisor/shared/translate.h" -#include "periph.h" - -#include - -// TODO -//#include "samd/pins.h" - -//#undef ENABLE -// -//# define _TCC_SIZE(unused, n) TCC ## n ## _SIZE, -//# define TCC_SIZES { REPEAT_MACRO(_TCC_SIZE, 0, TCC_INST_NUM) } -// -//static uint32_t tcc_periods[TCC_INST_NUM]; -//static uint32_t tc_periods[TC_INST_NUM]; -// -//uint32_t target_tcc_frequencies[TCC_INST_NUM]; -//uint8_t tcc_refcount[TCC_INST_NUM]; -// -//// This bitmask keeps track of which channels of a TCC are currently claimed. -//#ifdef SAMD21 -//uint8_t tcc_channels[3]; // Set by pwmout_reset() to {0xf0, 0xfc, 0xfc} initially. -//#endif -//#ifdef SAMD51 -//uint8_t tcc_channels[5]; // Set by pwmout_reset() to {0xc0, 0xf0, 0xf8, 0xfc, 0xfc} initially. -//#endif -// -//static uint8_t never_reset_tc_or_tcc[TC_INST_NUM + TCC_INST_NUM]; - -void common_hal_pulseio_pwmout_never_reset(pulseio_pwmout_obj_t *self) { -// if (self->timer->is_tc) { -// never_reset_tc_or_tcc[self->timer->index] += 1; -// } else { -// never_reset_tc_or_tcc[TC_INST_NUM + self->timer->index] += 1; -// } -// -// never_reset_pin_number(self->pin->number); -} - -void common_hal_pulseio_pwmout_reset_ok(pulseio_pwmout_obj_t *self) { -// if (self->timer->is_tc) { -// never_reset_tc_or_tcc[self->timer->index] -= 1; -// } else { -// never_reset_tc_or_tcc[TC_INST_NUM + self->timer->index] -= 1; -// } -} - -void pwmout_reset(void) { -// // Reset all timers -// for (int i = 0; i < TCC_INST_NUM; i++) { -// target_tcc_frequencies[i] = 0; -// tcc_refcount[i] = 0; -// } -// Tcc *tccs[TCC_INST_NUM] = TCC_INSTS; -// for (int i = 0; i < TCC_INST_NUM; i++) { -// if (never_reset_tc_or_tcc[TC_INST_NUM + i] > 0) { -// continue; -// } -// // Disable the module before resetting it. -// if (tccs[i]->CTRLA.bit.ENABLE == 1) { -// tccs[i]->CTRLA.bit.ENABLE = 0; -// while (tccs[i]->SYNCBUSY.bit.ENABLE == 1) { -// } -// } -// uint8_t mask = 0xff; -// for (uint8_t j = 0; j < tcc_cc_num[i]; j++) { -// mask <<= 1; -// } -// tcc_channels[i] = mask; -// tccs[i]->CTRLA.bit.SWRST = 1; -// while (tccs[i]->CTRLA.bit.SWRST == 1) { -// } -// } -// Tc *tcs[TC_INST_NUM] = TC_INSTS; -// for (int i = 0; i < TC_INST_NUM; i++) { -// if (never_reset_tc_or_tcc[i] > 0) { -// continue; -// } -// tcs[i]->COUNT16.CTRLA.bit.SWRST = 1; -// while (tcs[i]->COUNT16.CTRLA.bit.SWRST == 1) { -// } -// } -} - -//static uint8_t tcc_channel(const pin_timer_t* t) { -// // For the SAMD51 this hardcodes the use of OTMX == 0x0, the output matrix mapping, which uses -// // SAMD21-style modulo mapping. -// return t->wave_output % tcc_cc_num[t->index]; -//} - -//bool channel_ok(const pin_timer_t* t) { -// uint8_t channel_bit = 1 << tcc_channel(t); -// return (!t->is_tc && ((tcc_channels[t->index] & channel_bit) == 0)) || -// t->is_tc; -//} - -#define PWM_SRC_CLK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk) - -pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t *self, - const mcu_pin_obj_t *pin, - uint16_t duty, - uint32_t frequency, - bool variable_frequency) { - self->pin = pin; - self->variable_frequency = variable_frequency; - - const uint32_t pwm_count = sizeof(mcu_pwm_list) / sizeof(mcu_pwm_obj_t); - - for (uint32_t i = 0; i < pwm_count; ++i) { - if (mcu_pwm_list[i].pin != pin) - continue; - - printf("pwm: 0x%p, sum %d, chan %d, mux %d\r\n", mcu_pwm_list[i].pwm, mcu_pwm_list[i].submodule, mcu_pwm_list[i].channel, mcu_pwm_list[i].mux_mode); - - self->pwm = &mcu_pwm_list[i]; - - break; - } - - if (self->pwm == NULL) { - return PWMOUT_INVALID_PIN; - } - - CLOCK_SetDiv(kCLOCK_AhbDiv, 0x2); /* Set AHB PODF to 2, divide by 3 */ - CLOCK_SetDiv(kCLOCK_IpgDiv, 0x3); /* Set IPG PODF to 3, divede by 4 */ - -//TODO re-enable -// IOMUXC_SetPinMux( -// IOMUXC_GPIO_SD_02_FLEXPWM1_PWM0_A, /* GPIO_02 is configured as FLEXPWM1_PWM0_A */ -// 0U); /* Software Input On Field: Input Path is determined by functionality */ -// -// IOMUXC_SetPinConfig( -// IOMUXC_GPIO_SD_02_FLEXPWM1_PWM0_A, /* GPIO_02 PAD functional properties : */ -// 0x10A0U); /* Slew Rate Field: Slow Slew Rate -// Drive Strength Field: R0/4 -// Speed Field: fast(150MHz) -// Open Drain Enable Field: Open Drain Disabled -// Pull / Keep Enable Field: Pull/Keeper Enabled -// Pull / Keep Select Field: Keeper -// Pull Up / Down Config. Field: 100K Ohm Pull Down -// Hyst. Enable Field: Hysteresis Disabled */ - - pwm_config_t pwmConfig; - - /* - * pwmConfig.enableDebugMode = false; - * pwmConfig.enableWait = false; - * pwmConfig.reloadSelect = kPWM_LocalReload; - * pwmConfig.faultFilterCount = 0; - * pwmConfig.faultFilterPeriod = 0; - * pwmConfig.clockSource = kPWM_BusClock; - * pwmConfig.prescale = kPWM_Prescale_Divide_1; - * pwmConfig.initializationControl = kPWM_Initialize_LocalSync; - * pwmConfig.forceTrigger = kPWM_Force_Local; - * pwmConfig.reloadFrequency = kPWM_LoadEveryOportunity; - * pwmConfig.reloadLogic = kPWM_ReloadImmediate; - * pwmConfig.pairOperation = kPWM_Independent; - */ - PWM_GetDefaultConfig(&pwmConfig); - - //pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle; - pwmConfig.enableDebugMode = true; - - if (PWM_Init(PWM1, self->pwm->submodule, &pwmConfig) == kStatus_Fail) { - printf("PWM initialization failed\r\n"); - return PWMOUT_INVALID_PIN; - } - - pwm_signal_param_t pwmSignal; - - /* Set deadtime count, we set this to about 650ns */ - uint16_t deadTimeVal = ((uint64_t)PWM_SRC_CLK_FREQ * 650) / 1000000000; - - pwmSignal.pwmChannel = self->pwm->channel; - pwmSignal.level = kPWM_HighTrue; - pwmSignal.dutyCyclePercent = frequency / 2; /* 1 percent dutycycle */ - pwmSignal.deadtimeValue = deadTimeVal; - - PWM_SetupPwm(PWM1, self->pwm->submodule, &pwmSignal, 1, kPWM_SignedCenterAligned, frequency, PWM_SRC_CLK_FREQ); - - PWM_SetPwmLdok(PWM1, kPWM_Control_Module_0 | kPWM_Control_Module_1 | kPWM_Control_Module_2, true); - - PWM_StartTimer(PWM1, kPWM_Control_Module_0 | kPWM_Control_Module_1 | kPWM_Control_Module_2); - -// if (frequency == 0 || frequency > 6000000) { -// return PWMOUT_INVALID_FREQUENCY; -// } - -// // Figure out which timer we are using. -// // First see if a tcc is already going with the frequency we want and our -// // channel is unused. tc's don't have enough channels to share. -// const pin_timer_t* timer = NULL; -// uint8_t mux_position = 0; -// if (!variable_frequency) { -// for (uint8_t i = 0; i < TCC_INST_NUM && timer == NULL; i++) { -// if (target_tcc_frequencies[i] != frequency) { -// continue; -// } -// for (uint8_t j = 0; j < NUM_TIMERS_PER_PIN && timer == NULL; j++) { -// const pin_timer_t* t = &pin->timer[j]; -// if (t->index != i || t->is_tc || t->index >= TCC_INST_NUM) { -// continue; -// } -// Tcc* tcc = tcc_insts[t->index]; -// if (tcc->CTRLA.bit.ENABLE == 1 && channel_ok(t)) { -// timer = t; -// mux_position = j; -// // Claim channel. -// tcc_channels[timer->index] |= (1 << tcc_channel(timer)); -// -// } -// } -// } -// } -// -// // No existing timer has been found, so find a new one to use and set it up. -// if (timer == NULL) { -// // By default, with fixed frequency we want to share a TCC because its likely we'll have -// // other outputs at the same frequency. If the frequency is variable then we'll only have -// // one output so we start with the TCs to see if they work. -// int8_t direction = -1; -// uint8_t start = NUM_TIMERS_PER_PIN - 1; -// bool found = false; -// if (variable_frequency) { -// direction = 1; -// start = 0; -// } -// for (int8_t i = start; i >= 0 && i < NUM_TIMERS_PER_PIN && timer == NULL; i += direction) { -// const pin_timer_t* t = &pin->timer[i]; -// if ((!t->is_tc && t->index >= TCC_INST_NUM) || -// (t->is_tc && t->index >= TC_INST_NUM)) { -// continue; -// } -// if (t->is_tc) { -// found = true; -// Tc* tc = tc_insts[t->index]; -// if (tc->COUNT16.CTRLA.bit.ENABLE == 0 && t->wave_output == 1) { -// timer = t; -// mux_position = i; -// } -// } else { -// Tcc* tcc = tcc_insts[t->index]; -// if (tcc->CTRLA.bit.ENABLE == 0 && channel_ok(t)) { -// timer = t; -// mux_position = i; -// } -// } -// } -// -// if (timer == NULL) { -// if (found) { -// return PWMOUT_ALL_TIMERS_ON_PIN_IN_USE; -// } -// return PWMOUT_ALL_TIMERS_IN_USE; -// } -// -// uint8_t resolution = 0; -// if (timer->is_tc) { -// resolution = 16; -// } else { -// // TCC resolution varies so look it up. -// const uint8_t _tcc_sizes[TCC_INST_NUM] = TCC_SIZES; -// resolution = _tcc_sizes[timer->index]; -// } -// // First determine the divisor that gets us the highest resolution. -// uint32_t system_clock = common_hal_mcu_processor_get_frequency(); -// uint32_t top; -// uint8_t divisor; -// for (divisor = 0; divisor < 8; divisor++) { -// top = (system_clock / prescaler[divisor] / frequency) - 1; -// if (top < (1u << resolution)) { -// break; -// } -// } -// -// set_timer_handler(timer->is_tc, timer->index, TC_HANDLER_NO_INTERRUPT); -// // We use the zeroeth clock on either port to go full speed. -// turn_on_clocks(timer->is_tc, timer->index, 0); -// -// if (timer->is_tc) { -// tc_periods[timer->index] = top; -// Tc* tc = tc_insts[timer->index]; -// #ifdef SAMD21 -// tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | -// TC_CTRLA_PRESCALER(divisor) | -// TC_CTRLA_WAVEGEN_MPWM; -// tc->COUNT16.CC[0].reg = top; -// #endif -// #ifdef SAMD51 -// -// tc->COUNT16.CTRLA.bit.SWRST = 1; -// while (tc->COUNT16.CTRLA.bit.SWRST == 1) { -// } -// tc_set_enable(tc, false); -// tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_PRESCALER(divisor); -// tc->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MPWM; -// tc->COUNT16.CCBUF[0].reg = top; -// tc->COUNT16.CCBUF[1].reg = 0; -// #endif -// -// tc_set_enable(tc, true); -// } else { -// tcc_periods[timer->index] = top; -// Tcc* tcc = tcc_insts[timer->index]; -// tcc_set_enable(tcc, false); -// tcc->CTRLA.bit.PRESCALER = divisor; -// tcc->PER.bit.PER = top; -// tcc->WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val; -// tcc_set_enable(tcc, true); -// target_tcc_frequencies[timer->index] = frequency; -// tcc_refcount[timer->index]++; -// if (variable_frequency) { -// // We're changing frequency so claim all of the channels. -// tcc_channels[timer->index] = 0xff; -// } else { -// tcc_channels[timer->index] |= (1 << tcc_channel(timer)); -// } -// } -// } -// -// self->timer = timer; -// -// gpio_set_pin_function(pin->number, GPIO_PIN_FUNCTION_E + mux_position); - - common_hal_pulseio_pwmout_set_duty_cycle(self, duty); - - return PWMOUT_OK; -} - -bool common_hal_pulseio_pwmout_deinited(pulseio_pwmout_obj_t* self) { - return self->pin == NULL; -} - -void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) { - if (common_hal_pulseio_pwmout_deinited(self)) { - return; - } - -// const pin_timer_t* t = self->timer; -// if (t->is_tc) { -// Tc* tc = tc_insts[t->index]; -// tc_set_enable(tc, false); -// tc->COUNT16.CTRLA.bit.SWRST = true; -// tc_wait_for_sync(tc); -// } else { -// tcc_refcount[t->index]--; -// tcc_channels[t->index] &= ~(1 << tcc_channel(t)); -// if (tcc_refcount[t->index] == 0) { -// target_tcc_frequencies[t->index] = 0; -// Tcc* tcc = tcc_insts[t->index]; -// tcc_set_enable(tcc, false); -// tcc->CTRLA.bit.SWRST = true; -// while (tcc->SYNCBUSY.bit.SWRST != 0) { -// /* Wait for sync */ -// } -// } -// } -// reset_pin_number(self->pin->number); - self->pin = NULL; -} - -void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t *self, uint16_t duty) { - PWM_UpdatePwmDutycycle(PWM1, self->pwm->submodule, self->pwm->channel, kPWM_SignedCenterAligned, duty); - -// const pin_timer_t* t = self->timer; -// if (t->is_tc) { -// uint16_t adjusted_duty = tc_periods[t->index] * duty / 0xffff; -// #ifdef SAMD21 -// tc_insts[t->index]->COUNT16.CC[t->wave_output].reg = adjusted_duty; -// #endif -// #ifdef SAMD51 -// Tc* tc = tc_insts[t->index]; -// while (tc->COUNT16.SYNCBUSY.bit.CC1 != 0) {} -// tc->COUNT16.CCBUF[1].reg = adjusted_duty; -// #endif -// } else { -// uint32_t adjusted_duty = ((uint64_t) tcc_periods[t->index]) * duty / 0xffff; -// uint8_t channel = tcc_channel(t); -// Tcc* tcc = tcc_insts[t->index]; -// -// // Write into the CC buffer register, which will be transferred to the -// // CC register on an UPDATE (when period is finished). -// // Do clock domain syncing as necessary. -// -// while (tcc->SYNCBUSY.reg != 0) {} -// -// // Lock out double-buffering while updating the CCB value. -// tcc->CTRLBSET.bit.LUPD = 1; -// #ifdef SAMD21 -// tcc->CCB[channel].reg = adjusted_duty; -// #endif -// #ifdef SAMD51 -// tcc->CCBUF[channel].reg = adjusted_duty; -// #endif -// tcc->CTRLBCLR.bit.LUPD = 1; -// } -} - -uint16_t common_hal_pulseio_pwmout_get_duty_cycle(pulseio_pwmout_obj_t* self) { - return 0; -// const pin_timer_t* t = self->timer; -// if (t->is_tc) { -// Tc* tc = tc_insts[t->index]; -// tc_wait_for_sync(tc); -// uint16_t cv = tc->COUNT16.CC[t->wave_output].reg; -// return cv * 0xffff / tc_periods[t->index]; -// } else { -// Tcc* tcc = tcc_insts[t->index]; -// uint8_t channel = tcc_channel(t); -// uint32_t cv = 0; -// -// while (tcc->SYNCBUSY.bit.CTRLB) {} -// -// #ifdef SAMD21 -// // If CCBV (CCB valid) is set, the CCB value hasn't yet been copied -// // to the CC value. -// if ((tcc->STATUS.vec.CCBV & (1 << channel)) != 0) { -// cv = tcc->CCB[channel].reg; -// } else { -// cv = tcc->CC[channel].reg; -// } -// #endif -// #ifdef SAMD51 -// if ((tcc->STATUS.vec.CCBUFV & (1 << channel)) != 0) { -// cv = tcc->CCBUF[channel].reg; -// } else { -// cv = tcc->CC[channel].reg; -// } -// #endif -// -// uint32_t duty_cycle = ((uint64_t) cv) * 0xffff / tcc_periods[t->index]; -// -// return duty_cycle; -// } -} - -void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self, - uint32_t frequency) { -// if (frequency == 0 || frequency > 6000000) { -// mp_raise_ValueError(translate("Invalid PWM frequency")); -// } -// const pin_timer_t* t = self->timer; -// uint8_t resolution; -// if (t->is_tc) { -// resolution = 16; -// } else { -// resolution = 24; -// } -// uint32_t system_clock = common_hal_mcu_processor_get_frequency(); -// uint32_t new_top; -// uint8_t new_divisor; -// for (new_divisor = 0; new_divisor < 8; new_divisor++) { -// new_top = (system_clock / prescaler[new_divisor] / frequency) - 1; -// if (new_top < (1u << resolution)) { -// break; -// } -// } -// uint16_t old_duty = common_hal_pulseio_pwmout_get_duty_cycle(self); -// if (t->is_tc) { -// Tc* tc = tc_insts[t->index]; -// uint8_t old_divisor = tc->COUNT16.CTRLA.bit.PRESCALER; -// if (new_divisor != old_divisor) { -// tc_set_enable(tc, false); -// tc->COUNT16.CTRLA.bit.PRESCALER = new_divisor; -// tc_set_enable(tc, true); -// } -// tc_periods[t->index] = new_top; -// #ifdef SAMD21 -// tc->COUNT16.CC[0].reg = new_top; -// #endif -// #ifdef SAMD51 -// while (tc->COUNT16.SYNCBUSY.reg != 0) {} -// tc->COUNT16.CCBUF[0].reg = new_top; -// #endif -// } else { -// Tcc* tcc = tcc_insts[t->index]; -// uint8_t old_divisor = tcc->CTRLA.bit.PRESCALER; -// if (new_divisor != old_divisor) { -// tcc_set_enable(tcc, false); -// tcc->CTRLA.bit.PRESCALER = new_divisor; -// tcc_set_enable(tcc, true); -// } -// while (tcc->SYNCBUSY.reg != 0) {} -// tcc_periods[t->index] = new_top; -// #ifdef SAMD21 -// tcc->PERB.bit.PERB = new_top; -// #endif -// #ifdef SAMD51 -// tcc->PERBUF.bit.PERBUF = new_top; -// #endif -// } - -// common_hal_pulseio_pwmout_set_duty_cycle(self, old_duty); -} - -uint32_t common_hal_pulseio_pwmout_get_frequency(pulseio_pwmout_obj_t* self) { -// uint32_t system_clock = common_hal_mcu_processor_get_frequency(); -// const pin_timer_t* t = self->timer; -// uint8_t divisor; -// uint32_t top; -// if (t->is_tc) { -// divisor = tc_insts[t->index]->COUNT16.CTRLA.bit.PRESCALER; -// top = tc_periods[t->index]; -// } else { -// divisor = tcc_insts[t->index]->CTRLA.bit.PRESCALER; -// top = tcc_periods[t->index]; -// } -// return (system_clock / prescaler[divisor]) / (top + 1); - return 0; -} - -bool common_hal_pulseio_pwmout_get_variable_frequency(pulseio_pwmout_obj_t* self) { - return self->variable_frequency; -} diff --git a/ports/mimxrt10xx/common-hal/pulseio/PWMOut.h b/ports/mimxrt10xx/common-hal/pulseio/PWMOut.h deleted file mode 100644 index 2f0fe94c4..000000000 --- a/ports/mimxrt10xx/common-hal/pulseio/PWMOut.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries - * Copyright (c) 2019 Artur Pacholec - * - * 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_MIMXRT10XX_COMMON_HAL_PULSEIO_PWMOUT_H -#define MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_PULSEIO_PWMOUT_H - -#include "common-hal/microcontroller/Pin.h" -#include "periph.h" -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - const mcu_pin_obj_t *pin; - const mcu_pwm_obj_t *pwm; - bool variable_frequency; -} pulseio_pwmout_obj_t; - -void pwmout_reset(void); - -#endif // MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_PULSEIO_PWMOUT_H diff --git a/ports/mimxrt10xx/common-hal/pulseio/PulseOut.c b/ports/mimxrt10xx/common-hal/pulseio/PulseOut.c index ffa885688..2c27847ed 100644 --- a/ports/mimxrt10xx/common-hal/pulseio/PulseOut.c +++ b/ports/mimxrt10xx/common-hal/pulseio/PulseOut.c @@ -94,7 +94,7 @@ void pulseout_reset() { } void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, - const pulseio_pwmout_obj_t* carrier) { + const pwmio_pwmout_obj_t* carrier) { // if (refcount == 0) { // // Find a spare timer. // Tc *tc = NULL; diff --git a/ports/mimxrt10xx/common-hal/pwmio/PWMOut.c b/ports/mimxrt10xx/common-hal/pwmio/PWMOut.c new file mode 100644 index 000000000..dd464ef84 --- /dev/null +++ b/ports/mimxrt10xx/common-hal/pwmio/PWMOut.c @@ -0,0 +1,551 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George + * Copyright (c) 2019 Artur Pacholec + * + * 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 + +#include "py/runtime.h" +#include "common-hal/pwmio/PWMOut.h" +#include "shared-bindings/pwmio/PWMOut.h" +#include "shared-bindings/microcontroller/Processor.h" + +#include "fsl_pwm.h" + +#include "supervisor/shared/translate.h" +#include "periph.h" + +#include + +// TODO +//#include "samd/pins.h" + +//#undef ENABLE +// +//# define _TCC_SIZE(unused, n) TCC ## n ## _SIZE, +//# define TCC_SIZES { REPEAT_MACRO(_TCC_SIZE, 0, TCC_INST_NUM) } +// +//static uint32_t tcc_periods[TCC_INST_NUM]; +//static uint32_t tc_periods[TC_INST_NUM]; +// +//uint32_t target_tcc_frequencies[TCC_INST_NUM]; +//uint8_t tcc_refcount[TCC_INST_NUM]; +// +//// This bitmask keeps track of which channels of a TCC are currently claimed. +//#ifdef SAMD21 +//uint8_t tcc_channels[3]; // Set by pwmout_reset() to {0xf0, 0xfc, 0xfc} initially. +//#endif +//#ifdef SAMD51 +//uint8_t tcc_channels[5]; // Set by pwmout_reset() to {0xc0, 0xf0, 0xf8, 0xfc, 0xfc} initially. +//#endif +// +//static uint8_t never_reset_tc_or_tcc[TC_INST_NUM + TCC_INST_NUM]; + +void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self) { +// if (self->timer->is_tc) { +// never_reset_tc_or_tcc[self->timer->index] += 1; +// } else { +// never_reset_tc_or_tcc[TC_INST_NUM + self->timer->index] += 1; +// } +// +// never_reset_pin_number(self->pin->number); +} + +void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) { +// if (self->timer->is_tc) { +// never_reset_tc_or_tcc[self->timer->index] -= 1; +// } else { +// never_reset_tc_or_tcc[TC_INST_NUM + self->timer->index] -= 1; +// } +} + +void pwmout_reset(void) { +// // Reset all timers +// for (int i = 0; i < TCC_INST_NUM; i++) { +// target_tcc_frequencies[i] = 0; +// tcc_refcount[i] = 0; +// } +// Tcc *tccs[TCC_INST_NUM] = TCC_INSTS; +// for (int i = 0; i < TCC_INST_NUM; i++) { +// if (never_reset_tc_or_tcc[TC_INST_NUM + i] > 0) { +// continue; +// } +// // Disable the module before resetting it. +// if (tccs[i]->CTRLA.bit.ENABLE == 1) { +// tccs[i]->CTRLA.bit.ENABLE = 0; +// while (tccs[i]->SYNCBUSY.bit.ENABLE == 1) { +// } +// } +// uint8_t mask = 0xff; +// for (uint8_t j = 0; j < tcc_cc_num[i]; j++) { +// mask <<= 1; +// } +// tcc_channels[i] = mask; +// tccs[i]->CTRLA.bit.SWRST = 1; +// while (tccs[i]->CTRLA.bit.SWRST == 1) { +// } +// } +// Tc *tcs[TC_INST_NUM] = TC_INSTS; +// for (int i = 0; i < TC_INST_NUM; i++) { +// if (never_reset_tc_or_tcc[i] > 0) { +// continue; +// } +// tcs[i]->COUNT16.CTRLA.bit.SWRST = 1; +// while (tcs[i]->COUNT16.CTRLA.bit.SWRST == 1) { +// } +// } +} + +//static uint8_t tcc_channel(const pin_timer_t* t) { +// // For the SAMD51 this hardcodes the use of OTMX == 0x0, the output matrix mapping, which uses +// // SAMD21-style modulo mapping. +// return t->wave_output % tcc_cc_num[t->index]; +//} + +//bool channel_ok(const pin_timer_t* t) { +// uint8_t channel_bit = 1 << tcc_channel(t); +// return (!t->is_tc && ((tcc_channels[t->index] & channel_bit) == 0)) || +// t->is_tc; +//} + +#define PWM_SRC_CLK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk) + +pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self, + const mcu_pin_obj_t *pin, + uint16_t duty, + uint32_t frequency, + bool variable_frequency) { + self->pin = pin; + self->variable_frequency = variable_frequency; + + const uint32_t pwm_count = sizeof(mcu_pwm_list) / sizeof(mcu_pwm_obj_t); + + for (uint32_t i = 0; i < pwm_count; ++i) { + if (mcu_pwm_list[i].pin != pin) + continue; + + printf("pwm: 0x%p, sum %d, chan %d, mux %d\r\n", mcu_pwm_list[i].pwm, mcu_pwm_list[i].submodule, mcu_pwm_list[i].channel, mcu_pwm_list[i].mux_mode); + + self->pwm = &mcu_pwm_list[i]; + + break; + } + + if (self->pwm == NULL) { + return PWMOUT_INVALID_PIN; + } + + CLOCK_SetDiv(kCLOCK_AhbDiv, 0x2); /* Set AHB PODF to 2, divide by 3 */ + CLOCK_SetDiv(kCLOCK_IpgDiv, 0x3); /* Set IPG PODF to 3, divede by 4 */ + +//TODO re-enable +// IOMUXC_SetPinMux( +// IOMUXC_GPIO_SD_02_FLEXPWM1_PWM0_A, /* GPIO_02 is configured as FLEXPWM1_PWM0_A */ +// 0U); /* Software Input On Field: Input Path is determined by functionality */ +// +// IOMUXC_SetPinConfig( +// IOMUXC_GPIO_SD_02_FLEXPWM1_PWM0_A, /* GPIO_02 PAD functional properties : */ +// 0x10A0U); /* Slew Rate Field: Slow Slew Rate +// Drive Strength Field: R0/4 +// Speed Field: fast(150MHz) +// Open Drain Enable Field: Open Drain Disabled +// Pull / Keep Enable Field: Pull/Keeper Enabled +// Pull / Keep Select Field: Keeper +// Pull Up / Down Config. Field: 100K Ohm Pull Down +// Hyst. Enable Field: Hysteresis Disabled */ + + pwm_config_t pwmConfig; + + /* + * pwmConfig.enableDebugMode = false; + * pwmConfig.enableWait = false; + * pwmConfig.reloadSelect = kPWM_LocalReload; + * pwmConfig.faultFilterCount = 0; + * pwmConfig.faultFilterPeriod = 0; + * pwmConfig.clockSource = kPWM_BusClock; + * pwmConfig.prescale = kPWM_Prescale_Divide_1; + * pwmConfig.initializationControl = kPWM_Initialize_LocalSync; + * pwmConfig.forceTrigger = kPWM_Force_Local; + * pwmConfig.reloadFrequency = kPWM_LoadEveryOportunity; + * pwmConfig.reloadLogic = kPWM_ReloadImmediate; + * pwmConfig.pairOperation = kPWM_Independent; + */ + PWM_GetDefaultConfig(&pwmConfig); + + //pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle; + pwmConfig.enableDebugMode = true; + + if (PWM_Init(PWM1, self->pwm->submodule, &pwmConfig) == kStatus_Fail) { + printf("PWM initialization failed\r\n"); + return PWMOUT_INVALID_PIN; + } + + pwm_signal_param_t pwmSignal; + + /* Set deadtime count, we set this to about 650ns */ + uint16_t deadTimeVal = ((uint64_t)PWM_SRC_CLK_FREQ * 650) / 1000000000; + + pwmSignal.pwmChannel = self->pwm->channel; + pwmSignal.level = kPWM_HighTrue; + pwmSignal.dutyCyclePercent = frequency / 2; /* 1 percent dutycycle */ + pwmSignal.deadtimeValue = deadTimeVal; + + PWM_SetupPwm(PWM1, self->pwm->submodule, &pwmSignal, 1, kPWM_SignedCenterAligned, frequency, PWM_SRC_CLK_FREQ); + + PWM_SetPwmLdok(PWM1, kPWM_Control_Module_0 | kPWM_Control_Module_1 | kPWM_Control_Module_2, true); + + PWM_StartTimer(PWM1, kPWM_Control_Module_0 | kPWM_Control_Module_1 | kPWM_Control_Module_2); + +// if (frequency == 0 || frequency > 6000000) { +// return PWMOUT_INVALID_FREQUENCY; +// } + +// // Figure out which timer we are using. +// // First see if a tcc is already going with the frequency we want and our +// // channel is unused. tc's don't have enough channels to share. +// const pin_timer_t* timer = NULL; +// uint8_t mux_position = 0; +// if (!variable_frequency) { +// for (uint8_t i = 0; i < TCC_INST_NUM && timer == NULL; i++) { +// if (target_tcc_frequencies[i] != frequency) { +// continue; +// } +// for (uint8_t j = 0; j < NUM_TIMERS_PER_PIN && timer == NULL; j++) { +// const pin_timer_t* t = &pin->timer[j]; +// if (t->index != i || t->is_tc || t->index >= TCC_INST_NUM) { +// continue; +// } +// Tcc* tcc = tcc_insts[t->index]; +// if (tcc->CTRLA.bit.ENABLE == 1 && channel_ok(t)) { +// timer = t; +// mux_position = j; +// // Claim channel. +// tcc_channels[timer->index] |= (1 << tcc_channel(timer)); +// +// } +// } +// } +// } +// +// // No existing timer has been found, so find a new one to use and set it up. +// if (timer == NULL) { +// // By default, with fixed frequency we want to share a TCC because its likely we'll have +// // other outputs at the same frequency. If the frequency is variable then we'll only have +// // one output so we start with the TCs to see if they work. +// int8_t direction = -1; +// uint8_t start = NUM_TIMERS_PER_PIN - 1; +// bool found = false; +// if (variable_frequency) { +// direction = 1; +// start = 0; +// } +// for (int8_t i = start; i >= 0 && i < NUM_TIMERS_PER_PIN && timer == NULL; i += direction) { +// const pin_timer_t* t = &pin->timer[i]; +// if ((!t->is_tc && t->index >= TCC_INST_NUM) || +// (t->is_tc && t->index >= TC_INST_NUM)) { +// continue; +// } +// if (t->is_tc) { +// found = true; +// Tc* tc = tc_insts[t->index]; +// if (tc->COUNT16.CTRLA.bit.ENABLE == 0 && t->wave_output == 1) { +// timer = t; +// mux_position = i; +// } +// } else { +// Tcc* tcc = tcc_insts[t->index]; +// if (tcc->CTRLA.bit.ENABLE == 0 && channel_ok(t)) { +// timer = t; +// mux_position = i; +// } +// } +// } +// +// if (timer == NULL) { +// if (found) { +// return PWMOUT_ALL_TIMERS_ON_PIN_IN_USE; +// } +// return PWMOUT_ALL_TIMERS_IN_USE; +// } +// +// uint8_t resolution = 0; +// if (timer->is_tc) { +// resolution = 16; +// } else { +// // TCC resolution varies so look it up. +// const uint8_t _tcc_sizes[TCC_INST_NUM] = TCC_SIZES; +// resolution = _tcc_sizes[timer->index]; +// } +// // First determine the divisor that gets us the highest resolution. +// uint32_t system_clock = common_hal_mcu_processor_get_frequency(); +// uint32_t top; +// uint8_t divisor; +// for (divisor = 0; divisor < 8; divisor++) { +// top = (system_clock / prescaler[divisor] / frequency) - 1; +// if (top < (1u << resolution)) { +// break; +// } +// } +// +// set_timer_handler(timer->is_tc, timer->index, TC_HANDLER_NO_INTERRUPT); +// // We use the zeroeth clock on either port to go full speed. +// turn_on_clocks(timer->is_tc, timer->index, 0); +// +// if (timer->is_tc) { +// tc_periods[timer->index] = top; +// Tc* tc = tc_insts[timer->index]; +// #ifdef SAMD21 +// tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | +// TC_CTRLA_PRESCALER(divisor) | +// TC_CTRLA_WAVEGEN_MPWM; +// tc->COUNT16.CC[0].reg = top; +// #endif +// #ifdef SAMD51 +// +// tc->COUNT16.CTRLA.bit.SWRST = 1; +// while (tc->COUNT16.CTRLA.bit.SWRST == 1) { +// } +// tc_set_enable(tc, false); +// tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_PRESCALER(divisor); +// tc->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MPWM; +// tc->COUNT16.CCBUF[0].reg = top; +// tc->COUNT16.CCBUF[1].reg = 0; +// #endif +// +// tc_set_enable(tc, true); +// } else { +// tcc_periods[timer->index] = top; +// Tcc* tcc = tcc_insts[timer->index]; +// tcc_set_enable(tcc, false); +// tcc->CTRLA.bit.PRESCALER = divisor; +// tcc->PER.bit.PER = top; +// tcc->WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val; +// tcc_set_enable(tcc, true); +// target_tcc_frequencies[timer->index] = frequency; +// tcc_refcount[timer->index]++; +// if (variable_frequency) { +// // We're changing frequency so claim all of the channels. +// tcc_channels[timer->index] = 0xff; +// } else { +// tcc_channels[timer->index] |= (1 << tcc_channel(timer)); +// } +// } +// } +// +// self->timer = timer; +// +// gpio_set_pin_function(pin->number, GPIO_PIN_FUNCTION_E + mux_position); + + common_hal_pwmio_pwmout_set_duty_cycle(self, duty); + + return PWMOUT_OK; +} + +bool common_hal_pwmio_pwmout_deinited(pwmio_pwmout_obj_t* self) { + return self->pin == NULL; +} + +void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t* self) { + if (common_hal_pwmio_pwmout_deinited(self)) { + return; + } + +// const pin_timer_t* t = self->timer; +// if (t->is_tc) { +// Tc* tc = tc_insts[t->index]; +// tc_set_enable(tc, false); +// tc->COUNT16.CTRLA.bit.SWRST = true; +// tc_wait_for_sync(tc); +// } else { +// tcc_refcount[t->index]--; +// tcc_channels[t->index] &= ~(1 << tcc_channel(t)); +// if (tcc_refcount[t->index] == 0) { +// target_tcc_frequencies[t->index] = 0; +// Tcc* tcc = tcc_insts[t->index]; +// tcc_set_enable(tcc, false); +// tcc->CTRLA.bit.SWRST = true; +// while (tcc->SYNCBUSY.bit.SWRST != 0) { +// /* Wait for sync */ +// } +// } +// } +// reset_pin_number(self->pin->number); + self->pin = NULL; +} + +void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t *self, uint16_t duty) { + PWM_UpdatePwmDutycycle(PWM1, self->pwm->submodule, self->pwm->channel, kPWM_SignedCenterAligned, duty); + +// const pin_timer_t* t = self->timer; +// if (t->is_tc) { +// uint16_t adjusted_duty = tc_periods[t->index] * duty / 0xffff; +// #ifdef SAMD21 +// tc_insts[t->index]->COUNT16.CC[t->wave_output].reg = adjusted_duty; +// #endif +// #ifdef SAMD51 +// Tc* tc = tc_insts[t->index]; +// while (tc->COUNT16.SYNCBUSY.bit.CC1 != 0) {} +// tc->COUNT16.CCBUF[1].reg = adjusted_duty; +// #endif +// } else { +// uint32_t adjusted_duty = ((uint64_t) tcc_periods[t->index]) * duty / 0xffff; +// uint8_t channel = tcc_channel(t); +// Tcc* tcc = tcc_insts[t->index]; +// +// // Write into the CC buffer register, which will be transferred to the +// // CC register on an UPDATE (when period is finished). +// // Do clock domain syncing as necessary. +// +// while (tcc->SYNCBUSY.reg != 0) {} +// +// // Lock out double-buffering while updating the CCB value. +// tcc->CTRLBSET.bit.LUPD = 1; +// #ifdef SAMD21 +// tcc->CCB[channel].reg = adjusted_duty; +// #endif +// #ifdef SAMD51 +// tcc->CCBUF[channel].reg = adjusted_duty; +// #endif +// tcc->CTRLBCLR.bit.LUPD = 1; +// } +} + +uint16_t common_hal_pwmio_pwmout_get_duty_cycle(pwmio_pwmout_obj_t* self) { + return 0; +// const pin_timer_t* t = self->timer; +// if (t->is_tc) { +// Tc* tc = tc_insts[t->index]; +// tc_wait_for_sync(tc); +// uint16_t cv = tc->COUNT16.CC[t->wave_output].reg; +// return cv * 0xffff / tc_periods[t->index]; +// } else { +// Tcc* tcc = tcc_insts[t->index]; +// uint8_t channel = tcc_channel(t); +// uint32_t cv = 0; +// +// while (tcc->SYNCBUSY.bit.CTRLB) {} +// +// #ifdef SAMD21 +// // If CCBV (CCB valid) is set, the CCB value hasn't yet been copied +// // to the CC value. +// if ((tcc->STATUS.vec.CCBV & (1 << channel)) != 0) { +// cv = tcc->CCB[channel].reg; +// } else { +// cv = tcc->CC[channel].reg; +// } +// #endif +// #ifdef SAMD51 +// if ((tcc->STATUS.vec.CCBUFV & (1 << channel)) != 0) { +// cv = tcc->CCBUF[channel].reg; +// } else { +// cv = tcc->CC[channel].reg; +// } +// #endif +// +// uint32_t duty_cycle = ((uint64_t) cv) * 0xffff / tcc_periods[t->index]; +// +// return duty_cycle; +// } +} + +void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t* self, + uint32_t frequency) { +// if (frequency == 0 || frequency > 6000000) { +// mp_raise_ValueError(translate("Invalid PWM frequency")); +// } +// const pin_timer_t* t = self->timer; +// uint8_t resolution; +// if (t->is_tc) { +// resolution = 16; +// } else { +// resolution = 24; +// } +// uint32_t system_clock = common_hal_mcu_processor_get_frequency(); +// uint32_t new_top; +// uint8_t new_divisor; +// for (new_divisor = 0; new_divisor < 8; new_divisor++) { +// new_top = (system_clock / prescaler[new_divisor] / frequency) - 1; +// if (new_top < (1u << resolution)) { +// break; +// } +// } +// uint16_t old_duty = common_hal_pwmio_pwmout_get_duty_cycle(self); +// if (t->is_tc) { +// Tc* tc = tc_insts[t->index]; +// uint8_t old_divisor = tc->COUNT16.CTRLA.bit.PRESCALER; +// if (new_divisor != old_divisor) { +// tc_set_enable(tc, false); +// tc->COUNT16.CTRLA.bit.PRESCALER = new_divisor; +// tc_set_enable(tc, true); +// } +// tc_periods[t->index] = new_top; +// #ifdef SAMD21 +// tc->COUNT16.CC[0].reg = new_top; +// #endif +// #ifdef SAMD51 +// while (tc->COUNT16.SYNCBUSY.reg != 0) {} +// tc->COUNT16.CCBUF[0].reg = new_top; +// #endif +// } else { +// Tcc* tcc = tcc_insts[t->index]; +// uint8_t old_divisor = tcc->CTRLA.bit.PRESCALER; +// if (new_divisor != old_divisor) { +// tcc_set_enable(tcc, false); +// tcc->CTRLA.bit.PRESCALER = new_divisor; +// tcc_set_enable(tcc, true); +// } +// while (tcc->SYNCBUSY.reg != 0) {} +// tcc_periods[t->index] = new_top; +// #ifdef SAMD21 +// tcc->PERB.bit.PERB = new_top; +// #endif +// #ifdef SAMD51 +// tcc->PERBUF.bit.PERBUF = new_top; +// #endif +// } + +// common_hal_pwmio_pwmout_set_duty_cycle(self, old_duty); +} + +uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t* self) { +// uint32_t system_clock = common_hal_mcu_processor_get_frequency(); +// const pin_timer_t* t = self->timer; +// uint8_t divisor; +// uint32_t top; +// if (t->is_tc) { +// divisor = tc_insts[t->index]->COUNT16.CTRLA.bit.PRESCALER; +// top = tc_periods[t->index]; +// } else { +// divisor = tcc_insts[t->index]->CTRLA.bit.PRESCALER; +// top = tcc_periods[t->index]; +// } +// return (system_clock / prescaler[divisor]) / (top + 1); + return 0; +} + +bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t* self) { + return self->variable_frequency; +} diff --git a/ports/mimxrt10xx/common-hal/pwmio/PWMOut.h b/ports/mimxrt10xx/common-hal/pwmio/PWMOut.h new file mode 100644 index 000000000..d3954de40 --- /dev/null +++ b/ports/mimxrt10xx/common-hal/pwmio/PWMOut.h @@ -0,0 +1,44 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2019 Artur Pacholec + * + * 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_MIMXRT10XX_COMMON_HAL_PWMIO_PWMOUT_H +#define MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_PWMIO_PWMOUT_H + +#include "common-hal/microcontroller/Pin.h" +#include "periph.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + const mcu_pin_obj_t *pin; + const mcu_pwm_obj_t *pwm; + bool variable_frequency; +} pwmio_pwmout_obj_t; + +void pwmout_reset(void); + +#endif // MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_PWMIO_PWMOUT_H diff --git a/ports/mimxrt10xx/common-hal/pwmio/__init__.c b/ports/mimxrt10xx/common-hal/pwmio/__init__.c new file mode 100644 index 000000000..2bee925bc --- /dev/null +++ b/ports/mimxrt10xx/common-hal/pwmio/__init__.c @@ -0,0 +1 @@ +// No pulseio module functions. diff --git a/ports/mimxrt10xx/supervisor/port.c b/ports/mimxrt10xx/supervisor/port.c index 0b53a79f0..38cf16a49 100644 --- a/ports/mimxrt10xx/supervisor/port.c +++ b/ports/mimxrt10xx/supervisor/port.c @@ -39,7 +39,7 @@ #include "common-hal/microcontroller/Pin.h" #include "common-hal/pulseio/PulseIn.h" #include "common-hal/pulseio/PulseOut.h" -#include "common-hal/pulseio/PWMOut.h" +#include "common-hal/pwmio/PWMOut.h" #include "common-hal/rtc/RTC.h" #include "common-hal/busio/SPI.h" @@ -289,6 +289,8 @@ void reset_port(void) { #if CIRCUITPY_PULSEIO pulseout_reset(); +#endif +#if CIRCUITPY_PWMIO pwmout_reset(); #endif diff --git a/ports/nrf/common-hal/audiopwmio/PWMAudioOut.c b/ports/nrf/common-hal/audiopwmio/PWMAudioOut.c index 7fec766fb..ed1bf81e4 100644 --- a/ports/nrf/common-hal/audiopwmio/PWMAudioOut.c +++ b/ports/nrf/common-hal/audiopwmio/PWMAudioOut.c @@ -32,7 +32,7 @@ #include "py/mperrno.h" #include "py/runtime.h" #include "common-hal/audiopwmio/PWMAudioOut.h" -#include "common-hal/pulseio/PWMOut.h" +#include "common-hal/pwmio/PWMOut.h" #include "shared-bindings/audiopwmio/PWMAudioOut.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" diff --git a/ports/nrf/common-hal/pulseio/PWMOut.c b/ports/nrf/common-hal/pulseio/PWMOut.c deleted file mode 100644 index 9d42ccca0..000000000 --- a/ports/nrf/common-hal/pulseio/PWMOut.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Dan Halbert for Adafruit Industries - * - * 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 -#include "nrf.h" - -#include "py/runtime.h" -#include "common-hal/pulseio/PWMOut.h" -#include "shared-bindings/pulseio/PWMOut.h" -#include "supervisor/shared/translate.h" - -#include "nrf_gpio.h" - -#define PWM_MAX_FREQ (16000000) - -STATIC NRF_PWM_Type* pwms[] = { -#if NRFX_CHECK(NRFX_PWM0_ENABLED) - NRF_PWM0, -#endif -#if NRFX_CHECK(NRFX_PWM1_ENABLED) - NRF_PWM1, -#endif -#if NRFX_CHECK(NRFX_PWM2_ENABLED) - NRF_PWM2, -#endif -#if NRFX_CHECK(NRFX_PWM3_ENABLED) - NRF_PWM3, -#endif -}; - -#define CHANNELS_PER_PWM 4 - -STATIC uint16_t pwm_seq[MP_ARRAY_SIZE(pwms)][CHANNELS_PER_PWM]; - -static uint8_t never_reset_pwm[MP_ARRAY_SIZE(pwms)]; - -STATIC int pwm_idx(NRF_PWM_Type *pwm) { - for(size_t i=0; i < MP_ARRAY_SIZE(pwms); i++) - if(pwms[i] == pwm) return i; - return -1; -} - -void common_hal_pulseio_pwmout_never_reset(pulseio_pwmout_obj_t *self) { - for(size_t i=0; i < MP_ARRAY_SIZE(pwms); i++) { - NRF_PWM_Type* pwm = pwms[i]; - if (pwm == self->pwm) { - never_reset_pwm[i] += 1; - } - } - - never_reset_pin_number(self->pin_number); -} - -void common_hal_pulseio_pwmout_reset_ok(pulseio_pwmout_obj_t *self) { - for(size_t i=0; i < MP_ARRAY_SIZE(pwms); i++) { - NRF_PWM_Type* pwm = pwms[i]; - if (pwm == self->pwm) { - never_reset_pwm[i] -= 1; - } - } -} - -void reset_single_pwmout(uint8_t i) { - NRF_PWM_Type* pwm = pwms[i]; - - pwm->ENABLE = 0; - pwm->MODE = PWM_MODE_UPDOWN_Up; - pwm->DECODER = PWM_DECODER_LOAD_Individual; - pwm->LOOP = 0; - pwm->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_1; // default is 500 hz - pwm->COUNTERTOP = (PWM_MAX_FREQ/500); // default is 500 hz - - pwm->SEQ[0].PTR = (uint32_t) pwm_seq[i]; - pwm->SEQ[0].CNT = CHANNELS_PER_PWM; // default mode is Individual --> count must be 4 - pwm->SEQ[0].REFRESH = 0; - pwm->SEQ[0].ENDDELAY = 0; - - pwm->SEQ[1].PTR = 0; - pwm->SEQ[1].CNT = 0; - pwm->SEQ[1].REFRESH = 0; - pwm->SEQ[1].ENDDELAY = 0; - - for(int ch =0; ch < CHANNELS_PER_PWM; ch++) { - pwm_seq[i][ch] = (1 << 15); // polarity = 0 - } -} - -void pwmout_reset(void) { - for(size_t i=0; i < MP_ARRAY_SIZE(pwms); i++) { - if (never_reset_pwm[i] > 0) { - continue; - } - reset_single_pwmout(i); - } -} - -// Find the smallest prescaler value that will allow the divisor to be in range. -// This allows the most accuracy. -bool convert_frequency(uint32_t frequency, uint16_t *countertop, nrf_pwm_clk_t *base_clock) { - uint32_t divisor = 1; - // Use a 32-bit number so we don't overflow the uint16_t; - uint32_t tentative_countertop; - for (*base_clock = PWM_PRESCALER_PRESCALER_DIV_1; - *base_clock <= PWM_PRESCALER_PRESCALER_DIV_128; - (*base_clock)++) { - tentative_countertop = PWM_MAX_FREQ / divisor / frequency; - // COUNTERTOP must be 3..32767, according to datasheet, but 3 doesn't work. 4 does. - if (tentative_countertop <= 32767 && tentative_countertop >= 4) { - // In range, OK to return. - *countertop = tentative_countertop; - return true; - } - divisor *= 2; - } - - return false; -} - -// We store these in an array because we cannot compute them. -static IRQn_Type pwm_irqs[4] = {PWM0_IRQn, PWM1_IRQn, PWM2_IRQn, PWM3_IRQn}; - -NRF_PWM_Type *pwmout_allocate(uint16_t countertop, nrf_pwm_clk_t base_clock, - bool variable_frequency, int8_t *channel_out, bool *pwm_already_in_use_out, - IRQn_Type* irq) { - for (size_t pwm_index = 0; pwm_index < MP_ARRAY_SIZE(pwms); pwm_index++) { - NRF_PWM_Type *pwm = pwms[pwm_index]; - bool pwm_already_in_use = pwm->ENABLE & PWM_ENABLE_ENABLE_Msk; - if (pwm_already_in_use) { - if (variable_frequency) { - // Variable frequency requires exclusive use of a PWM, so try the next one. - continue; - } - - // PWM is in use, but see if it's set to the same frequency we need. If so, - // look for a free channel. - if (pwm->COUNTERTOP == countertop && pwm->PRESCALER == base_clock) { - for (size_t chan = 0; chan < CHANNELS_PER_PWM; chan++) { - if (pwm->PSEL.OUT[chan] == 0xFFFFFFFF) { - // Channel is free. - if (channel_out) { - *channel_out = chan; - } - if (pwm_already_in_use_out) { - *pwm_already_in_use_out = pwm_already_in_use; - } - if (irq) { - *irq = pwm_irqs[pwm_index]; - } - return pwm; - } - } - } - } else { - // PWM not yet in use, so we can start to use it. Use channel 0. - if (channel_out) { - *channel_out = 0; - } - if (pwm_already_in_use_out) { - *pwm_already_in_use_out = pwm_already_in_use; - } - if (irq) { - *irq = pwm_irqs[pwm_index]; - } - return pwm; - } - } - return NULL; -} - -void pwmout_free_channel(NRF_PWM_Type *pwm, int8_t channel) { - // Disconnect pin from channel. - pwm->PSEL.OUT[channel] = 0xFFFFFFFF; - - for(int i=0; i < CHANNELS_PER_PWM; i++) { - if (pwm->PSEL.OUT[i] != 0xFFFFFFFF) { - // Some channel is still being used, so don't disable. - return; - } - } - - nrf_pwm_disable(pwm); -} - -pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, - const mcu_pin_obj_t* pin, - uint16_t duty, - uint32_t frequency, - bool variable_frequency) { - - // We don't use the nrfx driver here because we want to dynamically allocate channels - // as needed in an already-enabled PWM. - - uint16_t countertop; - nrf_pwm_clk_t base_clock; - if (frequency == 0 || !convert_frequency(frequency, &countertop, &base_clock)) { - return PWMOUT_INVALID_FREQUENCY; - } - - int8_t channel; - bool pwm_already_in_use; - self->pwm = pwmout_allocate(countertop, base_clock, variable_frequency, - &channel, &pwm_already_in_use, NULL); - - if (self->pwm == NULL) { - return PWMOUT_ALL_TIMERS_IN_USE; - } - - self->channel = channel; - self->pin_number = pin->number; - claim_pin(pin); - - self->frequency = frequency; - self->variable_frequency = variable_frequency; - - // Note this is standard, not strong drive. - nrf_gpio_cfg_output(self->pin_number); - - // disable before mapping pin channel - nrf_pwm_disable(self->pwm); - - if (!pwm_already_in_use) { - reset_single_pwmout(pwm_idx(self->pwm)); - nrf_pwm_configure(self->pwm, base_clock, NRF_PWM_MODE_UP, countertop); - } - - // Connect channel to pin, without disturbing other channels. - self->pwm->PSEL.OUT[self->channel] = pin->number; - - nrf_pwm_enable(self->pwm); - - common_hal_pulseio_pwmout_set_duty_cycle(self, duty); - return PWMOUT_OK; -} - -bool common_hal_pulseio_pwmout_deinited(pulseio_pwmout_obj_t* self) { - return self->pwm == NULL; -} - -void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) { - if (common_hal_pulseio_pwmout_deinited(self)) { - return; - } - - nrf_gpio_cfg_default(self->pin_number); - - NRF_PWM_Type* pwm = self->pwm; - self->pwm = NULL; - - pwmout_free_channel(pwm, self->channel); - - reset_pin_number(self->pin_number); - self->pin_number = NO_PIN; -} - -void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, uint16_t duty_cycle) { - self->duty_cycle = duty_cycle; - - uint16_t* p_value = ((uint16_t*)self->pwm->SEQ[0].PTR) + self->channel; - *p_value = ((duty_cycle * self->pwm->COUNTERTOP) / 0xFFFF) | (1 << 15); - - self->pwm->TASKS_SEQSTART[0] = 1; -} - -uint16_t common_hal_pulseio_pwmout_get_duty_cycle(pulseio_pwmout_obj_t* self) { - return self->duty_cycle; -} - -void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self, uint32_t frequency) { - // COUNTERTOP is 3..32767, so highest available frequency is PWM_MAX_FREQ / 3. - uint16_t countertop; - nrf_pwm_clk_t base_clock; - if (frequency == 0 || !convert_frequency(frequency, &countertop, &base_clock)) { - mp_raise_ValueError(translate("Invalid PWM frequency")); - } - self->frequency = frequency; - - nrf_pwm_configure(self->pwm, base_clock, NRF_PWM_MODE_UP, countertop); - // Set the duty cycle again, because it depends on COUNTERTOP, which probably changed. - // Setting the duty cycle will also do a SEQSTART. - common_hal_pulseio_pwmout_set_duty_cycle(self, self->duty_cycle); -} - -uint32_t common_hal_pulseio_pwmout_get_frequency(pulseio_pwmout_obj_t* self) { - return self->frequency; -} - -bool common_hal_pulseio_pwmout_get_variable_frequency(pulseio_pwmout_obj_t* self) { - return self->variable_frequency; -} diff --git a/ports/nrf/common-hal/pulseio/PWMOut.h b/ports/nrf/common-hal/pulseio/PWMOut.h deleted file mode 100644 index a0c2d8747..000000000 --- a/ports/nrf/common-hal/pulseio/PWMOut.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries - * - * 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_NRF_COMMON_HAL_PULSEIO_PWMOUT_H -#define MICROPY_INCLUDED_NRF_COMMON_HAL_PULSEIO_PWMOUT_H - -#include "nrfx_pwm.h" -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - NRF_PWM_Type* pwm; - uint8_t pin_number; - uint8_t channel: 7; - bool variable_frequency: 1; - uint16_t duty_cycle; - uint32_t frequency; -} pulseio_pwmout_obj_t; - -void pwmout_reset(void); -NRF_PWM_Type *pwmout_allocate(uint16_t countertop, nrf_pwm_clk_t base_clock, - bool variable_frequency, int8_t *channel_out, bool *pwm_already_in_use_out, - IRQn_Type *irq); -void pwmout_free_channel(NRF_PWM_Type *pwm, int8_t channel); - -#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_PULSEIO_PWMOUT_H diff --git a/ports/nrf/common-hal/pulseio/PulseOut.c b/ports/nrf/common-hal/pulseio/PulseOut.c index 270cb45d6..16e383caf 100644 --- a/ports/nrf/common-hal/pulseio/PulseOut.c +++ b/ports/nrf/common-hal/pulseio/PulseOut.c @@ -34,7 +34,7 @@ #include "py/gc.h" #include "py/runtime.h" #include "shared-bindings/pulseio/PulseOut.h" -#include "shared-bindings/pulseio/PWMOut.h" +#include "shared-bindings/pwmio/PWMOut.h" #include "supervisor/shared/translate.h" // A single timer is shared amongst all PulseOut objects under the assumption that @@ -100,7 +100,7 @@ void pulseout_reset() { } void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, - const pulseio_pwmout_obj_t* carrier) { + const pwmio_pwmout_obj_t* carrier) { if (refcount == 0) { timer = nrf_peripherals_allocate_timer_or_throw(); } diff --git a/ports/nrf/common-hal/pulseio/PulseOut.h b/ports/nrf/common-hal/pulseio/PulseOut.h index 42ec52e30..714f740b2 100644 --- a/ports/nrf/common-hal/pulseio/PulseOut.h +++ b/ports/nrf/common-hal/pulseio/PulseOut.h @@ -28,13 +28,13 @@ #define MICROPY_INCLUDED_NRF_COMMON_HAL_PULSEIO_PULSEOUT_H #include "common-hal/microcontroller/Pin.h" -#include "common-hal/pulseio/PWMOut.h" +#include "common-hal/pwmio/PWMOut.h" #include "py/obj.h" typedef struct { mp_obj_base_t base; - const pulseio_pwmout_obj_t *pwmout; + const pwmio_pwmout_obj_t *pwmout; } pulseio_pulseout_obj_t; void pulseout_reset(void); diff --git a/ports/nrf/common-hal/pwmio/PWMOut.c b/ports/nrf/common-hal/pwmio/PWMOut.c new file mode 100644 index 000000000..a9d896488 --- /dev/null +++ b/ports/nrf/common-hal/pwmio/PWMOut.c @@ -0,0 +1,312 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018 Dan Halbert for Adafruit Industries + * + * 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 +#include "nrf.h" + +#include "py/runtime.h" +#include "common-hal/pwmio/PWMOut.h" +#include "shared-bindings/pwmio/PWMOut.h" +#include "supervisor/shared/translate.h" + +#include "nrf_gpio.h" + +#define PWM_MAX_FREQ (16000000) + +STATIC NRF_PWM_Type* pwms[] = { +#if NRFX_CHECK(NRFX_PWM0_ENABLED) + NRF_PWM0, +#endif +#if NRFX_CHECK(NRFX_PWM1_ENABLED) + NRF_PWM1, +#endif +#if NRFX_CHECK(NRFX_PWM2_ENABLED) + NRF_PWM2, +#endif +#if NRFX_CHECK(NRFX_PWM3_ENABLED) + NRF_PWM3, +#endif +}; + +#define CHANNELS_PER_PWM 4 + +STATIC uint16_t pwm_seq[MP_ARRAY_SIZE(pwms)][CHANNELS_PER_PWM]; + +static uint8_t never_reset_pwm[MP_ARRAY_SIZE(pwms)]; + +STATIC int pwm_idx(NRF_PWM_Type *pwm) { + for(size_t i=0; i < MP_ARRAY_SIZE(pwms); i++) + if(pwms[i] == pwm) return i; + return -1; +} + +void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self) { + for(size_t i=0; i < MP_ARRAY_SIZE(pwms); i++) { + NRF_PWM_Type* pwm = pwms[i]; + if (pwm == self->pwm) { + never_reset_pwm[i] += 1; + } + } + + never_reset_pin_number(self->pin_number); +} + +void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) { + for(size_t i=0; i < MP_ARRAY_SIZE(pwms); i++) { + NRF_PWM_Type* pwm = pwms[i]; + if (pwm == self->pwm) { + never_reset_pwm[i] -= 1; + } + } +} + +void reset_single_pwmout(uint8_t i) { + NRF_PWM_Type* pwm = pwms[i]; + + pwm->ENABLE = 0; + pwm->MODE = PWM_MODE_UPDOWN_Up; + pwm->DECODER = PWM_DECODER_LOAD_Individual; + pwm->LOOP = 0; + pwm->PRESCALER = PWM_PRESCALER_PRESCALER_DIV_1; // default is 500 hz + pwm->COUNTERTOP = (PWM_MAX_FREQ/500); // default is 500 hz + + pwm->SEQ[0].PTR = (uint32_t) pwm_seq[i]; + pwm->SEQ[0].CNT = CHANNELS_PER_PWM; // default mode is Individual --> count must be 4 + pwm->SEQ[0].REFRESH = 0; + pwm->SEQ[0].ENDDELAY = 0; + + pwm->SEQ[1].PTR = 0; + pwm->SEQ[1].CNT = 0; + pwm->SEQ[1].REFRESH = 0; + pwm->SEQ[1].ENDDELAY = 0; + + for(int ch =0; ch < CHANNELS_PER_PWM; ch++) { + pwm_seq[i][ch] = (1 << 15); // polarity = 0 + } +} + +void pwmout_reset(void) { + for(size_t i=0; i < MP_ARRAY_SIZE(pwms); i++) { + if (never_reset_pwm[i] > 0) { + continue; + } + reset_single_pwmout(i); + } +} + +// Find the smallest prescaler value that will allow the divisor to be in range. +// This allows the most accuracy. +bool convert_frequency(uint32_t frequency, uint16_t *countertop, nrf_pwm_clk_t *base_clock) { + uint32_t divisor = 1; + // Use a 32-bit number so we don't overflow the uint16_t; + uint32_t tentative_countertop; + for (*base_clock = PWM_PRESCALER_PRESCALER_DIV_1; + *base_clock <= PWM_PRESCALER_PRESCALER_DIV_128; + (*base_clock)++) { + tentative_countertop = PWM_MAX_FREQ / divisor / frequency; + // COUNTERTOP must be 3..32767, according to datasheet, but 3 doesn't work. 4 does. + if (tentative_countertop <= 32767 && tentative_countertop >= 4) { + // In range, OK to return. + *countertop = tentative_countertop; + return true; + } + divisor *= 2; + } + + return false; +} + +// We store these in an array because we cannot compute them. +static IRQn_Type pwm_irqs[4] = {PWM0_IRQn, PWM1_IRQn, PWM2_IRQn, PWM3_IRQn}; + +NRF_PWM_Type *pwmout_allocate(uint16_t countertop, nrf_pwm_clk_t base_clock, + bool variable_frequency, int8_t *channel_out, bool *pwm_already_in_use_out, + IRQn_Type* irq) { + for (size_t pwm_index = 0; pwm_index < MP_ARRAY_SIZE(pwms); pwm_index++) { + NRF_PWM_Type *pwm = pwms[pwm_index]; + bool pwm_already_in_use = pwm->ENABLE & PWM_ENABLE_ENABLE_Msk; + if (pwm_already_in_use) { + if (variable_frequency) { + // Variable frequency requires exclusive use of a PWM, so try the next one. + continue; + } + + // PWM is in use, but see if it's set to the same frequency we need. If so, + // look for a free channel. + if (pwm->COUNTERTOP == countertop && pwm->PRESCALER == base_clock) { + for (size_t chan = 0; chan < CHANNELS_PER_PWM; chan++) { + if (pwm->PSEL.OUT[chan] == 0xFFFFFFFF) { + // Channel is free. + if (channel_out) { + *channel_out = chan; + } + if (pwm_already_in_use_out) { + *pwm_already_in_use_out = pwm_already_in_use; + } + if (irq) { + *irq = pwm_irqs[pwm_index]; + } + return pwm; + } + } + } + } else { + // PWM not yet in use, so we can start to use it. Use channel 0. + if (channel_out) { + *channel_out = 0; + } + if (pwm_already_in_use_out) { + *pwm_already_in_use_out = pwm_already_in_use; + } + if (irq) { + *irq = pwm_irqs[pwm_index]; + } + return pwm; + } + } + return NULL; +} + +void pwmout_free_channel(NRF_PWM_Type *pwm, int8_t channel) { + // Disconnect pin from channel. + pwm->PSEL.OUT[channel] = 0xFFFFFFFF; + + for(int i=0; i < CHANNELS_PER_PWM; i++) { + if (pwm->PSEL.OUT[i] != 0xFFFFFFFF) { + // Some channel is still being used, so don't disable. + return; + } + } + + nrf_pwm_disable(pwm); +} + +pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t* self, + const mcu_pin_obj_t* pin, + uint16_t duty, + uint32_t frequency, + bool variable_frequency) { + + // We don't use the nrfx driver here because we want to dynamically allocate channels + // as needed in an already-enabled PWM. + + uint16_t countertop; + nrf_pwm_clk_t base_clock; + if (frequency == 0 || !convert_frequency(frequency, &countertop, &base_clock)) { + return PWMOUT_INVALID_FREQUENCY; + } + + int8_t channel; + bool pwm_already_in_use; + self->pwm = pwmout_allocate(countertop, base_clock, variable_frequency, + &channel, &pwm_already_in_use, NULL); + + if (self->pwm == NULL) { + return PWMOUT_ALL_TIMERS_IN_USE; + } + + self->channel = channel; + self->pin_number = pin->number; + claim_pin(pin); + + self->frequency = frequency; + self->variable_frequency = variable_frequency; + + // Note this is standard, not strong drive. + nrf_gpio_cfg_output(self->pin_number); + + // disable before mapping pin channel + nrf_pwm_disable(self->pwm); + + if (!pwm_already_in_use) { + reset_single_pwmout(pwm_idx(self->pwm)); + nrf_pwm_configure(self->pwm, base_clock, NRF_PWM_MODE_UP, countertop); + } + + // Connect channel to pin, without disturbing other channels. + self->pwm->PSEL.OUT[self->channel] = pin->number; + + nrf_pwm_enable(self->pwm); + + common_hal_pwmio_pwmout_set_duty_cycle(self, duty); + return PWMOUT_OK; +} + +bool common_hal_pwmio_pwmout_deinited(pwmio_pwmout_obj_t* self) { + return self->pwm == NULL; +} + +void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t* self) { + if (common_hal_pwmio_pwmout_deinited(self)) { + return; + } + + nrf_gpio_cfg_default(self->pin_number); + + NRF_PWM_Type* pwm = self->pwm; + self->pwm = NULL; + + pwmout_free_channel(pwm, self->channel); + + reset_pin_number(self->pin_number); + self->pin_number = NO_PIN; +} + +void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t* self, uint16_t duty_cycle) { + self->duty_cycle = duty_cycle; + + uint16_t* p_value = ((uint16_t*)self->pwm->SEQ[0].PTR) + self->channel; + *p_value = ((duty_cycle * self->pwm->COUNTERTOP) / 0xFFFF) | (1 << 15); + + self->pwm->TASKS_SEQSTART[0] = 1; +} + +uint16_t common_hal_pwmio_pwmout_get_duty_cycle(pwmio_pwmout_obj_t* self) { + return self->duty_cycle; +} + +void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t* self, uint32_t frequency) { + // COUNTERTOP is 3..32767, so highest available frequency is PWM_MAX_FREQ / 3. + uint16_t countertop; + nrf_pwm_clk_t base_clock; + if (frequency == 0 || !convert_frequency(frequency, &countertop, &base_clock)) { + mp_raise_ValueError(translate("Invalid PWM frequency")); + } + self->frequency = frequency; + + nrf_pwm_configure(self->pwm, base_clock, NRF_PWM_MODE_UP, countertop); + // Set the duty cycle again, because it depends on COUNTERTOP, which probably changed. + // Setting the duty cycle will also do a SEQSTART. + common_hal_pwmio_pwmout_set_duty_cycle(self, self->duty_cycle); +} + +uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t* self) { + return self->frequency; +} + +bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t* self) { + return self->variable_frequency; +} diff --git a/ports/nrf/common-hal/pwmio/PWMOut.h b/ports/nrf/common-hal/pwmio/PWMOut.h new file mode 100644 index 000000000..e910baa76 --- /dev/null +++ b/ports/nrf/common-hal/pwmio/PWMOut.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * + * 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_NRF_COMMON_HAL_PWMIO_PWMOUT_H +#define MICROPY_INCLUDED_NRF_COMMON_HAL_PWMIO_PWMOUT_H + +#include "nrfx_pwm.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + NRF_PWM_Type* pwm; + uint8_t pin_number; + uint8_t channel: 7; + bool variable_frequency: 1; + uint16_t duty_cycle; + uint32_t frequency; +} pwmio_pwmout_obj_t; + +void pwmout_reset(void); +NRF_PWM_Type *pwmout_allocate(uint16_t countertop, nrf_pwm_clk_t base_clock, + bool variable_frequency, int8_t *channel_out, bool *pwm_already_in_use_out, + IRQn_Type *irq); +void pwmout_free_channel(NRF_PWM_Type *pwm, int8_t channel); + +#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_PWMIO_PWMOUT_H diff --git a/ports/nrf/common-hal/pwmio/__init__.c b/ports/nrf/common-hal/pwmio/__init__.c new file mode 100644 index 000000000..9e551a107 --- /dev/null +++ b/ports/nrf/common-hal/pwmio/__init__.c @@ -0,0 +1 @@ +// No pwmio module functions. diff --git a/ports/nrf/supervisor/port.c b/ports/nrf/supervisor/port.c index 87a4d7396..2945f244d 100644 --- a/ports/nrf/supervisor/port.c +++ b/ports/nrf/supervisor/port.c @@ -45,9 +45,9 @@ #include "common-hal/busio/I2C.h" #include "common-hal/busio/SPI.h" #include "common-hal/busio/UART.h" -#include "common-hal/pulseio/PWMOut.h" #include "common-hal/pulseio/PulseOut.h" #include "common-hal/pulseio/PulseIn.h" +#include "common-hal/pwmio/PWMOut.h" #include "common-hal/rtc/RTC.h" #include "common-hal/neopixel_write/__init__.h" #include "common-hal/watchdog/WatchDogTimer.h" @@ -196,11 +196,14 @@ void reset_port(void) { #if CIRCUITPY_PULSEIO - pwmout_reset(); pulseout_reset(); pulsein_reset(); #endif +#if CIRCUITPY_PWMIO + pwmout_reset(); +#endif + #if CIRCUITPY_RTC rtc_reset(); #endif diff --git a/ports/stm/common-hal/pulseio/PWMOut.c b/ports/stm/common-hal/pulseio/PWMOut.c deleted file mode 100644 index ddbadaf4c..000000000 --- a/ports/stm/common-hal/pulseio/PWMOut.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Lucian Copeland for Adafruit Industries - * Uses code from Micropython, Copyright (c) 2013-2016 Damien P. George - * - * 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 -#include "py/runtime.h" -#include "common-hal/pulseio/PWMOut.h" -#include "shared-bindings/pulseio/PWMOut.h" -#include "supervisor/shared/translate.h" - -#include "shared-bindings/microcontroller/__init__.h" -#include STM32_HAL_H -#include "shared-bindings/microcontroller/Pin.h" - -#include "timers.h" - -#define ALL_CLOCKS 0xFFFF - -STATIC uint8_t reserved_tim[TIM_BANK_ARRAY_LEN]; -STATIC uint32_t tim_frequencies[TIM_BANK_ARRAY_LEN]; -STATIC bool never_reset_tim[TIM_BANK_ARRAY_LEN]; - -STATIC uint32_t timer_get_internal_duty(uint16_t duty, uint32_t period) { - //duty cycle is duty/0xFFFF fraction x (number of pulses per period) - return (duty*period) / ((1 << 16) - 1); -} - -STATIC void timer_get_optimal_divisors(uint32_t*period, uint32_t*prescaler, - uint32_t frequency, uint32_t source_freq) { - //Find the largest possible period supported by this frequency - for (int i = 0; i < (1 << 16); i++) { - *period = source_freq / (i * frequency); - if (*period < (1 << 16) && *period >= 2) { - *prescaler = i; - break; - } - } - if (*prescaler == 0) { - mp_raise_ValueError(translate("Invalid frequency supplied")); - } -} - -void pwmout_reset(void) { - uint16_t never_reset_mask = 0x00; - for (int i = 0; i < TIM_BANK_ARRAY_LEN; i++) { - if (!never_reset_tim[i]) { - reserved_tim[i] = 0x00; - tim_frequencies[i] = 0x00; - } else { - never_reset_mask |= 1 << i; - } - } -} - -pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, - const mcu_pin_obj_t* pin, - uint16_t duty, - uint32_t frequency, - bool variable_frequency) { - TIM_TypeDef * TIMx; - uint8_t tim_num = MP_ARRAY_SIZE(mcu_tim_pin_list); - bool tim_taken_internal = false; - bool tim_chan_taken = false; - bool tim_taken_f_mismatch = false; - bool var_freq_mismatch = false; - bool first_time_setup = true; - - for (uint i = 0; i < tim_num; i++) { - const mcu_tim_pin_obj_t * l_tim = &mcu_tim_pin_list[i]; - uint8_t l_tim_index = l_tim->tim_index - 1; - uint8_t l_tim_channel = l_tim->channel_index - 1; - - //if pin is same - if (l_tim->pin == pin) { - //check if the timer has a channel active, or is reserved by main timer system - if (reserved_tim[l_tim_index] != 0) { - // Timer has already been reserved by an internal module - if (stm_peripherals_timer_is_reserved(mcu_tim_banks[l_tim_index])) { - tim_taken_internal = true; - continue; //keep looking - } - //is it the same channel? (or all channels reserved by a var-freq) - if (reserved_tim[l_tim_index] & 1 << (l_tim_channel)) { - tim_chan_taken = true; - continue; //keep looking, might be another viable option - } - //If the frequencies are the same it's ok - if (tim_frequencies[l_tim_index] != frequency) { - tim_taken_f_mismatch = true; - continue; //keep looking - } - //you can't put a variable frequency on a partially reserved timer - if (variable_frequency) { - var_freq_mismatch = true; - continue; //keep looking - } - first_time_setup = false; //skip setting up the timer - } - //No problems taken, so set it up - self->tim = l_tim; - break; - } - } - - //handle valid/invalid timer instance - if (self->tim != NULL) { - //create instance - TIMx = mcu_tim_banks[self->tim->tim_index - 1]; - //reserve timer/channel - if (variable_frequency) { - reserved_tim[self->tim->tim_index - 1] = 0x0F; - } else { - reserved_tim[self->tim->tim_index - 1] |= 1 << (self->tim->channel_index - 1); - } - tim_frequencies[self->tim->tim_index - 1] = frequency; - stm_peripherals_timer_reserve(TIMx); - } else { //no match found - if (tim_chan_taken) { - mp_raise_ValueError(translate("No more timers available on this pin.")); - } else if (tim_taken_internal) { - mp_raise_ValueError(translate("Timer was reserved for internal use - declare PWM pins earlier in the program")); - } else if (tim_taken_f_mismatch) { - mp_raise_ValueError(translate("Frequency must match existing PWMOut using this timer")); - } else if (var_freq_mismatch) { - mp_raise_ValueError(translate("Cannot vary frequency on a timer that is already in use")); - } else { - mp_raise_ValueError(translate("Invalid pins for PWMOut")); - } - } - - GPIO_InitTypeDef GPIO_InitStruct = {0}; - GPIO_InitStruct.Pin = pin_mask(pin->number); - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Alternate = self->tim->altfn_index; - HAL_GPIO_Init(pin_port(pin->port), &GPIO_InitStruct); - - tim_clock_enable(1 << (self->tim->tim_index - 1)); - - //translate channel into handle value - self->channel = 4 * (self->tim->channel_index - 1); - - uint32_t prescaler = 0; //prescaler is 15 bit - uint32_t period = 0; //period is 16 bit - uint32_t source_freq = stm_peripherals_timer_get_source_freq(TIMx); - timer_get_optimal_divisors(&period, &prescaler, frequency, source_freq); - - //Timer init - self->handle.Instance = TIMx; - self->handle.Init.Period = period - 1; - self->handle.Init.Prescaler = prescaler - 1; - self->handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; - self->handle.Init.CounterMode = TIM_COUNTERMODE_UP; - self->handle.Init.RepetitionCounter = 0; - - //only run init if this is the first instance of this timer - if (first_time_setup) { - if (HAL_TIM_PWM_Init(&self->handle) != HAL_OK) { - mp_raise_ValueError(translate("Could not initialize timer")); - } - } - - //Channel/PWM init - self->chan_handle.OCMode = TIM_OCMODE_PWM1; - self->chan_handle.Pulse = timer_get_internal_duty(duty, period); - self->chan_handle.OCPolarity = TIM_OCPOLARITY_HIGH; - self->chan_handle.OCFastMode = TIM_OCFAST_DISABLE; - if (HAL_TIM_PWM_ConfigChannel(&self->handle, &self->chan_handle, self->channel) != HAL_OK) { - mp_raise_ValueError(translate("Could not initialize channel")); - } - if (HAL_TIM_PWM_Start(&self->handle, self->channel) != HAL_OK) { - mp_raise_ValueError(translate("Could not start PWM")); - } - - self->variable_frequency = variable_frequency; - self->frequency = frequency; - self->duty_cycle = duty; - self->period = period; - - return PWMOUT_OK; -} - -void common_hal_pulseio_pwmout_never_reset(pulseio_pwmout_obj_t *self) { - for (size_t i = 0; i < TIM_BANK_ARRAY_LEN; i++) { - if (mcu_tim_banks[i] == self->handle.Instance) { - never_reset_tim[i] = true; - never_reset_pin_number(self->tim->pin->port, self->tim->pin->number); - break; - } - } -} - -void common_hal_pulseio_pwmout_reset_ok(pulseio_pwmout_obj_t *self) { - for(size_t i = 0; i < TIM_BANK_ARRAY_LEN; i++) { - if (mcu_tim_banks[i] == self->handle.Instance) { - never_reset_tim[i] = false; - break; - } - } -} - -bool common_hal_pulseio_pwmout_deinited(pulseio_pwmout_obj_t* self) { - return self->tim == NULL; -} - -void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) { - if (common_hal_pulseio_pwmout_deinited(self)) { - return; - } - //var freq shuts down entire timer, others just their channel - if (self->variable_frequency) { - reserved_tim[self->tim->tim_index - 1] = 0x00; - } else { - reserved_tim[self->tim->tim_index - 1] &= ~(1 << self->tim->channel_index); - HAL_TIM_PWM_Stop(&self->handle, self->channel); - } - reset_pin_number(self->tim->pin->port,self->tim->pin->number); - self->tim = NULL; - - //if reserved timer has no active channels, we can disable it - if (!reserved_tim[self->tim->tim_index - 1]) { - tim_frequencies[self->tim->tim_index - 1] = 0x00; - stm_peripherals_timer_free(self->handle.Instance); - } -} - -void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, uint16_t duty) { - uint32_t internal_duty_cycle = timer_get_internal_duty(duty, self->period); - __HAL_TIM_SET_COMPARE(&self->handle, self->channel, internal_duty_cycle); - self->duty_cycle = duty; -} - -uint16_t common_hal_pulseio_pwmout_get_duty_cycle(pulseio_pwmout_obj_t* self) { - return self->duty_cycle; -} - -void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self, uint32_t frequency) { - //don't halt setup for the same frequency - if (frequency == self->frequency) { - return; - } - - uint32_t prescaler = 0; - uint32_t period = 0; - uint32_t source_freq = stm_peripherals_timer_get_source_freq(self->handle.Instance); - timer_get_optimal_divisors(&period, &prescaler, frequency, source_freq); - - //shut down - HAL_TIM_PWM_Stop(&self->handle, self->channel); - - //Only change altered values - self->handle.Init.Period = period - 1; - self->handle.Init.Prescaler = prescaler - 1; - - //restart everything, adjusting for new speed - if (HAL_TIM_PWM_Init(&self->handle) != HAL_OK) { - mp_raise_ValueError(translate("Could not re-init timer")); - } - - self->chan_handle.Pulse = timer_get_internal_duty(self->duty_cycle, period); - - if (HAL_TIM_PWM_ConfigChannel(&self->handle, &self->chan_handle, self->channel) != HAL_OK) { - mp_raise_ValueError(translate("Could not re-init channel")); - } - if (HAL_TIM_PWM_Start(&self->handle, self->channel) != HAL_OK) { - mp_raise_ValueError(translate("Could not restart PWM")); - } - - tim_frequencies[self->tim->tim_index - 1] = frequency; - self->frequency = frequency; - self->period = period; -} - -uint32_t common_hal_pulseio_pwmout_get_frequency(pulseio_pwmout_obj_t* self) { - return self->frequency; -} - -bool common_hal_pulseio_pwmout_get_variable_frequency(pulseio_pwmout_obj_t* self) { - return self->variable_frequency; -} diff --git a/ports/stm/common-hal/pulseio/PWMOut.h b/ports/stm/common-hal/pulseio/PWMOut.h deleted file mode 100644 index 57ab143b9..000000000 --- a/ports/stm/common-hal/pulseio/PWMOut.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Lucian Copeland for Adafruit Industries - * - * 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_STM32F4_COMMON_HAL_PULSEIO_PWMOUT_H -#define MICROPY_INCLUDED_STM32F4_COMMON_HAL_PULSEIO_PWMOUT_H - -#include "common-hal/microcontroller/Pin.h" - -#include STM32_HAL_H -#include "peripherals/periph.h" - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - TIM_HandleTypeDef handle; - TIM_OC_InitTypeDef chan_handle; - const mcu_tim_pin_obj_t *tim; - uint8_t channel: 7; - bool variable_frequency: 1; - uint16_t duty_cycle; - uint32_t frequency; - uint32_t period; -} pulseio_pwmout_obj_t; - -void pwmout_reset(void); - -#endif // MICROPY_INCLUDED_STM32F4_COMMON_HAL_PULSEIO_PWMOUT_H diff --git a/ports/stm/common-hal/pulseio/PulseOut.c b/ports/stm/common-hal/pulseio/PulseOut.c index bcc25d817..fb48561d8 100644 --- a/ports/stm/common-hal/pulseio/PulseOut.c +++ b/ports/stm/common-hal/pulseio/PulseOut.c @@ -32,7 +32,7 @@ #include "py/gc.h" #include "py/runtime.h" #include "shared-bindings/pulseio/PulseOut.h" -#include "shared-bindings/pulseio/PWMOut.h" +#include "shared-bindings/pwmio/PWMOut.h" #include "supervisor/shared/translate.h" #include STM32_HAL_H @@ -113,7 +113,7 @@ void pulseout_reset() { } void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, - const pulseio_pwmout_obj_t* carrier) { + const pwmio_pwmout_obj_t* carrier) { // Add to active PulseOuts refcount++; TIM_TypeDef * tim_instance = stm_peripherals_find_timer(); @@ -135,7 +135,7 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, tim_handle.Instance->SR = 0; // The HAL can't work with const, recast required. - self->pwmout = (pulseio_pwmout_obj_t*)carrier; + self->pwmout = (pwmio_pwmout_obj_t*)carrier; turn_off(self); } diff --git a/ports/stm/common-hal/pulseio/PulseOut.h b/ports/stm/common-hal/pulseio/PulseOut.h index aa97396d0..29894f27d 100644 --- a/ports/stm/common-hal/pulseio/PulseOut.h +++ b/ports/stm/common-hal/pulseio/PulseOut.h @@ -28,13 +28,13 @@ #define MICROPY_INCLUDED_STM32F4_COMMON_HAL_PULSEIO_PULSEOUT_H #include "common-hal/microcontroller/Pin.h" -#include "common-hal/pulseio/PWMOut.h" +#include "common-hal/pwmio/PWMOut.h" #include "py/obj.h" typedef struct { mp_obj_base_t base; - pulseio_pwmout_obj_t *pwmout; + pwmio_pwmout_obj_t *pwmout; } pulseio_pulseout_obj_t; void pulseout_reset(void); diff --git a/ports/stm/common-hal/pwmio/PWMOut.c b/ports/stm/common-hal/pwmio/PWMOut.c new file mode 100644 index 000000000..065eb2a75 --- /dev/null +++ b/ports/stm/common-hal/pwmio/PWMOut.c @@ -0,0 +1,304 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Lucian Copeland for Adafruit Industries + * Uses code from Micropython, Copyright (c) 2013-2016 Damien P. George + * + * 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 +#include "py/runtime.h" +#include "common-hal/pwmio/PWMOut.h" +#include "shared-bindings/pwmio/PWMOut.h" +#include "supervisor/shared/translate.h" + +#include "shared-bindings/microcontroller/__init__.h" +#include STM32_HAL_H +#include "shared-bindings/microcontroller/Pin.h" + +#include "timers.h" + +#define ALL_CLOCKS 0xFFFF + +STATIC uint8_t reserved_tim[TIM_BANK_ARRAY_LEN]; +STATIC uint32_t tim_frequencies[TIM_BANK_ARRAY_LEN]; +STATIC bool never_reset_tim[TIM_BANK_ARRAY_LEN]; + +STATIC uint32_t timer_get_internal_duty(uint16_t duty, uint32_t period) { + //duty cycle is duty/0xFFFF fraction x (number of pulses per period) + return (duty*period) / ((1 << 16) - 1); +} + +STATIC void timer_get_optimal_divisors(uint32_t*period, uint32_t*prescaler, + uint32_t frequency, uint32_t source_freq) { + //Find the largest possible period supported by this frequency + for (int i = 0; i < (1 << 16); i++) { + *period = source_freq / (i * frequency); + if (*period < (1 << 16) && *period >= 2) { + *prescaler = i; + break; + } + } + if (*prescaler == 0) { + mp_raise_ValueError(translate("Invalid frequency supplied")); + } +} + +void pwmout_reset(void) { + uint16_t never_reset_mask = 0x00; + for (int i = 0; i < TIM_BANK_ARRAY_LEN; i++) { + if (!never_reset_tim[i]) { + reserved_tim[i] = 0x00; + tim_frequencies[i] = 0x00; + } else { + never_reset_mask |= 1 << i; + } + } +} + +pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t* self, + const mcu_pin_obj_t* pin, + uint16_t duty, + uint32_t frequency, + bool variable_frequency) { + TIM_TypeDef * TIMx; + uint8_t tim_num = MP_ARRAY_SIZE(mcu_tim_pin_list); + bool tim_taken_internal = false; + bool tim_chan_taken = false; + bool tim_taken_f_mismatch = false; + bool var_freq_mismatch = false; + bool first_time_setup = true; + + for (uint i = 0; i < tim_num; i++) { + const mcu_tim_pin_obj_t * l_tim = &mcu_tim_pin_list[i]; + uint8_t l_tim_index = l_tim->tim_index - 1; + uint8_t l_tim_channel = l_tim->channel_index - 1; + + //if pin is same + if (l_tim->pin == pin) { + //check if the timer has a channel active, or is reserved by main timer system + if (reserved_tim[l_tim_index] != 0) { + // Timer has already been reserved by an internal module + if (stm_peripherals_timer_is_reserved(mcu_tim_banks[l_tim_index])) { + tim_taken_internal = true; + continue; //keep looking + } + //is it the same channel? (or all channels reserved by a var-freq) + if (reserved_tim[l_tim_index] & 1 << (l_tim_channel)) { + tim_chan_taken = true; + continue; //keep looking, might be another viable option + } + //If the frequencies are the same it's ok + if (tim_frequencies[l_tim_index] != frequency) { + tim_taken_f_mismatch = true; + continue; //keep looking + } + //you can't put a variable frequency on a partially reserved timer + if (variable_frequency) { + var_freq_mismatch = true; + continue; //keep looking + } + first_time_setup = false; //skip setting up the timer + } + //No problems taken, so set it up + self->tim = l_tim; + break; + } + } + + //handle valid/invalid timer instance + if (self->tim != NULL) { + //create instance + TIMx = mcu_tim_banks[self->tim->tim_index - 1]; + //reserve timer/channel + if (variable_frequency) { + reserved_tim[self->tim->tim_index - 1] = 0x0F; + } else { + reserved_tim[self->tim->tim_index - 1] |= 1 << (self->tim->channel_index - 1); + } + tim_frequencies[self->tim->tim_index - 1] = frequency; + stm_peripherals_timer_reserve(TIMx); + } else { //no match found + if (tim_chan_taken) { + mp_raise_ValueError(translate("No more timers available on this pin.")); + } else if (tim_taken_internal) { + mp_raise_ValueError(translate("Timer was reserved for internal use - declare PWM pins earlier in the program")); + } else if (tim_taken_f_mismatch) { + mp_raise_ValueError(translate("Frequency must match existing PWMOut using this timer")); + } else if (var_freq_mismatch) { + mp_raise_ValueError(translate("Cannot vary frequency on a timer that is already in use")); + } else { + mp_raise_ValueError(translate("Invalid pins for PWMOut")); + } + } + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + GPIO_InitStruct.Pin = pin_mask(pin->number); + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = self->tim->altfn_index; + HAL_GPIO_Init(pin_port(pin->port), &GPIO_InitStruct); + + tim_clock_enable(1 << (self->tim->tim_index - 1)); + + //translate channel into handle value + self->channel = 4 * (self->tim->channel_index - 1); + + uint32_t prescaler = 0; //prescaler is 15 bit + uint32_t period = 0; //period is 16 bit + uint32_t source_freq = stm_peripherals_timer_get_source_freq(TIMx); + timer_get_optimal_divisors(&period, &prescaler, frequency, source_freq); + + //Timer init + self->handle.Instance = TIMx; + self->handle.Init.Period = period - 1; + self->handle.Init.Prescaler = prescaler - 1; + self->handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + self->handle.Init.CounterMode = TIM_COUNTERMODE_UP; + self->handle.Init.RepetitionCounter = 0; + + //only run init if this is the first instance of this timer + if (first_time_setup) { + if (HAL_TIM_PWM_Init(&self->handle) != HAL_OK) { + mp_raise_ValueError(translate("Could not initialize timer")); + } + } + + //Channel/PWM init + self->chan_handle.OCMode = TIM_OCMODE_PWM1; + self->chan_handle.Pulse = timer_get_internal_duty(duty, period); + self->chan_handle.OCPolarity = TIM_OCPOLARITY_HIGH; + self->chan_handle.OCFastMode = TIM_OCFAST_DISABLE; + if (HAL_TIM_PWM_ConfigChannel(&self->handle, &self->chan_handle, self->channel) != HAL_OK) { + mp_raise_ValueError(translate("Could not initialize channel")); + } + if (HAL_TIM_PWM_Start(&self->handle, self->channel) != HAL_OK) { + mp_raise_ValueError(translate("Could not start PWM")); + } + + self->variable_frequency = variable_frequency; + self->frequency = frequency; + self->duty_cycle = duty; + self->period = period; + + return PWMOUT_OK; +} + +void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self) { + for (size_t i = 0; i < TIM_BANK_ARRAY_LEN; i++) { + if (mcu_tim_banks[i] == self->handle.Instance) { + never_reset_tim[i] = true; + never_reset_pin_number(self->tim->pin->port, self->tim->pin->number); + break; + } + } +} + +void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self) { + for(size_t i = 0; i < TIM_BANK_ARRAY_LEN; i++) { + if (mcu_tim_banks[i] == self->handle.Instance) { + never_reset_tim[i] = false; + break; + } + } +} + +bool common_hal_pwmio_pwmout_deinited(pwmio_pwmout_obj_t* self) { + return self->tim == NULL; +} + +void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t* self) { + if (common_hal_pwmio_pwmout_deinited(self)) { + return; + } + //var freq shuts down entire timer, others just their channel + if (self->variable_frequency) { + reserved_tim[self->tim->tim_index - 1] = 0x00; + } else { + reserved_tim[self->tim->tim_index - 1] &= ~(1 << self->tim->channel_index); + HAL_TIM_PWM_Stop(&self->handle, self->channel); + } + reset_pin_number(self->tim->pin->port,self->tim->pin->number); + self->tim = NULL; + + //if reserved timer has no active channels, we can disable it + if (!reserved_tim[self->tim->tim_index - 1]) { + tim_frequencies[self->tim->tim_index - 1] = 0x00; + stm_peripherals_timer_free(self->handle.Instance); + } +} + +void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t* self, uint16_t duty) { + uint32_t internal_duty_cycle = timer_get_internal_duty(duty, self->period); + __HAL_TIM_SET_COMPARE(&self->handle, self->channel, internal_duty_cycle); + self->duty_cycle = duty; +} + +uint16_t common_hal_pwmio_pwmout_get_duty_cycle(pwmio_pwmout_obj_t* self) { + return self->duty_cycle; +} + +void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t* self, uint32_t frequency) { + //don't halt setup for the same frequency + if (frequency == self->frequency) { + return; + } + + uint32_t prescaler = 0; + uint32_t period = 0; + uint32_t source_freq = stm_peripherals_timer_get_source_freq(self->handle.Instance); + timer_get_optimal_divisors(&period, &prescaler, frequency, source_freq); + + //shut down + HAL_TIM_PWM_Stop(&self->handle, self->channel); + + //Only change altered values + self->handle.Init.Period = period - 1; + self->handle.Init.Prescaler = prescaler - 1; + + //restart everything, adjusting for new speed + if (HAL_TIM_PWM_Init(&self->handle) != HAL_OK) { + mp_raise_ValueError(translate("Could not re-init timer")); + } + + self->chan_handle.Pulse = timer_get_internal_duty(self->duty_cycle, period); + + if (HAL_TIM_PWM_ConfigChannel(&self->handle, &self->chan_handle, self->channel) != HAL_OK) { + mp_raise_ValueError(translate("Could not re-init channel")); + } + if (HAL_TIM_PWM_Start(&self->handle, self->channel) != HAL_OK) { + mp_raise_ValueError(translate("Could not restart PWM")); + } + + tim_frequencies[self->tim->tim_index - 1] = frequency; + self->frequency = frequency; + self->period = period; +} + +uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t* self) { + return self->frequency; +} + +bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t* self) { + return self->variable_frequency; +} diff --git a/ports/stm/common-hal/pwmio/PWMOut.h b/ports/stm/common-hal/pwmio/PWMOut.h new file mode 100644 index 000000000..5d8001202 --- /dev/null +++ b/ports/stm/common-hal/pwmio/PWMOut.h @@ -0,0 +1,51 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Lucian Copeland for Adafruit Industries + * + * 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_STM32F4_COMMON_HAL_PWMIO_PWMOUT_H +#define MICROPY_INCLUDED_STM32F4_COMMON_HAL_PWMIO_PWMOUT_H + +#include "common-hal/microcontroller/Pin.h" + +#include STM32_HAL_H +#include "peripherals/periph.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + TIM_HandleTypeDef handle; + TIM_OC_InitTypeDef chan_handle; + const mcu_tim_pin_obj_t *tim; + uint8_t channel: 7; + bool variable_frequency: 1; + uint16_t duty_cycle; + uint32_t frequency; + uint32_t period; +} pwmio_pwmout_obj_t; + +void pwmout_reset(void); + +#endif // MICROPY_INCLUDED_STM32F4_COMMON_HAL_PWMIO_PWMOUT_H diff --git a/ports/stm/common-hal/pwmio/__init__.c b/ports/stm/common-hal/pwmio/__init__.c new file mode 100644 index 000000000..9e551a107 --- /dev/null +++ b/ports/stm/common-hal/pwmio/__init__.c @@ -0,0 +1 @@ +// No pwmio module functions. diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index 5ce92f70a..e21105001 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -38,9 +38,13 @@ #include "common-hal/busio/UART.h" #endif #if CIRCUITPY_PULSEIO -#include "common-hal/pulseio/PWMOut.h" #include "common-hal/pulseio/PulseOut.h" #include "common-hal/pulseio/PulseIn.h" +#endif +#if CIRCUITPY_PWMIO +#include "common-hal/pwmio/PWMOut.h" +#endif +#if CIRCUITPY_PULSEIO || CIRCUITPY_PWMIO #include "timers.h" #endif #if CIRCUITPY_SDIOIO @@ -230,12 +234,16 @@ void reset_port(void) { #if CIRCUITPY_SDIOIO sdioio_reset(); #endif -#if CIRCUITPY_PULSEIO +#if CIRCUITPY_PULSEIO || CIRCUITPY_PWMIO timers_reset(); - pwmout_reset(); +#endif +#if CIRCUITPY_PULSEIO pulseout_reset(); pulsein_reset(); #endif +#if CIRCUITPY_PWMIO + pwmout_reset(); +#endif } void reset_to_bootloader(void) { diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index b70ae64a8..ab7a3af60 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -198,11 +198,14 @@ endif ifeq ($(CIRCUITPY_RGBMATRIX),1) SRC_PATTERNS += rgbmatrix/% endif +ifeq ($(CIRCUITPY_PS2IO),1) +SRC_PATTERNS += ps2io/% +endif ifeq ($(CIRCUITPY_PULSEIO),1) SRC_PATTERNS += pulseio/% endif -ifeq ($(CIRCUITPY_PS2IO),1) -SRC_PATTERNS += ps2io/% +ifeq ($(CIRCUITPY_PWMIO),1) +SRC_PATTERNS += pwmio/% endif ifeq ($(CIRCUITPY_RANDOM),1) SRC_PATTERNS += random/% @@ -316,10 +319,11 @@ SRC_COMMON_HAL_ALL = \ os/__init__.c \ ps2io/Ps2.c \ ps2io/__init__.c \ - pulseio/PWMOut.c \ pulseio/PulseIn.c \ pulseio/PulseOut.c \ pulseio/__init__.c \ + pwmio/PWMOut.c \ + pwmio/__init__.c \ rgbmatrix/RGBMatrix.c \ rgbmatrix/__init__.c \ rotaryio/IncrementalEncoder.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 12d667d8f..76b91defa 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -503,6 +503,13 @@ extern const struct _mp_obj_module_t pixelbuf_module; #define PIXELBUF_MODULE #endif +#if CIRCUITPY_PS2IO +extern const struct _mp_obj_module_t ps2io_module; +#define PS2IO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_ps2io), (mp_obj_t)&ps2io_module }, +#else +#define PS2IO_MODULE +#endif + #if CIRCUITPY_PULSEIO extern const struct _mp_obj_module_t pulseio_module; #define PULSEIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_pulseio), (mp_obj_t)&pulseio_module }, @@ -510,11 +517,11 @@ extern const struct _mp_obj_module_t pulseio_module; #define PULSEIO_MODULE #endif -#if CIRCUITPY_PS2IO -extern const struct _mp_obj_module_t ps2io_module; -#define PS2IO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_ps2io), (mp_obj_t)&ps2io_module }, +#if CIRCUITPY_PWMIO +extern const struct _mp_obj_module_t pwmio_module; +#define PWMIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_pwmio), (mp_obj_t)&pwmio_module }, #else -#define PS2IO_MODULE +#define PWMIO_MODULE #endif #if CIRCUITPY_RGBMATRIX @@ -740,6 +747,7 @@ extern const struct _mp_obj_module_t watchdog_module; PIXELBUF_MODULE \ PS2IO_MODULE \ PULSEIO_MODULE \ + PWMIO_MODULE \ RANDOM_MODULE \ RE_MODULE \ RGBMATRIX_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index bdc1e77d5..379c3850e 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -148,19 +148,24 @@ CFLAGS += -DCIRCUITPY_OS=$(CIRCUITPY_OS) CIRCUITPY_PIXELBUF ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_PIXELBUF=$(CIRCUITPY_PIXELBUF) -CIRCUITPY_RGBMATRIX ?= 0 -CFLAGS += -DCIRCUITPY_RGBMATRIX=$(CIRCUITPY_RGBMATRIX) +# Only for SAMD boards for the moment +CIRCUITPY_PS2IO ?= 0 +CFLAGS += -DCIRCUITPY_PS2IO=$(CIRCUITPY_PS2IO) CIRCUITPY_PULSEIO ?= 1 CFLAGS += -DCIRCUITPY_PULSEIO=$(CIRCUITPY_PULSEIO) -# Only for SAMD boards for the moment -CIRCUITPY_PS2IO ?= 0 -CFLAGS += -DCIRCUITPY_PS2IO=$(CIRCUITPY_PS2IO) +# For now we tie PWMIO to PULSEIO so they always both exist. In CircuitPython 7 +# we can enable and disable them separately once PWMOut is removed from `pulseio`. +CIRCUITPY_PWMIO = $(CIRCUITPY_PULSEIO) +CFLAGS += -DCIRCUITPY_PWMIO=$(CIRCUITPY_PWMIO) CIRCUITPY_RANDOM ?= 1 CFLAGS += -DCIRCUITPY_RANDOM=$(CIRCUITPY_RANDOM) +CIRCUITPY_RGBMATRIX ?= 0 +CFLAGS += -DCIRCUITPY_RGBMATRIX=$(CIRCUITPY_RGBMATRIX) + CIRCUITPY_ROTARYIO ?= 1 CFLAGS += -DCIRCUITPY_ROTARYIO=$(CIRCUITPY_ROTARYIO) diff --git a/shared-bindings/pulseio/PWMOut.c b/shared-bindings/pulseio/PWMOut.c deleted file mode 100644 index e9b6c45d2..000000000 --- a/shared-bindings/pulseio/PWMOut.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George - * - * 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 - -#include "lib/utils/context_manager_helpers.h" -#include "py/objproperty.h" -#include "py/runtime.h" - -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/pulseio/PWMOut.h" -#include "shared-bindings/util.h" -#include "supervisor/shared/translate.h" - -//| class PWMOut: -//| """Output a Pulse Width Modulated signal on a given pin.""" -//| -//| def __init__(self, pin: microcontroller.Pin, *, duty_cycle: int = 0, frequency: int = 500, variable_frequency: bool = False) -> None: -//| """Create a PWM object associated with the given pin. This allows you to -//| write PWM signals out on the given pin. Frequency is fixed after init -//| unless ``variable_frequency`` is True. -//| -//| .. note:: When ``variable_frequency`` is True, further PWM outputs may be -//| limited because it may take more internal resources to be flexible. So, -//| when outputting both fixed and flexible frequency signals construct the -//| fixed outputs first. -//| -//| :param ~microcontroller.Pin pin: The pin to output to -//| :param int duty_cycle: The fraction of each pulse which is high. 16-bit -//| :param int frequency: The target frequency in Hertz (32-bit) -//| :param bool variable_frequency: True if the frequency will change over time -//| -//| Simple LED fade:: -//| -//| import pulseio -//| import board -//| -//| pwm = pulseio.PWMOut(board.D13) # output on D13 -//| pwm.duty_cycle = 2 ** 15 # Cycles the pin with 50% duty cycle (half of 2 ** 16) at the default 500hz -//| -//| PWM at specific frequency (servos and motors):: -//| -//| import pulseio -//| import board -//| -//| pwm = pulseio.PWMOut(board.D13, frequency=50) -//| pwm.duty_cycle = 2 ** 15 # Cycles the pin with 50% duty cycle (half of 2 ** 16) at 50hz -//| -//| Variable frequency (usually tones):: -//| -//| import pulseio -//| import board -//| import time -//| -//| pwm = pulseio.PWMOut(board.D13, duty_cycle=2 ** 15, frequency=440, variable_frequency=True) -//| time.sleep(0.2) -//| pwm.frequency = 880 -//| time.sleep(0.1)""" -//| ... -//| -STATIC mp_obj_t pulseio_pwmout_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - enum { ARG_pin, ARG_duty_cycle, ARG_frequency, ARG_variable_frequency }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ, }, - { MP_QSTR_duty_cycle, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 500} }, - { MP_QSTR_variable_frequency, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - }; - mp_arg_val_t parsed_args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, parsed_args); - - const mcu_pin_obj_t *pin = validate_obj_is_free_pin(parsed_args[ARG_pin].u_obj); - - uint16_t duty_cycle = parsed_args[ARG_duty_cycle].u_int; - uint32_t frequency = parsed_args[ARG_frequency].u_int; - bool variable_frequency = parsed_args[ARG_variable_frequency].u_bool; - - // create PWM object from the given pin - pulseio_pwmout_obj_t *self = m_new_obj(pulseio_pwmout_obj_t); - self->base.type = &pulseio_pwmout_type; - pwmout_result_t result = common_hal_pulseio_pwmout_construct(self, pin, duty_cycle, frequency, variable_frequency); - if (result == PWMOUT_INVALID_PIN) { - mp_raise_ValueError(translate("Invalid pin")); - } else if (result == PWMOUT_INVALID_FREQUENCY) { - mp_raise_ValueError(translate("Invalid PWM frequency")); - } else if (result == PWMOUT_ALL_TIMERS_ON_PIN_IN_USE) { - mp_raise_ValueError(translate("All timers for this pin are in use")); - } else if (result == PWMOUT_ALL_TIMERS_IN_USE) { - mp_raise_RuntimeError(translate("All timers in use")); - } - - return MP_OBJ_FROM_PTR(self); -} - -//| def deinit(self) -> None: -//| """Deinitialises the PWMOut and releases any hardware resources for reuse.""" -//| ... -//| -STATIC mp_obj_t pulseio_pwmout_deinit(mp_obj_t self_in) { - pulseio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_pulseio_pwmout_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pwmout_deinit_obj, pulseio_pwmout_deinit); - -STATIC void check_for_deinit(pulseio_pwmout_obj_t *self) { - if (common_hal_pulseio_pwmout_deinited(self)) { - raise_deinited_error(); - } -} - -//| def __enter__(self) -> PWMOut: -//| """No-op used by Context Managers.""" -//| ... -//| -// Provided by context manager helper. - -//| def __exit__(self) -> None: -//| """Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info.""" -//| ... -//| -STATIC mp_obj_t pulseio_pwmout_obj___exit__(size_t n_args, const mp_obj_t *args) { - (void)n_args; - common_hal_pulseio_pwmout_deinit(args[0]); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pulseio_pwmout___exit___obj, 4, 4, pulseio_pwmout_obj___exit__); - -//| duty_cycle: int -//| """16 bit value that dictates how much of one cycle is high (1) versus low -//| (0). 0xffff will always be high, 0 will always be low and 0x7fff will -//| be half high and then half low. -//| -//| Depending on how PWM is implemented on a specific board, the internal -//| representation for duty cycle might have less than 16 bits of resolution. -//| Reading this property will return the value from the internal representation, -//| so it may differ from the value set.""" -//| -STATIC mp_obj_t pulseio_pwmout_obj_get_duty_cycle(mp_obj_t self_in) { - pulseio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_pulseio_pwmout_get_duty_cycle(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pwmout_get_duty_cycle_obj, pulseio_pwmout_obj_get_duty_cycle); - -STATIC mp_obj_t pulseio_pwmout_obj_set_duty_cycle(mp_obj_t self_in, mp_obj_t duty_cycle) { - pulseio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - mp_int_t duty = mp_obj_get_int(duty_cycle); - if (duty < 0 || duty > 0xffff) { - mp_raise_ValueError(translate("PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)")); - } - common_hal_pulseio_pwmout_set_duty_cycle(self, duty); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(pulseio_pwmout_set_duty_cycle_obj, pulseio_pwmout_obj_set_duty_cycle); - -const mp_obj_property_t pulseio_pwmout_duty_cycle_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&pulseio_pwmout_get_duty_cycle_obj, - (mp_obj_t)&pulseio_pwmout_set_duty_cycle_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| frequency: int -//| """32 bit value that dictates the PWM frequency in Hertz (cycles per -//| second). Only writeable when constructed with ``variable_frequency=True``. -//| -//| Depending on how PWM is implemented on a specific board, the internal value -//| for the PWM's duty cycle may need to be recalculated when the frequency -//| changes. In these cases, the duty cycle is automatically recalculated -//| from the original duty cycle value. This should happen without any need -//| to manually re-set the duty cycle.""" -//| -STATIC mp_obj_t pulseio_pwmout_obj_get_frequency(mp_obj_t self_in) { - pulseio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_pulseio_pwmout_get_frequency(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(pulseio_pwmout_get_frequency_obj, pulseio_pwmout_obj_get_frequency); - -STATIC mp_obj_t pulseio_pwmout_obj_set_frequency(mp_obj_t self_in, mp_obj_t frequency) { - pulseio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - if (!common_hal_pulseio_pwmout_get_variable_frequency(self)) { - mp_raise_AttributeError(translate( - "PWM frequency not writable when variable_frequency is False on " - "construction.")); - } - common_hal_pulseio_pwmout_set_frequency(self, mp_obj_get_int(frequency)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(pulseio_pwmout_set_frequency_obj, pulseio_pwmout_obj_set_frequency); - -const mp_obj_property_t pulseio_pwmout_frequency_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&pulseio_pwmout_get_frequency_obj, - (mp_obj_t)&pulseio_pwmout_set_frequency_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -STATIC const mp_rom_map_elem_t pulseio_pwmout_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pulseio_pwmout_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&pulseio_pwmout___exit___obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_duty_cycle), MP_ROM_PTR(&pulseio_pwmout_duty_cycle_obj) }, - { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&pulseio_pwmout_frequency_obj) }, - // TODO(tannewt): Add enabled to determine whether the signal is output - // without giving up the resources. Useful for IR output. -}; -STATIC MP_DEFINE_CONST_DICT(pulseio_pwmout_locals_dict, pulseio_pwmout_locals_dict_table); - -const mp_obj_type_t pulseio_pwmout_type = { - { &mp_type_type }, - .name = MP_QSTR_PWMOut, - .make_new = pulseio_pwmout_make_new, - .locals_dict = (mp_obj_dict_t*)&pulseio_pwmout_locals_dict, -}; diff --git a/shared-bindings/pulseio/PWMOut.h b/shared-bindings/pulseio/PWMOut.h deleted file mode 100644 index c72278e0e..000000000 --- a/shared-bindings/pulseio/PWMOut.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George - * - * 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_SHARED_BINDINGS_PULSEIO_PWMOUT_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_PULSEIO_PWMOUT_H - -#include "common-hal/microcontroller/Pin.h" -#include "common-hal/pulseio/PWMOut.h" - -extern const mp_obj_type_t pulseio_pwmout_type; - -typedef enum { - PWMOUT_OK, - PWMOUT_INVALID_PIN, - PWMOUT_INVALID_FREQUENCY, - PWMOUT_ALL_TIMERS_ON_PIN_IN_USE, - PWMOUT_ALL_TIMERS_IN_USE -} pwmout_result_t; - -extern pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self, - const mcu_pin_obj_t* pin, uint16_t duty, uint32_t frequency, - bool variable_frequency); -extern void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self); -extern bool common_hal_pulseio_pwmout_deinited(pulseio_pwmout_obj_t* self); -extern void common_hal_pulseio_pwmout_set_duty_cycle(pulseio_pwmout_obj_t* self, uint16_t duty); -extern uint16_t common_hal_pulseio_pwmout_get_duty_cycle(pulseio_pwmout_obj_t* self); -extern void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self, uint32_t frequency); -extern uint32_t common_hal_pulseio_pwmout_get_frequency(pulseio_pwmout_obj_t* self); -extern bool common_hal_pulseio_pwmout_get_variable_frequency(pulseio_pwmout_obj_t* self); - -// This is used by the supervisor to claim PWMOut devices indefinitely. -extern void common_hal_pulseio_pwmout_never_reset(pulseio_pwmout_obj_t *self); -extern void common_hal_pulseio_pwmout_reset_ok(pulseio_pwmout_obj_t *self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PULSEIO_PWMOUT_H diff --git a/shared-bindings/pulseio/PulseOut.c b/shared-bindings/pulseio/PulseOut.c index 3d35f0544..024ee613c 100644 --- a/shared-bindings/pulseio/PulseOut.c +++ b/shared-bindings/pulseio/PulseOut.c @@ -32,7 +32,7 @@ #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/pulseio/PulseOut.h" -#include "shared-bindings/pulseio/PWMOut.h" +#include "shared-bindings/pwmio/PWMOut.h" #include "shared-bindings/util.h" #include "supervisor/shared/translate.h" @@ -41,19 +41,20 @@ //| pulsed signal consists of timed on and off periods. Unlike PWM, there is no set duration //| for on and off pairs.""" //| -//| def __init__(self, carrier: PWMOut) -> None: +//| def __init__(self, carrier: pwmio.PWMOut) -> None: //| """Create a PulseOut object associated with the given PWMout object. //| -//| :param ~pulseio.PWMOut carrier: PWMOut that is set to output on the desired pin. +//| :param ~pwmio.PWMOut carrier: PWMOut that is set to output on the desired pin. //| //| Send a short series of pulses:: //| //| import array //| import pulseio +//| import pwmio //| import board //| //| # 50% duty cycle at 38kHz. -//| pwm = pulseio.PWMOut(board.D13, frequency=38000, duty_cycle=32768) +//| pwm = pwmio.PWMOut(board.D13, frequency=38000, duty_cycle=32768) //| pulse = pulseio.PulseOut(pwm) //| # on off on off on //| pulses = array.array('H', [65000, 1000, 65000, 65000, 1000]) @@ -68,15 +69,15 @@ STATIC mp_obj_t pulseio_pulseout_make_new(const mp_obj_type_t *type, size_t n_ar mp_arg_check_num(n_args, kw_args, 1, 1, false); mp_obj_t carrier_obj = args[0]; - if (!MP_OBJ_IS_TYPE(carrier_obj, &pulseio_pwmout_type)) { - mp_raise_TypeError_varg(translate("Expected a %q"), pulseio_pwmout_type.name); + if (!MP_OBJ_IS_TYPE(carrier_obj, &pwmio_pwmout_type)) { + mp_raise_TypeError_varg(translate("Expected a %q"), pwmio_pwmout_type.name); } // create Pulse object from the given pin pulseio_pulseout_obj_t *self = m_new_obj(pulseio_pulseout_obj_t); self->base.type = &pulseio_pulseout_type; - common_hal_pulseio_pulseout_construct(self, (pulseio_pwmout_obj_t *)MP_OBJ_TO_PTR(carrier_obj)); + common_hal_pulseio_pulseout_construct(self, (pwmio_pwmout_obj_t *)MP_OBJ_TO_PTR(carrier_obj)); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/pulseio/PulseOut.h b/shared-bindings/pulseio/PulseOut.h index 390910ff6..80dd0e92f 100644 --- a/shared-bindings/pulseio/PulseOut.h +++ b/shared-bindings/pulseio/PulseOut.h @@ -29,12 +29,12 @@ #include "common-hal/microcontroller/Pin.h" #include "common-hal/pulseio/PulseOut.h" -#include "common-hal/pulseio/PWMOut.h" +#include "common-hal/pwmio/PWMOut.h" extern const mp_obj_type_t pulseio_pulseout_type; extern void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self, - const pulseio_pwmout_obj_t* carrier); + const pwmio_pwmout_obj_t* carrier); extern void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self); extern bool common_hal_pulseio_pulseout_deinited(pulseio_pulseout_obj_t* self); extern void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, diff --git a/shared-bindings/pulseio/__init__.c b/shared-bindings/pulseio/__init__.c index 87946e5f0..efef64043 100644 --- a/shared-bindings/pulseio/__init__.c +++ b/shared-bindings/pulseio/__init__.c @@ -33,40 +33,29 @@ #include "shared-bindings/pulseio/__init__.h" #include "shared-bindings/pulseio/PulseIn.h" #include "shared-bindings/pulseio/PulseOut.h" -#include "shared-bindings/pulseio/PWMOut.h" +#include "shared-bindings/pwmio/PWMOut.h" -//| """Support for pulse based protocols +//| """Support for individual pulse based protocols //| //| The `pulseio` module contains classes to provide access to basic pulse IO. +//| Individual pulses are commonly used in infrared remotes and in DHT +//| temperature sensors. //| +//| .. warning:: PWMOut is moving to `pwmio` and will be removed from `pulseio` +//| in CircuitPython 7. + //| All classes change hardware state and should be deinitialized when they //| are no longer needed if the program continues after use. To do so, either //| call :py:meth:`!deinit` or use a context manager. See //| :ref:`lifetime-and-contextmanagers` for more info. //| -//| For example:: -//| -//| import pulseio -//| import time -//| from board import * -//| -//| pwm = pulseio.PWMOut(D13) -//| pwm.duty_cycle = 2 ** 15 -//| time.sleep(0.1) -//| -//| This example will initialize the the device, set -//| :py:data:`~pulseio.PWMOut.duty_cycle`, and then sleep 0.1 seconds. -//| CircuitPython will automatically turn off the PWM when it resets all -//| hardware after program completion. Use ``deinit()`` or a ``with`` statement -//| to do it yourself.""" -//| STATIC const mp_rom_map_elem_t pulseio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pulseio) }, { MP_ROM_QSTR(MP_QSTR_PulseIn), MP_ROM_PTR(&pulseio_pulsein_type) }, { MP_ROM_QSTR(MP_QSTR_PulseOut), MP_ROM_PTR(&pulseio_pulseout_type) }, - { MP_ROM_QSTR(MP_QSTR_PWMOut), MP_ROM_PTR(&pulseio_pwmout_type) }, + { MP_ROM_QSTR(MP_QSTR_PWMOut), MP_ROM_PTR(&pwmio_pwmout_type) }, }; STATIC MP_DEFINE_CONST_DICT(pulseio_module_globals, pulseio_module_globals_table); diff --git a/shared-bindings/pwmio/PWMOut.c b/shared-bindings/pwmio/PWMOut.c new file mode 100644 index 000000000..da0755592 --- /dev/null +++ b/shared-bindings/pwmio/PWMOut.c @@ -0,0 +1,245 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George + * + * 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 + +#include "lib/utils/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/pwmio/PWMOut.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/translate.h" + +//| class PWMOut: +//| """Output a Pulse Width Modulated signal on a given pin.""" +//| +//| def __init__(self, pin: microcontroller.Pin, *, duty_cycle: int = 0, frequency: int = 500, variable_frequency: bool = False) -> None: +//| """Create a PWM object associated with the given pin. This allows you to +//| write PWM signals out on the given pin. Frequency is fixed after init +//| unless ``variable_frequency`` is True. +//| +//| .. note:: When ``variable_frequency`` is True, further PWM outputs may be +//| limited because it may take more internal resources to be flexible. So, +//| when outputting both fixed and flexible frequency signals construct the +//| fixed outputs first. +//| +//| :param ~microcontroller.Pin pin: The pin to output to +//| :param int duty_cycle: The fraction of each pulse which is high. 16-bit +//| :param int frequency: The target frequency in Hertz (32-bit) +//| :param bool variable_frequency: True if the frequency will change over time +//| +//| Simple LED fade:: +//| +//| import pwmio +//| import board +//| +//| pwm = pwmio.PWMOut(board.D13) # output on D13 +//| pwm.duty_cycle = 2 ** 15 # Cycles the pin with 50% duty cycle (half of 2 ** 16) at the default 500hz +//| +//| PWM at specific frequency (servos and motors):: +//| +//| import pwmio +//| import board +//| +//| pwm = pwmio.PWMOut(board.D13, frequency=50) +//| pwm.duty_cycle = 2 ** 15 # Cycles the pin with 50% duty cycle (half of 2 ** 16) at 50hz +//| +//| Variable frequency (usually tones):: +//| +//| import pwmio +//| import board +//| import time +//| +//| pwm = pwmio.PWMOut(board.D13, duty_cycle=2 ** 15, frequency=440, variable_frequency=True) +//| time.sleep(0.2) +//| pwm.frequency = 880 +//| time.sleep(0.1)""" +//| ... +//| +STATIC mp_obj_t pwmio_pwmout_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + enum { ARG_pin, ARG_duty_cycle, ARG_frequency, ARG_variable_frequency }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ, }, + { MP_QSTR_duty_cycle, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 500} }, + { MP_QSTR_variable_frequency, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t parsed_args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, parsed_args); + + const mcu_pin_obj_t *pin = validate_obj_is_free_pin(parsed_args[ARG_pin].u_obj); + + uint16_t duty_cycle = parsed_args[ARG_duty_cycle].u_int; + uint32_t frequency = parsed_args[ARG_frequency].u_int; + bool variable_frequency = parsed_args[ARG_variable_frequency].u_bool; + + // create PWM object from the given pin + pwmio_pwmout_obj_t *self = m_new_obj(pwmio_pwmout_obj_t); + self->base.type = &pwmio_pwmout_type; + pwmout_result_t result = common_hal_pwmio_pwmout_construct(self, pin, duty_cycle, frequency, variable_frequency); + if (result == PWMOUT_INVALID_PIN) { + mp_raise_ValueError(translate("Invalid pin")); + } else if (result == PWMOUT_INVALID_FREQUENCY) { + mp_raise_ValueError(translate("Invalid PWM frequency")); + } else if (result == PWMOUT_ALL_TIMERS_ON_PIN_IN_USE) { + mp_raise_ValueError(translate("All timers for this pin are in use")); + } else if (result == PWMOUT_ALL_TIMERS_IN_USE) { + mp_raise_RuntimeError(translate("All timers in use")); + } + + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Deinitialises the PWMOut and releases any hardware resources for reuse.""" +//| ... +//| +STATIC mp_obj_t pwmio_pwmout_deinit(mp_obj_t self_in) { + pwmio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_pwmio_pwmout_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(pwmio_pwmout_deinit_obj, pwmio_pwmout_deinit); + +STATIC void check_for_deinit(pwmio_pwmout_obj_t *self) { + if (common_hal_pwmio_pwmout_deinited(self)) { + raise_deinited_error(); + } +} + +//| def __enter__(self) -> PWMOut: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t pwmio_pwmout_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_pwmio_pwmout_deinit(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pwmio_pwmout___exit___obj, 4, 4, pwmio_pwmout_obj___exit__); + +//| duty_cycle: int +//| """16 bit value that dictates how much of one cycle is high (1) versus low +//| (0). 0xffff will always be high, 0 will always be low and 0x7fff will +//| be half high and then half low. +//| +//| Depending on how PWM is implemented on a specific board, the internal +//| representation for duty cycle might have less than 16 bits of resolution. +//| Reading this property will return the value from the internal representation, +//| so it may differ from the value set.""" +//| +STATIC mp_obj_t pwmio_pwmout_obj_get_duty_cycle(mp_obj_t self_in) { + pwmio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_pwmio_pwmout_get_duty_cycle(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(pwmio_pwmout_get_duty_cycle_obj, pwmio_pwmout_obj_get_duty_cycle); + +STATIC mp_obj_t pwmio_pwmout_obj_set_duty_cycle(mp_obj_t self_in, mp_obj_t duty_cycle) { + pwmio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + mp_int_t duty = mp_obj_get_int(duty_cycle); + if (duty < 0 || duty > 0xffff) { + mp_raise_ValueError(translate("PWM duty_cycle must be between 0 and 65535 inclusive (16 bit resolution)")); + } + common_hal_pwmio_pwmout_set_duty_cycle(self, duty); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(pwmio_pwmout_set_duty_cycle_obj, pwmio_pwmout_obj_set_duty_cycle); + +const mp_obj_property_t pwmio_pwmout_duty_cycle_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&pwmio_pwmout_get_duty_cycle_obj, + (mp_obj_t)&pwmio_pwmout_set_duty_cycle_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| frequency: int +//| """32 bit value that dictates the PWM frequency in Hertz (cycles per +//| second). Only writeable when constructed with ``variable_frequency=True``. +//| +//| Depending on how PWM is implemented on a specific board, the internal value +//| for the PWM's duty cycle may need to be recalculated when the frequency +//| changes. In these cases, the duty cycle is automatically recalculated +//| from the original duty cycle value. This should happen without any need +//| to manually re-set the duty cycle.""" +//| +STATIC mp_obj_t pwmio_pwmout_obj_get_frequency(mp_obj_t self_in) { + pwmio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_pwmio_pwmout_get_frequency(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(pwmio_pwmout_get_frequency_obj, pwmio_pwmout_obj_get_frequency); + +STATIC mp_obj_t pwmio_pwmout_obj_set_frequency(mp_obj_t self_in, mp_obj_t frequency) { + pwmio_pwmout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (!common_hal_pwmio_pwmout_get_variable_frequency(self)) { + mp_raise_AttributeError(translate( + "PWM frequency not writable when variable_frequency is False on " + "construction.")); + } + common_hal_pwmio_pwmout_set_frequency(self, mp_obj_get_int(frequency)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(pwmio_pwmout_set_frequency_obj, pwmio_pwmout_obj_set_frequency); + +const mp_obj_property_t pwmio_pwmout_frequency_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&pwmio_pwmout_get_frequency_obj, + (mp_obj_t)&pwmio_pwmout_set_frequency_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t pwmio_pwmout_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pwmio_pwmout_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&pwmio_pwmout___exit___obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_duty_cycle), MP_ROM_PTR(&pwmio_pwmout_duty_cycle_obj) }, + { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&pwmio_pwmout_frequency_obj) }, + // TODO(tannewt): Add enabled to determine whether the signal is output + // without giving up the resources. Useful for IR output. +}; +STATIC MP_DEFINE_CONST_DICT(pwmio_pwmout_locals_dict, pwmio_pwmout_locals_dict_table); + +const mp_obj_type_t pwmio_pwmout_type = { + { &mp_type_type }, + .name = MP_QSTR_PWMOut, + .make_new = pwmio_pwmout_make_new, + .locals_dict = (mp_obj_dict_t*)&pwmio_pwmout_locals_dict, +}; diff --git a/shared-bindings/pwmio/PWMOut.h b/shared-bindings/pwmio/PWMOut.h new file mode 100644 index 000000000..1a99914ea --- /dev/null +++ b/shared-bindings/pwmio/PWMOut.h @@ -0,0 +1,58 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * SPDX-FileCopyrightText: Copyright (c) 2013, 2014 Damien P. George + * + * 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_SHARED_BINDINGS_PWMIO_PWMOUT_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_PWMIO_PWMOUT_H + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/pwmio/PWMOut.h" + +extern const mp_obj_type_t pwmio_pwmout_type; + +typedef enum { + PWMOUT_OK, + PWMOUT_INVALID_PIN, + PWMOUT_INVALID_FREQUENCY, + PWMOUT_ALL_TIMERS_ON_PIN_IN_USE, + PWMOUT_ALL_TIMERS_IN_USE +} pwmout_result_t; + +extern pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t* self, + const mcu_pin_obj_t* pin, uint16_t duty, uint32_t frequency, + bool variable_frequency); +extern void common_hal_pwmio_pwmout_deinit(pwmio_pwmout_obj_t* self); +extern bool common_hal_pwmio_pwmout_deinited(pwmio_pwmout_obj_t* self); +extern void common_hal_pwmio_pwmout_set_duty_cycle(pwmio_pwmout_obj_t* self, uint16_t duty); +extern uint16_t common_hal_pwmio_pwmout_get_duty_cycle(pwmio_pwmout_obj_t* self); +extern void common_hal_pwmio_pwmout_set_frequency(pwmio_pwmout_obj_t* self, uint32_t frequency); +extern uint32_t common_hal_pwmio_pwmout_get_frequency(pwmio_pwmout_obj_t* self); +extern bool common_hal_pwmio_pwmout_get_variable_frequency(pwmio_pwmout_obj_t* self); + +// This is used by the supervisor to claim PWMOut devices indefinitely. +extern void common_hal_pwmio_pwmout_never_reset(pwmio_pwmout_obj_t *self); +extern void common_hal_pwmio_pwmout_reset_ok(pwmio_pwmout_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PWMIO_PWMOUT_H diff --git a/shared-bindings/pwmio/__init__.c b/shared-bindings/pwmio/__init__.c new file mode 100644 index 000000000..a51383703 --- /dev/null +++ b/shared-bindings/pwmio/__init__.c @@ -0,0 +1,73 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries + * + * 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 + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/pwmio/__init__.h" +#include "shared-bindings/pwmio/PWMOut.h" + +//| """Support for PWM based protocols +//| +//| The `pwmio` module contains classes to provide access to basic pulse IO. +//| + +//| All classes change hardware state and should be deinitialized when they +//| are no longer needed if the program continues after use. To do so, either +//| call :py:meth:`!deinit` or use a context manager. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +//| For example:: +//| +//| import pwmio +//| import time +//| from board import * +//| +//| pwm = pwmio.PWMOut(D13) +//| pwm.duty_cycle = 2 ** 15 +//| time.sleep(0.1) +//| +//| This example will initialize the the device, set +//| :py:data:`~pwmio.PWMOut.duty_cycle`, and then sleep 0.1 seconds. +//| CircuitPython will automatically turn off the PWM when it resets all +//| hardware after program completion. Use ``deinit()`` or a ``with`` statement +//| to do it yourself.""" +//| + +STATIC const mp_rom_map_elem_t pwmio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_pwmio) }, + { MP_ROM_QSTR(MP_QSTR_PWMOut), MP_ROM_PTR(&pwmio_pwmout_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(pwmio_module_globals, pwmio_module_globals_table); + +const mp_obj_module_t pwmio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&pwmio_module_globals, +}; diff --git a/shared-bindings/pwmio/__init__.h b/shared-bindings/pwmio/__init__.h new file mode 100644 index 000000000..93c70377d --- /dev/null +++ b/shared-bindings/pwmio/__init__.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * 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_SHARED_BINDINGS_PWMIO___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_PWMIO___INIT___H + +#include "py/obj.h" + +// Nothing now. + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_PWMIO___INIT___H diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 46bb6fdb5..4f92f249f 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -111,14 +111,14 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, if (backlight_pin != NULL && common_hal_mcu_pin_is_free(backlight_pin)) { // Avoid PWM types and functions when the module isn't enabled #if (CIRCUITPY_PULSEIO) - pwmout_result_t result = common_hal_pulseio_pwmout_construct(&self->backlight_pwm, backlight_pin, 0, 50000, false); + pwmout_result_t result = common_hal_pwmio_pwmout_construct(&self->backlight_pwm, backlight_pin, 0, 50000, false); if (result != PWMOUT_OK) { self->backlight_inout.base.type = &digitalio_digitalinout_type; common_hal_digitalio_digitalinout_construct(&self->backlight_inout, backlight_pin); common_hal_never_reset_pin(backlight_pin); } else { - self->backlight_pwm.base.type = &pulseio_pwmout_type; - common_hal_pulseio_pwmout_never_reset(&self->backlight_pwm); + self->backlight_pwm.base.type = &pwmio_pwmout_type; + common_hal_pwmio_pwmout_never_reset(&self->backlight_pwm); } #else // Otherwise default to digital @@ -173,14 +173,14 @@ bool common_hal_displayio_display_set_brightness(displayio_display_obj_t* self, // Avoid PWM types and functions when the module isn't enabled #if (CIRCUITPY_PULSEIO) - bool ispwm = (self->backlight_pwm.base.type == &pulseio_pwmout_type) ? true : false; + bool ispwm = (self->backlight_pwm.base.type == &pwmio_pwmout_type) ? true : false; #else bool ispwm = false; #endif if (ispwm) { #if (CIRCUITPY_PULSEIO) - common_hal_pulseio_pwmout_set_duty_cycle(&self->backlight_pwm, (uint16_t) (0xffff * brightness)); + common_hal_pwmio_pwmout_set_duty_cycle(&self->backlight_pwm, (uint16_t) (0xffff * brightness)); ok = true; #else ok = false; @@ -419,9 +419,9 @@ void release_display(displayio_display_obj_t* self) { common_hal_displayio_display_set_auto_refresh(self, false); release_display_core(&self->core); #if (CIRCUITPY_PULSEIO) - if (self->backlight_pwm.base.type == &pulseio_pwmout_type) { - common_hal_pulseio_pwmout_reset_ok(&self->backlight_pwm); - common_hal_pulseio_pwmout_deinit(&self->backlight_pwm); + if (self->backlight_pwm.base.type == &pwmio_pwmout_type) { + common_hal_pwmio_pwmout_reset_ok(&self->backlight_pwm); + common_hal_pwmio_pwmout_deinit(&self->backlight_pwm); } else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { common_hal_digitalio_digitalinout_deinit(&self->backlight_inout); } diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index 861a38fd7..bdb861aa0 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -29,8 +29,8 @@ #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/displayio/Group.h" -#if CIRCUITPY_PULSEIO -#include "shared-bindings/pulseio/PWMOut.h" +#if CIRCUITPY_PWMIO +#include "shared-bindings/pwmio/PWMOut.h" #endif #include "shared-module/displayio/area.h" @@ -41,8 +41,8 @@ typedef struct { displayio_display_core_t core; union { digitalio_digitalinout_obj_t backlight_inout; - #if CIRCUITPY_PULSEIO - pulseio_pwmout_obj_t backlight_pwm; + #if CIRCUITPY_PWMIO + pwmio_pwmout_obj_t backlight_pwm; #endif }; uint64_t last_backlight_refresh; diff --git a/shared-module/framebufferio/FramebufferDisplay.h b/shared-module/framebufferio/FramebufferDisplay.h index 89df0d27c..d73d4b9a9 100644 --- a/shared-module/framebufferio/FramebufferDisplay.h +++ b/shared-module/framebufferio/FramebufferDisplay.h @@ -33,7 +33,6 @@ #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/displayio/Group.h" -#include "shared-bindings/pulseio/PWMOut.h" #include "shared-module/displayio/area.h" #include "shared-module/displayio/display_core.h" -- cgit v1.2.3 From 8bab7b664c9627dfbaa32b3bf64893d7487f1cd0 Mon Sep 17 00:00:00 2001 From: Yihui Xiong Date: Wed, 19 Aug 2020 20:18:17 +0800 Subject: support to get HID OUT report --- shared-bindings/usb_hid/Device.c | 20 ++++++++++++++++++++ shared-module/usb_hid/Device.c | 17 ++++++++++------- shared-module/usb_hid/Device.h | 2 ++ tools/gen_usb_descriptor.py | 16 +++++++++++++--- tools/hid_report_descriptors.py | 18 +++++++++--------- 5 files changed, 54 insertions(+), 19 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/usb_hid/Device.c b/shared-bindings/usb_hid/Device.c index 83c0df4ae..2fbc5fe51 100644 --- a/shared-bindings/usb_hid/Device.c +++ b/shared-bindings/usb_hid/Device.c @@ -58,6 +58,25 @@ STATIC mp_obj_t usb_hid_device_send_report(mp_obj_t self_in, mp_obj_t buffer) { } MP_DEFINE_CONST_FUN_OBJ_2(usb_hid_device_send_report_obj, usb_hid_device_send_report); +//|report: bytes +//| """The HID OUT report as a `bytes`. (read-only)""" +//| +STATIC mp_obj_t usb_hid_device_obj_get_report(mp_obj_t self_in) { + usb_hid_device_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->out_report_buffer == 0) { + return mp_const_none; + } + return mp_obj_new_bytes(self->out_report_buffer, self->out_report_length); +} +MP_DEFINE_CONST_FUN_OBJ_1(usb_hid_device_get_report_obj, usb_hid_device_obj_get_report); + +const mp_obj_property_t usb_hid_device_report_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&usb_hid_device_get_report_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + //| usage_page: int //| """The usage page of the device as an `int`. Can be thought of a category. (read-only)""" //| @@ -96,6 +115,7 @@ const mp_obj_property_t usb_hid_device_usage_obj = { STATIC const mp_rom_map_elem_t usb_hid_device_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_send_report), MP_ROM_PTR(&usb_hid_device_send_report_obj) }, + { MP_ROM_QSTR(MP_QSTR_report), MP_ROM_PTR(&usb_hid_device_report_obj) }, { MP_ROM_QSTR(MP_QSTR_usage_page), MP_ROM_PTR(&usb_hid_device_usage_page_obj)}, { MP_ROM_QSTR(MP_QSTR_usage), MP_ROM_PTR(&usb_hid_device_usage_obj)}, }; diff --git a/shared-module/usb_hid/Device.c b/shared-module/usb_hid/Device.c index 8e9df6f04..943c9bfed 100644 --- a/shared-module/usb_hid/Device.c +++ b/shared-module/usb_hid/Device.c @@ -84,14 +84,17 @@ uint16_t tud_hid_get_report_cb(uint8_t report_id, hid_report_type_t report_type, // Callbacks invoked when receive Set_Report request through control endpoint void tud_hid_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) { + if (report_type == HID_REPORT_TYPE_INVALID) { + report_id = buffer[0]; + buffer++; + bufsize--; + } else if (report_type != HID_REPORT_TYPE_OUTPUT) { + return; + } + usb_hid_device_obj_t* hid_device = get_hid_device(report_id); - if ( report_type == HID_REPORT_TYPE_OUTPUT ) { - // Check if it is Keyboard device - if (hid_device->usage_page == HID_USAGE_PAGE_DESKTOP && - hid_device->usage == HID_USAGE_DESKTOP_KEYBOARD) { - // This is LED indicator (CapsLock, NumLock) - // TODO Light up some LED here - } + if (hid_device && hid_device->out_report_length >= bufsize) { + memcpy(hid_device->out_report_buffer, buffer, bufsize); } } diff --git a/shared-module/usb_hid/Device.h b/shared-module/usb_hid/Device.h index 10f2ee897..93c3518b4 100644 --- a/shared-module/usb_hid/Device.h +++ b/shared-module/usb_hid/Device.h @@ -43,6 +43,8 @@ typedef struct { uint8_t report_length; uint8_t usage_page; uint8_t usage; + uint8_t* out_report_buffer; + uint8_t out_report_length; } usb_hid_device_obj_t; diff --git a/tools/gen_usb_descriptor.py b/tools/gen_usb_descriptor.py index fb91fd334..4ad6cfb56 100644 --- a/tools/gen_usb_descriptor.py +++ b/tools/gen_usb_descriptor.py @@ -535,7 +535,7 @@ c_file.write(""" }; """) -c_file.write("\n"); +c_file.write("\n") hid_descriptor_length = len(bytes(combined_hid_report_descriptor)) @@ -593,12 +593,18 @@ for name in args.hid_devices: static uint8_t {name}_report_buffer[{report_length}]; """.format(name=name.lower(), report_length=hid_report_descriptors.HID_DEVICE_DATA[name].report_length)) + if hid_report_descriptors.HID_DEVICE_DATA[name].out_report_length > 0: + c_file.write("""\ +static uint8_t {name}_out_report_buffer[{report_length}]; +""".format(name=name.lower(), report_length=hid_report_descriptors.HID_DEVICE_DATA[name].out_report_length)) + # Write out table of device objects. c_file.write(""" usb_hid_device_obj_t usb_hid_devices[] = { -"""); +""") for name in args.hid_devices: device_data = hid_report_descriptors.HID_DEVICE_DATA[name] + out_report_buffer = '{}_out_report_buffer'.format(name.lower()) if device_data.out_report_length > 0 else 'NULL' c_file.write("""\ {{ .base = {{ .type = &usb_hid_device_type }}, @@ -607,11 +613,15 @@ for name in args.hid_devices: .report_length = {report_length}, .usage_page = {usage_page:#04x}, .usage = {usage:#04x}, + .out_report_buffer = {out_report_buffer}, + .out_report_length = {out_report_length}, }}, """.format(name=name.lower(), report_id=report_ids[name], report_length=device_data.report_length, usage_page=device_data.usage_page, - usage=device_data.usage)) + usage=device_data.usage, + out_report_buffer=out_report_buffer, + out_report_length=device_data.out_report_length)) c_file.write("""\ }; """) diff --git a/tools/hid_report_descriptors.py b/tools/hid_report_descriptors.py index e13e0dbdd..aaa5b18b1 100644 --- a/tools/hid_report_descriptors.py +++ b/tools/hid_report_descriptors.py @@ -18,16 +18,16 @@ from adafruit_usb_descriptor import hid # Information about each kind of device # report_length does not include report ID in first byte, if present when sent. -DeviceData = namedtuple('DeviceData', ('report_length', 'usage_page', 'usage')) +DeviceData = namedtuple('DeviceData', ('report_length', 'out_report_length', 'usage_page', 'usage')) HID_DEVICE_DATA = { - "KEYBOARD" : DeviceData(report_length=8, usage_page=0x01, usage=0x06), # Generic Desktop, Keyboard - "MOUSE" : DeviceData(report_length=4, usage_page=0x01, usage=0x02), # Generic Desktop, Mouse - "CONSUMER" : DeviceData(report_length=2, usage_page=0x0C, usage=0x01), # Consumer, Consumer Control - "SYS_CONTROL" : DeviceData(report_length=1, usage_page=0x01, usage=0x80), # Generic Desktop, Sys Control - "GAMEPAD" : DeviceData(report_length=6, usage_page=0x01, usage=0x05), # Generic Desktop, Game Pad - "DIGITIZER" : DeviceData(report_length=5, usage_page=0x0D, usage=0x02), # Digitizers, Pen - "XAC_COMPATIBLE_GAMEPAD" : DeviceData(report_length=3, usage_page=0x01, usage=0x05), # Generic Desktop, Game Pad - "RAW" : DeviceData(report_length=64, usage_page=0xFFAF, usage=0xAF), # Vendor 0xFFAF "Adafruit", 0xAF + "KEYBOARD" : DeviceData(report_length=8, out_report_length=1, usage_page=0x01, usage=0x06), # Generic Desktop, Keyboard + "MOUSE" : DeviceData(report_length=4, out_report_length=0, usage_page=0x01, usage=0x02), # Generic Desktop, Mouse + "CONSUMER" : DeviceData(report_length=2, out_report_length=0, usage_page=0x0C, usage=0x01), # Consumer, Consumer Control + "SYS_CONTROL" : DeviceData(report_length=1, out_report_length=0, usage_page=0x01, usage=0x80), # Generic Desktop, Sys Control + "GAMEPAD" : DeviceData(report_length=6, out_report_length=0, usage_page=0x01, usage=0x05), # Generic Desktop, Game Pad + "DIGITIZER" : DeviceData(report_length=5, out_report_length=0, usage_page=0x0D, usage=0x02), # Digitizers, Pen + "XAC_COMPATIBLE_GAMEPAD" : DeviceData(report_length=3, out_report_length=0, usage_page=0x01, usage=0x05), # Generic Desktop, Game Pad + "RAW" : DeviceData(report_length=64, out_report_length=0, usage_page=0xFFAF, usage=0xAF), # Vendor 0xFFAF "Adafruit", 0xAF } def keyboard_hid_descriptor(report_id): -- cgit v1.2.3 From c62ab6e09a4dda33b75bcb0ee5fed800b756e564 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 5 Aug 2020 12:53:35 -0700 Subject: Add ipaddress --- ports/esp32s2/common-hal/wifi/Network.c | 15 +- ports/esp32s2/common-hal/wifi/Radio.c | 51 ++++++- ports/esp32s2/common-hal/wifi/Radio.h | 2 + ports/esp32s2/common-hal/wifi/ScannedNetworks.c | 7 +- ports/esp32s2/common-hal/wifi/__init__.c | 40 ++++-- py/circuitpy_defns.mk | 5 + py/circuitpy_mpconfig.h | 7 + py/circuitpy_mpconfig.mk | 3 + shared-bindings/ipaddress/IPv4Address.c | 180 ++++++++++++++++++++++++ shared-bindings/ipaddress/IPv4Address.h | 38 +++++ shared-bindings/ipaddress/__init__.c | 65 +++++++++ shared-bindings/ipaddress/__init__.h | 34 +++++ shared-bindings/wifi/Network.c | 39 ++++- shared-bindings/wifi/Network.h | 2 + shared-bindings/wifi/Radio.c | 28 ++-- shared-bindings/wifi/Radio.h | 4 +- shared-module/ipaddress/IPv4Address.c | 39 +++++ shared-module/ipaddress/IPv4Address.h | 37 +++++ shared-module/ipaddress/__init__.c | 35 +++++ shared-module/ipaddress/__init__.h | 36 +++++ 20 files changed, 634 insertions(+), 33 deletions(-) create mode 100644 shared-bindings/ipaddress/IPv4Address.c create mode 100644 shared-bindings/ipaddress/IPv4Address.h create mode 100644 shared-bindings/ipaddress/__init__.c create mode 100644 shared-bindings/ipaddress/__init__.h create mode 100644 shared-module/ipaddress/IPv4Address.c create mode 100644 shared-module/ipaddress/IPv4Address.h create mode 100644 shared-module/ipaddress/__init__.c create mode 100644 shared-module/ipaddress/__init__.h (limited to 'shared-module') diff --git a/ports/esp32s2/common-hal/wifi/Network.c b/ports/esp32s2/common-hal/wifi/Network.c index a270fd9dc..0320e8f92 100644 --- a/ports/esp32s2/common-hal/wifi/Network.c +++ b/ports/esp32s2/common-hal/wifi/Network.c @@ -26,6 +26,19 @@ #include "shared-bindings/wifi/Network.h" +#include + +#include "py/obj.h" + mp_obj_t common_hal_wifi_network_get_ssid(wifi_network_obj_t *self) { - return mp_const_none; + const char* cstr = (const char*) self->record.ssid; + return mp_obj_new_str(cstr, strlen(cstr)); +} + +mp_obj_t common_hal_wifi_network_get_rssi(wifi_network_obj_t *self) { + return mp_obj_new_int(self->record.rssi); +} + +mp_obj_t common_hal_wifi_network_get_channel(wifi_network_obj_t *self) { + return mp_obj_new_int(self->record.primary); } diff --git a/ports/esp32s2/common-hal/wifi/Radio.c b/ports/esp32s2/common-hal/wifi/Radio.c index a2944dd52..623ba9e34 100644 --- a/ports/esp32s2/common-hal/wifi/Radio.c +++ b/ports/esp32s2/common-hal/wifi/Radio.c @@ -26,7 +26,11 @@ #include "shared-bindings/wifi/Radio.h" +#include + +#include "lib/utils/interrupt_char.h" #include "py/runtime.h" +#include "shared-bindings/ipaddress/IPv4Address.h" #include "shared-bindings/wifi/ScannedNetworks.h" #include "esp-idf/components/esp_wifi/include/esp_wifi.h" @@ -103,16 +107,51 @@ void common_hal_wifi_radio_stop_scanning_networks(wifi_radio_obj_t *self) { ESP_EARLY_LOGI(TAG, "stop scan done"); } -bool common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t* ssid, size_t ssid_len, uint8_t* password, size_t password_len, mp_float_t timeout) { +bool common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t* ssid, size_t ssid_len, uint8_t* password, size_t password_len, uint8_t channel, mp_float_t timeout) { // check enabled - wifi_config_t config; - esp_err_t result = esp_wifi_set_config(ESP_IF_WIFI_STA, &config); + wifi_config_t* config = &self->sta_config; + memcpy(&config->sta.ssid, ssid, ssid_len); + config->sta.ssid[ssid_len] = 0; + if (password_len > 0) { + memcpy(&config->sta.password, password, password_len); + } + config->sta.password[password_len] = 0; + config->sta.channel = channel; + ESP_EARLY_LOGI(TAG, "connecting to %s", config->sta.ssid); + esp_err_t result = esp_wifi_set_config(ESP_IF_WIFI_STA, config); + if (result != ESP_OK) { + ESP_EARLY_LOGI(TAG, "config fail %d", result); + } result = esp_wifi_connect(); - return result == ESP_OK; + if (result != ESP_OK) { + ESP_EARLY_LOGI(TAG, "connect fail %d", result); + } + + EventBits_t bits; + do { + RUN_BACKGROUND_TASKS; + bits = xEventGroupWaitBits(self->event_group_handle, + WIFI_CONNECTED_BIT | WIFI_DISCONNECTED_BIT, + pdTRUE, + pdTRUE, + 0); + } while ((bits & (WIFI_CONNECTED_BIT | WIFI_DISCONNECTED_BIT)) == 0 && !mp_hal_is_interrupted()); + if ((bits & WIFI_DISCONNECTED_BIT) != 0) { + return false; + } + return true; } -mp_obj_t common_hal_wifi_radio_get_ip_address(wifi_radio_obj_t *self) { - return mp_const_none; +mp_obj_t common_hal_wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) { + if (!esp_netif_is_netif_up(self->netif)) { + return mp_const_none; + } + esp_netif_ip_info_t ip_info; + esp_err_t result = esp_netif_get_ip_info(self->netif, &ip_info); + if (result != ESP_OK) { + ESP_EARLY_LOGI(TAG, "get ip fail %d", result); + } + return common_hal_ipaddress_new_ipv4address(ip_info.ip.addr); } mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address) { diff --git a/ports/esp32s2/common-hal/wifi/Radio.h b/ports/esp32s2/common-hal/wifi/Radio.h index 11b30799a..e7dce9477 100644 --- a/ports/esp32s2/common-hal/wifi/Radio.h +++ b/ports/esp32s2/common-hal/wifi/Radio.h @@ -35,6 +35,8 @@ // Event bits for the Radio event group. #define WIFI_SCAN_DONE_BIT BIT0 +#define WIFI_CONNECTED_BIT BIT1 +#define WIFI_DISCONNECTED_BIT BIT2 typedef struct { mp_obj_base_t base; diff --git a/ports/esp32s2/common-hal/wifi/ScannedNetworks.c b/ports/esp32s2/common-hal/wifi/ScannedNetworks.c index 248defa57..060e13f8e 100644 --- a/ports/esp32s2/common-hal/wifi/ScannedNetworks.c +++ b/ports/esp32s2/common-hal/wifi/ScannedNetworks.c @@ -29,6 +29,7 @@ #include #include "lib/utils/interrupt_char.h" +#include "py/gc.h" #include "py/objstr.h" #include "py/runtime.h" #include "shared-bindings/wifi/__init__.h" @@ -45,7 +46,10 @@ static void wifi_scannednetworks_done(wifi_scannednetworks_obj_t *self) { self->done = true; ESP_EARLY_LOGI(TAG, "free %x", self->results); if (self->results != NULL) { - m_free(self->results); + // Check to see if the heap is still active. If not, it'll be freed automatically. + if (gc_alloc_possible()) { + m_free(self->results); + } self->results = NULL; } } @@ -137,7 +141,6 @@ mp_obj_t common_hal_wifi_scannednetworks_next(wifi_scannednetworks_obj_t *self) static uint8_t scan_pattern[] = {6, 1, 11, 3, 9, 13, 2, 4, 8, 12, 5, 7, 10, 14}; void wifi_scannednetworks_scan_next_channel(wifi_scannednetworks_obj_t *self) { - uint8_t next_channel = sizeof(scan_pattern); while (self->current_channel_index < sizeof(scan_pattern)) { next_channel = scan_pattern[self->current_channel_index]; diff --git a/ports/esp32s2/common-hal/wifi/__init__.c b/ports/esp32s2/common-hal/wifi/__init__.c index d4a1d9892..1dc9ef9a8 100644 --- a/ports/esp32s2/common-hal/wifi/__init__.c +++ b/ports/esp32s2/common-hal/wifi/__init__.c @@ -41,9 +41,32 @@ static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { ESP_LOGI(TAG, "event %x", event_id); wifi_radio_obj_t* radio = arg; - if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_SCAN_DONE) { - xEventGroupSetBits(radio->event_group_handle, WIFI_SCAN_DONE_BIT); + if (event_base == WIFI_EVENT) { + if (event_id == WIFI_EVENT_SCAN_DONE) { + ESP_LOGI(TAG, "scan done"); + xEventGroupSetBits(radio->event_group_handle, WIFI_SCAN_DONE_BIT); + } else if (event_id == WIFI_EVENT_STA_START) { + ESP_LOGI(TAG, "station start"); + + } else if (event_id == WIFI_EVENT_STA_STOP) { + ESP_LOGI(TAG, "station stop"); + + } else if (event_id == WIFI_EVENT_STA_CONNECTED) { + ESP_LOGI(TAG, "connected to ap"); + } else if (event_id == WIFI_EVENT_STA_DISCONNECTED) { + ESP_LOGI(TAG, "disconnected"); + wifi_event_sta_disconnected_t* d = (wifi_event_sta_disconnected_t*) event_data; + ESP_LOGI(TAG, "reason %d", d->reason); + if (event_id != WIFI_REASON_ASSOC_LEAVE) { + // reconnect + } + xEventGroupSetBits(radio->event_group_handle, WIFI_DISCONNECTED_BIT); + } else if (event_id == WIFI_EVENT_STA_AUTHMODE_CHANGE) { + ESP_LOGI(TAG, "auth change"); + + } } + // esp_wifi_connect(); // if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { // esp_wifi_connect(); @@ -56,12 +79,13 @@ static void event_handler(void* arg, esp_event_base_t event_base, // xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); // } // ESP_LOGI(TAG,"connect to the AP fail"); - // } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { - // ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; - // ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); - // s_retry_num = 0; - // xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); - // } + // } else + if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; + ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); + // s_retry_num = 0; + xEventGroupSetBits(radio->event_group_handle, WIFI_CONNECTED_BIT); + } } static bool wifi_inited; diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index caf65d27e..1a5145c8b 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -168,6 +168,9 @@ endif ifeq ($(CIRCUITPY_I2CPERIPHERAL),1) SRC_PATTERNS += i2cperipheral/% endif +ifeq ($(CIRCUITPY_IPADDRESS),1) +SRC_PATTERNS += ipaddress/% +endif ifeq ($(CIRCUITPY_MATH),1) SRC_PATTERNS += math/% endif @@ -408,6 +411,8 @@ SRC_SHARED_MODULE_ALL = \ fontio/__init__.c \ framebufferio/FramebufferDisplay.c \ framebufferio/__init__.c \ + ipaddress/IPv4Address.c \ + ipaddress/__init__.c \ sdcardio/SDCard.c \ sdcardio/__init__.c \ gamepad/GamePad.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 2db20ca1d..8ff2ddc67 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -420,6 +420,13 @@ extern const struct _mp_obj_module_t i2cperipheral_module; #define I2CPERIPHERAL_MODULE #endif +#if CIRCUITPY_IPADDRESS +extern const struct _mp_obj_module_t ipaddress_module; +#define IPADDRESS_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_ipaddress), (mp_obj_t)&ipaddress_module }, +#else +#define IPADDRESS_MODULE +#endif + #if CIRCUITPY_MATH extern const struct _mp_obj_module_t math_module; #define MATH_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_math), (mp_obj_t)&math_module }, diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index abbd5a9a0..499e87aed 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -120,6 +120,9 @@ CFLAGS += -DCIRCUITPY_GNSS=$(CIRCUITPY_GNSS) CIRCUITPY_I2CPERIPHERAL ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_I2CPERIPHERAL=$(CIRCUITPY_I2CPERIPHERAL) +CIRCUITPY_IPADDRESS ?= $(CIRCUITPY_WIFI) +CFLAGS += -DCIRCUITPY_IPADDRESS=$(CIRCUITPY_IPADDRESS) + CIRCUITPY_MATH ?= 1 CFLAGS += -DCIRCUITPY_MATH=$(CIRCUITPY_MATH) diff --git a/shared-bindings/ipaddress/IPv4Address.c b/shared-bindings/ipaddress/IPv4Address.c new file mode 100644 index 000000000..3cef7516d --- /dev/null +++ b/shared-bindings/ipaddress/IPv4Address.c @@ -0,0 +1,180 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Dan Halbert for Adafruit Industries + * Copyright (c) 2018 Artur Pacholec + * + * 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 +#include + +#include "py/objproperty.h" +#include "py/objstr.h" +#include "py/runtime.h" +#include "shared-bindings/ipaddress/IPv4Address.h" + +//| class IPv4Address: +//| """Encapsulates an IPv4 address.""" +//| + +//| def __init__(self, address: Union[str, int]) -> None: +//| """Create a new Address object encapsulating the address value. +//| +//| The value itself can be one of:""" +//| ... +//| +STATIC mp_obj_t ipaddress_ipv4address_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_address }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_OBJ | MP_ARG_REQUIRED }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + ipaddress_ipv4address_obj_t *self = m_new_obj(ipaddress_ipv4address_obj_t); + self->base.type = &ipaddress_ipv4address_type; + + const mp_obj_t address = args[ARG_address].u_obj; + mp_buffer_info_t buf_info; + mp_get_buffer_raise(address, &buf_info, MP_BUFFER_READ); + if (buf_info.len != 4) { + mp_raise_ValueError_varg(translate("Address must be %d bytes long"), 4); + } + + common_hal_ipaddress_ipv4address_construct(self, buf_info.buf, buf_info.len); + + return MP_OBJ_FROM_PTR(self); +} + +//| packed: bytes +//| """The bytes that make up the address (read-only).""" +//| +STATIC mp_obj_t ipaddress_ipv4address_get_packed(mp_obj_t self_in) { + ipaddress_ipv4address_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return common_hal_ipaddress_ipv4address_get_packed(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(ipaddress_ipv4address_get_packed_obj, ipaddress_ipv4address_get_packed); + +const mp_obj_property_t ipaddress_ipv4address_packed_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&ipaddress_ipv4address_get_packed_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| version: int +//| """4 for IPv4, 6 for IPv6""" +//| +STATIC mp_obj_t ipaddress_ipv4address_get_version(mp_obj_t self_in) { + ipaddress_ipv4address_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t buf_info; + mp_obj_t address_bytes = common_hal_ipaddress_ipv4address_get_packed(self); + mp_get_buffer_raise(address_bytes, &buf_info, MP_BUFFER_READ); + mp_int_t version = 6; + if (buf_info.len == 4) { + version = 4; + } + + return MP_OBJ_NEW_SMALL_INT(version); +} +MP_DEFINE_CONST_FUN_OBJ_1(ipaddress_ipv4address_get_version_obj, ipaddress_ipv4address_get_version); + +const mp_obj_property_t ipaddress_ipv4address_version_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&ipaddress_ipv4address_get_version_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| def __eq__(self, other: Address) -> bool: +//| """Two Address objects are equal if their addresses and address types are equal.""" +//| ... +//| +STATIC mp_obj_t ipaddress_ipv4address_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { + switch (op) { + // Two Addresses are equal if their address bytes and address_type are equal + case MP_BINARY_OP_EQUAL: + if (MP_OBJ_IS_TYPE(rhs_in, &ipaddress_ipv4address_type)) { + ipaddress_ipv4address_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in); + ipaddress_ipv4address_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in); + return mp_obj_new_bool( + mp_obj_equal(common_hal_ipaddress_ipv4address_get_packed(lhs), + common_hal_ipaddress_ipv4address_get_packed(rhs))); + + } else { + return mp_const_false; + } + + default: + return MP_OBJ_NULL; // op not supported + } +} + +//| def __hash__(self) -> int: +//| """Returns a hash for the Address data.""" +//| ... +//| +STATIC mp_obj_t ipaddress_ipv4address_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + switch (op) { + // Two Addresses are equal if their address bytes and address_type are equal + case MP_UNARY_OP_HASH: { + mp_obj_t bytes = common_hal_ipaddress_ipv4address_get_packed(MP_OBJ_TO_PTR(self_in)); + GET_STR_HASH(bytes, h); + if (h == 0) { + GET_STR_DATA_LEN(bytes, data, len); + h = qstr_compute_hash(data, len); + } + return MP_OBJ_NEW_SMALL_INT(h); + } + default: + return MP_OBJ_NULL; // op not supported + } +} + +STATIC void ipaddress_ipv4address_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + ipaddress_ipv4address_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_buffer_info_t buf_info; + mp_obj_t address_bytes = common_hal_ipaddress_ipv4address_get_packed(self); + mp_get_buffer_raise(address_bytes, &buf_info, MP_BUFFER_READ); + + const uint8_t *buf = (uint8_t *) buf_info.buf; + mp_printf(print, "%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]); +} + +STATIC const mp_rom_map_elem_t ipaddress_ipv4address_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_packed), MP_ROM_PTR(&ipaddress_ipv4address_packed_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(ipaddress_ipv4address_locals_dict, ipaddress_ipv4address_locals_dict_table); + +const mp_obj_type_t ipaddress_ipv4address_type = { + { &mp_type_type }, + .name = MP_QSTR_Address, + .make_new = ipaddress_ipv4address_make_new, + .print = ipaddress_ipv4address_print, + .unary_op = ipaddress_ipv4address_unary_op, + .binary_op = ipaddress_ipv4address_binary_op, + .locals_dict = (mp_obj_dict_t*)&ipaddress_ipv4address_locals_dict +}; diff --git a/shared-bindings/ipaddress/IPv4Address.h b/shared-bindings/ipaddress/IPv4Address.h new file mode 100644 index 000000000..cf66b92b3 --- /dev/null +++ b/shared-bindings/ipaddress/IPv4Address.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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_SHARED_BINDINGS_IPADDRESS_IPV4ADDRESS_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_IPADDRESS_IPV4ADDRESS_H + +#include "shared-module/ipaddress/IPv4Address.h" + +extern const mp_obj_type_t ipaddress_ipv4address_type; + +mp_obj_t common_hal_ipaddress_new_ipv4address(mp_int_t value); +void common_hal_ipaddress_ipv4address_construct(ipaddress_ipv4address_obj_t* self, uint8_t* buf, size_t len); +mp_obj_t common_hal_ipaddress_ipv4address_get_packed(ipaddress_ipv4address_obj_t* self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_IPADDRESS_IPV4ADDRESS_H diff --git a/shared-bindings/ipaddress/__init__.c b/shared-bindings/ipaddress/__init__.c new file mode 100644 index 000000000..f9427ab84 --- /dev/null +++ b/shared-bindings/ipaddress/__init__.c @@ -0,0 +1,65 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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/objexcept.h" +#include "py/runtime.h" +#include "shared-bindings/ipaddress/__init__.h" +#include "shared-bindings/ipaddress/IPv4Address.h" + +//| """ +//| The `ipaddress` module provides types for IP addresses. It is a subset of CPython's ipaddress +//| module. +//| """ +//| + +//| def ip_address(obj: Union[int]) -> IPv4Address: +//| """Return a corresponding IP address object or raise ValueError if not possible.""" +//| ... +//| + +STATIC mp_obj_t ipaddress_ip_address(mp_obj_t ip_in) { + mp_int_t value; + if (!mp_obj_get_int_maybe(ip_in, &value)) { + mp_raise_ValueError(translate("Only raw int supported for ip.")); + } + + return common_hal_ipaddress_new_ipv4address(value); +} +MP_DEFINE_CONST_FUN_OBJ_1(ipaddress_ip_address_obj, ipaddress_ip_address); + +STATIC const mp_rom_map_elem_t ipaddress_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ipaddress) }, + { MP_ROM_QSTR(MP_QSTR_ip_address), MP_ROM_PTR(&ipaddress_ip_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_IPv4Address), MP_ROM_PTR(&ipaddress_ipv4address_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(ipaddress_module_globals, ipaddress_module_globals_table); + + +const mp_obj_module_t ipaddress_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&ipaddress_module_globals, +}; diff --git a/shared-bindings/ipaddress/__init__.h b/shared-bindings/ipaddress/__init__.h new file mode 100644 index 000000000..a31629cca --- /dev/null +++ b/shared-bindings/ipaddress/__init__.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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_SHARED_BINDINGS_IPADDRESS___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_IPADDRESS___INIT___H + +#include "shared-module/ipaddress/__init__.h" + +mp_obj_t common_hal_ipaddress_new_ipv4address(mp_int_t value); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_IPADDRESS___INIT___H diff --git a/shared-bindings/wifi/Network.c b/shared-bindings/wifi/Network.c index b4d389dcc..b6d5e0901 100644 --- a/shared-bindings/wifi/Network.c +++ b/shared-bindings/wifi/Network.c @@ -42,7 +42,7 @@ //| //| ssid: str -//| """True when the wifi network is enabled.""" +//| """String id of the network""" //| STATIC mp_obj_t wifi_network_get_ssid(mp_obj_t self) { return common_hal_wifi_network_get_ssid(self); @@ -57,8 +57,45 @@ const mp_obj_property_t wifi_network_ssid_obj = { (mp_obj_t)&mp_const_none_obj }, }; + +//| rssi: int +//| """Signal strength of the network""" +//| +STATIC mp_obj_t wifi_network_get_rssi(mp_obj_t self) { + return common_hal_wifi_network_get_rssi(self); + +} +MP_DEFINE_CONST_FUN_OBJ_1(wifi_network_get_rssi_obj, wifi_network_get_rssi); + +const mp_obj_property_t wifi_network_rssi_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&wifi_network_get_rssi_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + + +//| channel: int +//| """Channel number the network is operating on""" +//| +STATIC mp_obj_t wifi_network_get_channel(mp_obj_t self) { + return common_hal_wifi_network_get_channel(self); + +} +MP_DEFINE_CONST_FUN_OBJ_1(wifi_network_get_channel_obj, wifi_network_get_channel); + +const mp_obj_property_t wifi_network_channel_obj = { + .base.type = &mp_type_property, + .proxy = { (mp_obj_t)&wifi_network_get_channel_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj }, +}; + + STATIC const mp_rom_map_elem_t wifi_network_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_ssid), MP_ROM_PTR(&wifi_network_ssid_obj) }, + { MP_ROM_QSTR(MP_QSTR_rssi), MP_ROM_PTR(&wifi_network_rssi_obj) }, + { MP_ROM_QSTR(MP_QSTR_channel), MP_ROM_PTR(&wifi_network_channel_obj) }, }; STATIC MP_DEFINE_CONST_DICT(wifi_network_locals_dict, wifi_network_locals_dict_table); diff --git a/shared-bindings/wifi/Network.h b/shared-bindings/wifi/Network.h index 8a3d10ca7..6a7f7be4a 100644 --- a/shared-bindings/wifi/Network.h +++ b/shared-bindings/wifi/Network.h @@ -36,5 +36,7 @@ const mp_obj_type_t wifi_network_type; extern mp_obj_t common_hal_wifi_network_get_ssid(wifi_network_obj_t *self); +extern mp_obj_t common_hal_wifi_network_get_rssi(wifi_network_obj_t *self); +extern mp_obj_t common_hal_wifi_network_get_channel(wifi_network_obj_t *self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_NETWORK_H diff --git a/shared-bindings/wifi/Radio.c b/shared-bindings/wifi/Radio.c index c5bee8311..1d1423573 100644 --- a/shared-bindings/wifi/Radio.c +++ b/shared-bindings/wifi/Radio.c @@ -102,16 +102,18 @@ STATIC mp_obj_t wifi_radio_stop_scanning_networks(mp_obj_t self_in) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_stop_scanning_networks_obj, wifi_radio_stop_scanning_networks); -//| def connect(self, ssid: ReadableBuffer, password: ReadableBuffer = b"", *, timeout: Optional[float] = None) -> bool: -//| """""" +//| def connect(self, ssid: ReadableBuffer, password: ReadableBuffer = b"", *, channel: Optional[int] = 0, timeout: Optional[float] = None) -> bool: +//| """Connects to the given ssid and waits for an ip address. Reconnections are handled +//| automatically once one connection succeeds.""" //| ... //| STATIC mp_obj_t wifi_radio_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_ssid, ARG_password, ARG_timeout }; + enum { ARG_ssid, ARG_password, ARG_channel, ARG_timeout }; static const mp_arg_t allowed_args[] = { { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_password, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; wifi_radio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); @@ -136,22 +138,22 @@ STATIC mp_obj_t wifi_radio_connect(size_t n_args, const mp_obj_t *pos_args, mp_m mp_get_buffer_raise(args[ARG_password].u_obj, &password, MP_BUFFER_READ); } - return mp_obj_new_bool(common_hal_wifi_radio_connect(self, ssid.buf, ssid.len, password.buf, password.len, timeout)); + return mp_obj_new_bool(common_hal_wifi_radio_connect(self, ssid.buf, ssid.len, password.buf, password.len, args[ARG_channel].u_int, timeout)); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wifi_radio_connect_obj, 1, wifi_radio_connect); -//| ip_address: Optional[ipaddress.IPAddress] -//| """IP Address of the radio when connected to an access point. None otherwise.""" +//| ipv4_address: Optional[ipaddress.IPv4Address] +//| """IP v4 Address of the radio when connected to an access point. None otherwise.""" //| -STATIC mp_obj_t wifi_radio_get_ip_address(mp_obj_t self) { - return common_hal_wifi_radio_get_ip_address(self); +STATIC mp_obj_t wifi_radio_get_ipv4_address(mp_obj_t self) { + return common_hal_wifi_radio_get_ipv4_address(self); } -MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_ip_address_obj, wifi_radio_get_ip_address); +MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_ipv4_address_obj, wifi_radio_get_ipv4_address); -const mp_obj_property_t wifi_radio_ip_address_obj = { +const mp_obj_property_t wifi_radio_ipv4_address_obj = { .base.type = &mp_type_property, - .proxy = { (mp_obj_t)&wifi_radio_get_ip_address_obj, + .proxy = { (mp_obj_t)&wifi_radio_get_ipv4_address_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj }, }; @@ -179,7 +181,7 @@ STATIC const mp_rom_map_elem_t wifi_radio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&wifi_radio_connect_obj) }, // { MP_ROM_QSTR(MP_QSTR_connect_to_enterprise), MP_ROM_PTR(&wifi_radio_connect_to_enterprise_obj) }, - { MP_ROM_QSTR(MP_QSTR_ip_address), MP_ROM_PTR(&wifi_radio_ip_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_ipv4_address), MP_ROM_PTR(&wifi_radio_ipv4_address_obj) }, // { MP_ROM_QSTR(MP_QSTR_access_point_active), MP_ROM_PTR(&wifi_radio_access_point_active_obj) }, // { MP_ROM_QSTR(MP_QSTR_start_access_point), MP_ROM_PTR(&wifi_radio_start_access_point_obj) }, diff --git a/shared-bindings/wifi/Radio.h b/shared-bindings/wifi/Radio.h index c3bdac5ba..3890885ae 100644 --- a/shared-bindings/wifi/Radio.h +++ b/shared-bindings/wifi/Radio.h @@ -43,9 +43,9 @@ extern mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self); extern mp_obj_t common_hal_wifi_radio_start_scanning_networks(wifi_radio_obj_t *self); extern void common_hal_wifi_radio_stop_scanning_networks(wifi_radio_obj_t *self); -extern bool common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t* ssid, size_t ssid_len, uint8_t* password, size_t password_len, mp_float_t timeout); +extern bool common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t* ssid, size_t ssid_len, uint8_t* password, size_t password_len, uint8_t channel, mp_float_t timeout); -extern mp_obj_t common_hal_wifi_radio_get_ip_address(wifi_radio_obj_t *self); +extern mp_obj_t common_hal_wifi_radio_get_ipv4_address(wifi_radio_obj_t *self); extern mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address); diff --git a/shared-module/ipaddress/IPv4Address.c b/shared-module/ipaddress/IPv4Address.c new file mode 100644 index 000000000..f573d9d0a --- /dev/null +++ b/shared-module/ipaddress/IPv4Address.c @@ -0,0 +1,39 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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/obj.h" + +#include "shared-bindings/ipaddress/__init__.h" +#include "shared-bindings/ipaddress/IPv4Address.h" + + +void common_hal_ipaddress_ipv4address_construct(ipaddress_ipv4address_obj_t* self, uint8_t* buf, size_t len) { + self->ip_bytes = mp_obj_new_bytes(buf, len); +} + +mp_obj_t common_hal_ipaddress_ipv4address_get_packed(ipaddress_ipv4address_obj_t* self) { + return self->ip_bytes; +} diff --git a/shared-module/ipaddress/IPv4Address.h b/shared-module/ipaddress/IPv4Address.h new file mode 100644 index 000000000..3f2bde091 --- /dev/null +++ b/shared-module/ipaddress/IPv4Address.h @@ -0,0 +1,37 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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_SHARED_MODULE_IPADDRESS_IPV4ADDRESS_H +#define MICROPY_INCLUDED_SHARED_MODULE_IPADDRESS_IPV4ADDRESS_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + mp_obj_t ip_bytes; +} ipaddress_ipv4address_obj_t; + +#endif // MICROPY_INCLUDED_SHARED_MODULE_IPADDRESS_IPV4ADDRESS_H diff --git a/shared-module/ipaddress/__init__.c b/shared-module/ipaddress/__init__.c new file mode 100644 index 000000000..e5d857d5d --- /dev/null +++ b/shared-module/ipaddress/__init__.c @@ -0,0 +1,35 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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 "shared-bindings/ipaddress/__init__.h" +#include "shared-bindings/ipaddress/IPv4Address.h" + +mp_obj_t common_hal_ipaddress_new_ipv4address(mp_int_t value) { + ipaddress_ipv4address_obj_t* self = m_new_obj(ipaddress_ipv4address_obj_t); + self->base.type = &ipaddress_ipv4address_type; + common_hal_ipaddress_ipv4address_construct(self, (uint8_t*) &value, 4); + return self; +} diff --git a/shared-module/ipaddress/__init__.h b/shared-module/ipaddress/__init__.h new file mode 100644 index 000000000..7d5f2c220 --- /dev/null +++ b/shared-module/ipaddress/__init__.h @@ -0,0 +1,36 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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_SHARED_MODULE_IPADDRESS___INIT___H +#define MICROPY_INCLUDED_SHARED_MODULE_IPADDRESS___INIT___H + +#include + +#include "py/obj.h" + +mp_obj_t common_hal_ipaddress_new_ipv4(uint32_t value); + +#endif // MICROPY_INCLUDED_SHARED_MODULE_IPADDRESS___INIT___H -- cgit v1.2.3 From 3860991111511a9e4a60ea24f208b8de8f801ce7 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 10 Aug 2020 17:56:49 -0700 Subject: Ping work and start to add socketpool --- ports/esp32s2/Makefile | 4 + ports/esp32s2/common-hal/wifi/Radio.c | 29 +- ports/esp32s2/esp-idf | 2 +- py/circuitpy_defns.mk | 3 + py/circuitpy_mpconfig.h | 9 + py/circuitpy_mpconfig.mk | 3 + shared-bindings/socketpool/__init__.c | 603 ++++++++++++++++++++++++++++++++++ shared-bindings/wifi/Radio.c | 27 +- shared-bindings/wifi/Radio.h | 2 +- shared-module/ipaddress/__init__.c | 5 + shared-module/ipaddress/__init__.h | 4 + 11 files changed, 680 insertions(+), 11 deletions(-) create mode 100644 shared-bindings/socketpool/__init__.c (limited to 'shared-module') diff --git a/ports/esp32s2/Makefile b/ports/esp32s2/Makefile index 23a97a6fe..ab470d095 100644 --- a/ports/esp32s2/Makefile +++ b/ports/esp32s2/Makefile @@ -85,6 +85,10 @@ INC += -Iesp-idf/components/esp_rom/include INC += -Iesp-idf/components/esp_wifi/include INC += -Iesp-idf/components/xtensa/include INC += -Iesp-idf/components/esp_timer/include +INC += -Iesp-idf/components/newlib/platform_include +INC += -Iesp-idf/components/lwip/lwip/src/include +INC += -Iesp-idf/components/lwip/port/esp32/include +INC += -Iesp-idf/components/lwip/include/apps/sntp INC += -Iesp-idf/components/soc/include INC += -Iesp-idf/components/soc/src/esp32s2/include INC += -Iesp-idf/components/soc/soc/include diff --git a/ports/esp32s2/common-hal/wifi/Radio.c b/ports/esp32s2/common-hal/wifi/Radio.c index 623ba9e34..49ad0592e 100644 --- a/ports/esp32s2/common-hal/wifi/Radio.c +++ b/ports/esp32s2/common-hal/wifi/Radio.c @@ -32,8 +32,10 @@ #include "py/runtime.h" #include "shared-bindings/ipaddress/IPv4Address.h" #include "shared-bindings/wifi/ScannedNetworks.h" +#include "shared-module/ipaddress/__init__.h" #include "esp-idf/components/esp_wifi/include/esp_wifi.h" +#include "esp-idf/components/lwip/include/apps/ping/ping_sock.h" #include "esp_log.h" static const char *TAG = "cp radio"; @@ -154,6 +156,29 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) { return common_hal_ipaddress_new_ipv4address(ip_info.ip.addr); } -mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address) { - return 0; +mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address, mp_float_t timeout) { + esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG(); + ipaddress_ipaddress_to_esp_idf(ip_address, &ping_config.target_addr); + ping_config.count = 1; + + size_t timeout_ms = timeout * 1000; + + esp_ping_handle_t ping; + esp_ping_new_session(&ping_config, NULL, &ping); + esp_ping_start(ping); + + uint32_t received = 0; + uint32_t total_time_ms = 0; + while (received == 0 && total_time_ms < timeout_ms) { + RUN_BACKGROUND_TASKS; + esp_ping_get_profile(ping, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms)); + esp_ping_get_profile(ping, ESP_PING_PROF_REPLY, &received, sizeof(received)); + } + uint32_t elapsed_time = 0xffffffff; + if (received > 0) { + esp_ping_get_profile(ping, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time)); + } + esp_ping_delete_session(ping); + + return elapsed_time; } diff --git a/ports/esp32s2/esp-idf b/ports/esp32s2/esp-idf index 739180550..01c86ed7d 160000 --- a/ports/esp32s2/esp-idf +++ b/ports/esp32s2/esp-idf @@ -1 +1 @@ -Subproject commit 739180550254d4d68335cd3b443ada8909905bac +Subproject commit 01c86ed7d6f4bbbaeda0c461c5f20e3d9872b44b diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 1a5145c8b..c1b293b94 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -228,6 +228,9 @@ endif ifeq ($(CIRCUITPY_SHARPDISPLAY),1) SRC_PATTERNS += sharpdisplay/% endif +ifeq ($(CIRCUITPY_SOCKETPOOL),1) +SRC_PATTERNS += socketpool/% +endif ifeq ($(CIRCUITPY_STAGE),1) SRC_PATTERNS += _stage/% endif diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index f2789ee58..846328dcd 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -573,6 +573,7 @@ extern const struct _mp_obj_module_t sdioio_module; #define SDIOIO_MODULE #endif + #if CIRCUITPY_SHARPDISPLAY extern const struct _mp_obj_module_t sharpdisplay_module; #define SHARPDISPLAY_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_sharpdisplay),(mp_obj_t)&sharpdisplay_module }, @@ -580,6 +581,13 @@ extern const struct _mp_obj_module_t sharpdisplay_module; #define SHARPDISPLAY_MODULE #endif +#if CIRCUITPY_SOCKETPOOL +extern const struct _mp_obj_module_t socketpool_module; +#define SOCKETPOOL_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_socketpool), (mp_obj_t)&socketpool_module }, +#else +#define SOCKETPOOL_MODULE +#endif + #if CIRCUITPY_STAGE extern const struct _mp_obj_module_t stage_module; #define STAGE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__stage), (mp_obj_t)&stage_module }, @@ -764,6 +772,7 @@ extern const struct _mp_obj_module_t wifi_module; SDCARDIO_MODULE \ SDIOIO_MODULE \ SHARPDISPLAY_MODULE \ + SOCKETPOOL_MODULE \ STAGE_MODULE \ STORAGE_MODULE \ STRUCT_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 499e87aed..2ef8feb3a 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -185,6 +185,9 @@ CFLAGS += -DCIRCUITPY_SDIOIO=$(CIRCUITPY_SDIOIO) CIRCUITPY_SHARPDISPLAY ?= $(CIRCUITPY_FRAMEBUFFERIO) CFLAGS += -DCIRCUITPY_SHARPDISPLAY=$(CIRCUITPY_SHARPDISPLAY) +CIRCUITPY_SOCKETPOOL ?= 0 +CFLAGS += -DCIRCUITPY_SOCKETPOOL=$(CIRCUITPY_SOCKETPOOL) + # Currently always off. CIRCUITPY_STAGE ?= 0 CFLAGS += -DCIRCUITPY_STAGE=$(CIRCUITPY_STAGE) diff --git a/shared-bindings/socketpool/__init__.c b/shared-bindings/socketpool/__init__.c new file mode 100644 index 000000000..53ac57d11 --- /dev/null +++ b/shared-bindings/socketpool/__init__.c @@ -0,0 +1,603 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * SPDX-FileCopyrightText: Copyright (c) 2014 Damien P. George + * 2018 Nick Moore for Adafruit Industries + * + * 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 +#include + +#include "py/objtuple.h" +#include "py/objlist.h" +#include "py/runtime.h" +#include "py/stream.h" +#include "py/mperrno.h" +#include "lib/netutils/netutils.h" + +#include "shared-module/network/__init__.h" + +//| """TCP, UDP and RAW socket support +//| +//| .. warning:: This module is disabled in 6.x and will removed in 7.x. Please use networking +//| libraries instead. (Native networking will provide a socket compatible class.) +//| +//| Create TCP, UDP and RAW sockets for communicating over the Internet.""" +//| + +STATIC const mp_obj_type_t socket_type; + +//| class socket: +//| +//| def __init__(self, family: int, type: int, proto: int) -> None: +//| """Create a new socket +//| +//| :param ~int family: AF_INET or AF_INET6 +//| :param ~int type: SOCK_STREAM, SOCK_DGRAM or SOCK_RAW +//| :param ~int proto: IPPROTO_TCP, IPPROTO_UDP or IPPROTO_RAW (ignored)""" +//| ... +//| + +STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + mp_arg_check_num(n_args, kw_args, 0, 4, false); + + // create socket object (not bound to any NIC yet) + mod_network_socket_obj_t *s = m_new_obj_with_finaliser(mod_network_socket_obj_t); + s->base.type = &socket_type; + s->nic = MP_OBJ_NULL; + s->nic_type = NULL; + s->u_param.domain = MOD_NETWORK_AF_INET; + s->u_param.type = MOD_NETWORK_SOCK_STREAM; + s->u_param.fileno = -1; + if (n_args >= 1) { + s->u_param.domain = mp_obj_get_int(args[0]); + if (n_args >= 2) { + s->u_param.type = mp_obj_get_int(args[1]); + if (n_args >= 4) { + s->u_param.fileno = mp_obj_get_int(args[3]); + } + } + } + + return MP_OBJ_FROM_PTR(s); +} + +STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) { + if (self->nic == MP_OBJ_NULL) { + // select NIC based on IP + self->nic = network_module_find_nic(ip); + self->nic_type = (mod_network_nic_type_t*)mp_obj_get_type(self->nic); + + // call the NIC to open the socket + int _errno; + if (self->nic_type->socket(self, &_errno) != 0) { + mp_raise_OSError(_errno); + } + } +} + +//| def bind(self, address: tuple) -> None: +//| """Bind a socket to an address +//| +//| :param ~tuple address: tuple of (remote_address, remote_port)""" +//| ... +//| + +STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // get address + uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE]; + mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG); + + // check if we need to select a NIC + socket_select_nic(self, ip); + + // call the NIC to bind the socket + int _errno; + if (self->nic_type->bind(self, ip, port, &_errno) != 0) { + mp_raise_OSError(_errno); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); + +//| def listen(self, backlog: int) -> None: +//| """Set socket to listen for incoming connections +//| +//| :param ~int backlog: length of backlog queue for waiting connetions""" +//| ... +//| + +STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (self->nic == MP_OBJ_NULL) { + // not connected + // TODO I think we can listen even if not bound... + mp_raise_OSError(MP_ENOTCONN); + } + + int _errno; + if (self->nic_type->listen(self, mp_obj_get_int(backlog), &_errno) != 0) { + mp_raise_OSError(_errno); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen); + +//| def accept(self) -> tuple: +//| """Accept a connection on a listening socket of type SOCK_STREAM, +//| creating a new socket of type SOCK_STREAM. +//| Returns a tuple of (new_socket, remote_address)""" +//| + +STATIC mp_obj_t socket_accept(mp_obj_t self_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // create new socket object + // starts with empty NIC so that finaliser doesn't run close() method if accept() fails + mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t); + socket2->base.type = &socket_type; + socket2->nic = MP_OBJ_NULL; + socket2->nic_type = NULL; + + // accept incoming connection + uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE]; + mp_uint_t port; + int _errno; + if (self->nic_type->accept(self, socket2, ip, &port, &_errno) != 0) { + mp_raise_OSError(_errno); + } + + // new socket has valid state, so set the NIC to the same as parent + socket2->nic = self->nic; + socket2->nic_type = self->nic_type; + + // make the return value + mp_obj_tuple_t *client = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + client->items[0] = MP_OBJ_FROM_PTR(socket2); + client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + + return MP_OBJ_FROM_PTR(client); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept); + +//| def connect(self, address: tuple) -> None: +//| """Connect a socket to a remote address +//| +//| :param ~tuple address: tuple of (remote_address, remote_port)""" +//| ... +//| + +STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // get address + uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE]; + mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG); + + // check if we need to select a NIC + socket_select_nic(self, ip); + + // call the NIC to connect the socket + int _errno; + if (self->nic_type->connect(self, ip, port, &_errno) != 0) { + mp_raise_OSError(_errno); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); + +//| def send(self, bytes: ReadableBuffer) -> int: +//| """Send some bytes to the connected remote address. +//| Suits sockets of type SOCK_STREAM +//| +//| :param ~bytes bytes: some bytes to send""" +//| ... +//| + +STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->nic == MP_OBJ_NULL) { + // not connected + mp_raise_OSError(MP_EPIPE); + } + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + int _errno; + mp_int_t ret = self->nic_type->send(self, bufinfo.buf, bufinfo.len, &_errno); + if (ret == -1) { + mp_raise_OSError(_errno); + } + return mp_obj_new_int_from_uint(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send); + + +// helper function for socket_recv and socket_recv_into to handle common operations of both +STATIC mp_int_t _socket_recv_into(mod_network_socket_obj_t *sock, byte *buf, mp_int_t len) { + int _errno; + mp_int_t ret = sock->nic_type->recv(sock, buf, len, &_errno); + if (ret == -1) { + mp_raise_OSError(_errno); + } + return ret; +} + + +//| def recv_into(self, buffer: WriteableBuffer, bufsize: int) -> int: +//| """Reads some bytes from the connected remote address, writing +//| into the provided buffer. If bufsize <= len(buffer) is given, +//| a maximum of bufsize bytes will be read into the buffer. If no +//| valid value is given for bufsize, the default is the length of +//| the given buffer. +//| +//| Suits sockets of type SOCK_STREAM +//| Returns an int of number of bytes read. +//| +//| :param bytearray buffer: buffer to receive into +//| :param int bufsize: optionally, a maximum number of bytes to read.""" +//| ... +//| + +STATIC mp_obj_t socket_recv_into(size_t n_args, const mp_obj_t *args) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (self->nic == MP_OBJ_NULL) { + // not connected + mp_raise_OSError(MP_ENOTCONN); + } + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); + mp_int_t len = bufinfo.len; + if (n_args == 3) { + mp_int_t given_len = mp_obj_get_int(args[2]); + if (given_len < len) { + len = given_len; + } + } + + mp_int_t ret = _socket_recv_into(self, (byte*)bufinfo.buf, len); + return mp_obj_new_int_from_uint(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_recv_into_obj, 2, 3, socket_recv_into); + +//| def recv(self, bufsize: int) -> bytes: +//| """Reads some bytes from the connected remote address. +//| Suits sockets of type SOCK_STREAM +//| Returns a bytes() of length <= bufsize +//| +//| :param ~int bufsize: maximum number of bytes to receive""" +//| ... +//| + +STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->nic == MP_OBJ_NULL) { + // not connected + mp_raise_OSError(MP_ENOTCONN); + } + mp_int_t len = mp_obj_get_int(len_in); + vstr_t vstr; + vstr_init_len(&vstr, len); + mp_int_t ret = _socket_recv_into(self, (byte*)vstr.buf, len); + if (ret == 0) { + return mp_const_empty_bytes; + } + vstr.len = ret; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv); + +//| def sendto(self, bytes: ReadableBuffer, address: tuple) -> int: +//| """Send some bytes to a specific address. +//| Suits sockets of type SOCK_DGRAM +//| +//| :param ~bytes bytes: some bytes to send +//| :param ~tuple address: tuple of (remote_address, remote_port)""" +//| ... +//| + +STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + + // get the data + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); + + // get address + uint8_t ip[MOD_NETWORK_IPADDR_BUF_SIZE]; + mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG); + + // check if we need to select a NIC + socket_select_nic(self, ip); + + // call the NIC to sendto + int _errno; + mp_int_t ret = self->nic_type->sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno); + if (ret == -1) { + mp_raise_OSError(_errno); + } + + return mp_obj_new_int(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto); + +//| def recvfrom(self, bufsize: int) -> Tuple[bytes, tuple]: +//| """Reads some bytes from the connected remote address. +//| Suits sockets of type SOCK_STREAM +//| +//| Returns a tuple containing +//| * a bytes() of length <= bufsize +//| * a remote_address, which is a tuple of ip address and port number +//| +//| :param ~int bufsize: maximum number of bytes to receive""" +//| ... +//| + +STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->nic == MP_OBJ_NULL) { + // not connected + mp_raise_OSError(MP_ENOTCONN); + } + vstr_t vstr; + vstr_init_len(&vstr, mp_obj_get_int(len_in)); + byte ip[4]; + mp_uint_t port; + int _errno; + mp_int_t ret = self->nic_type->recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno); + if (ret == -1) { + mp_raise_OSError(_errno); + } + mp_obj_t tuple[2]; + if (ret == 0) { + tuple[0] = mp_const_empty_bytes; + } else { + vstr.len = ret; + tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); + } + tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom); + +//| def setsockopt(self, level: int, optname: int, value: int) -> None: +//| """Sets socket options""" +//| ... +//| + +STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(args[0]); + + mp_int_t level = mp_obj_get_int(args[1]); + mp_int_t opt = mp_obj_get_int(args[2]); + + const void *optval; + mp_uint_t optlen; + mp_int_t val; + if (mp_obj_is_integer(args[3])) { + val = mp_obj_get_int_truncated(args[3]); + optval = &val; + optlen = sizeof(val); + } else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + optval = bufinfo.buf; + optlen = bufinfo.len; + } + + int _errno; + if (self->nic_type->setsockopt(self, level, opt, optval, optlen, &_errno) != 0) { + mp_raise_OSError(_errno); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); + +//| def settimeout(self, value: int) -> None: +//| """Set the timeout value for this socket. +//| +//| :param ~int value: timeout in seconds. 0 means non-blocking. None means block indefinitely.""" +//| ... +//| + +STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (self->nic == MP_OBJ_NULL) { + // not connected + mp_raise_OSError(MP_ENOTCONN); + } + mp_uint_t timeout; + if (timeout_in == mp_const_none) { + timeout = -1; + } else { + #if MICROPY_PY_BUILTINS_FLOAT + timeout = 1000 * mp_obj_get_float(timeout_in); + #else + timeout = 1000 * mp_obj_get_int(timeout_in); + #endif + } + int _errno; + if (self->nic_type->settimeout(self, timeout, &_errno) != 0) { + mp_raise_OSError(_errno); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout); + +//| def setblocking(self, flag: bool) -> Optional[int]: +//| """Set the blocking behaviour of this socket. +//| +//| :param ~bool flag: False means non-blocking, True means block indefinitely.""" +//| ... +//| + +// method socket.setblocking(flag) +STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) { + if (mp_obj_is_true(blocking)) { + return socket_settimeout(self_in, mp_const_none); + } else { + return socket_settimeout(self_in, MP_OBJ_NEW_SMALL_INT(0)); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); + +STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) }, + { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) }, + { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) }, + { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) }, + { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) }, + { MP_ROM_QSTR(MP_QSTR_recv_into), MP_ROM_PTR(&socket_recv_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) }, + { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) }, + { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); + +mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { + mod_network_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (request == MP_STREAM_CLOSE) { + if (self->nic != MP_OBJ_NULL) { + self->nic_type->close(self); + self->nic = MP_OBJ_NULL; + } + return 0; + } + return self->nic_type->ioctl(self, request, arg, errcode); +} + +STATIC const mp_stream_p_t socket_stream_p = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_stream) + .ioctl = socket_ioctl, + .is_text = false, +}; + +STATIC const mp_obj_type_t socket_type = { + { &mp_type_type }, + .name = MP_QSTR_socket, + .make_new = socket_make_new, + .protocol = &socket_stream_p, + .locals_dict = (mp_obj_dict_t*)&socket_locals_dict, +}; + +//| def getaddrinfo(host: str, port: int) -> tuple: +//| """Gets the address information for a hostname and port +//| +//| Returns the appropriate family, socket type, socket protocol and +//| address information to call socket.socket() and socket.connect() with, +//| as a tuple.""" +//| ... +//| + +STATIC mp_obj_t socket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) { + size_t hlen; + const char *host = mp_obj_str_get_data(host_in, &hlen); + mp_int_t port = mp_obj_get_int(port_in); + uint8_t out_ip[MOD_NETWORK_IPADDR_BUF_SIZE]; + bool have_ip = false; + + if (hlen > 0) { + // check if host is already in IP form + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + netutils_parse_ipv4_addr(host_in, out_ip, NETUTILS_BIG); + have_ip = true; + nlr_pop(); + } else { + // swallow exception: host was not in IP form so need to do DNS lookup + } + } + + if (!have_ip) { + // find a NIC that can do a name lookup + for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) { + mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i]; + mod_network_nic_type_t *nic_type = (mod_network_nic_type_t*)mp_obj_get_type(nic); + if (nic_type->gethostbyname != NULL) { + int ret = nic_type->gethostbyname(nic, host, hlen, out_ip); + if (ret != 0) { + mp_raise_OSError(ret); + } + have_ip = true; + break; + } + } + } + + if (!have_ip) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, translate("no available NIC"))); + } + + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET); + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM); + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0); + tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_); + tuple->items[4] = netutils_format_inet_addr(out_ip, port, NETUTILS_BIG); + return mp_obj_new_list(1, (mp_obj_t*)&tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_getaddrinfo_obj, socket_getaddrinfo); + +STATIC const mp_rom_map_elem_t socket_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) }, + + { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&socket_type) }, + { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&socket_getaddrinfo_obj) }, + + // class constants + { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(MOD_NETWORK_AF_INET) }, + { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(MOD_NETWORK_AF_INET6) }, + + { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(MOD_NETWORK_SOCK_STREAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(MOD_NETWORK_SOCK_DGRAM) }, + { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(MOD_NETWORK_SOCK_RAW) }, + + /* + { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(MOD_NETWORK_IPPROTO_IP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_ICMP), MP_ROM_INT(MOD_NETWORK_IPPROTO_ICMP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_IPV4), MP_ROM_INT(MOD_NETWORK_IPPROTO_IPV4) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(MOD_NETWORK_IPPROTO_TCP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_UDP), MP_ROM_INT(MOD_NETWORK_IPPROTO_UDP) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_IPV6), MP_ROM_INT(MOD_NETWORK_IPPROTO_IPV6) }, + { MP_ROM_QSTR(MP_QSTR_IPPROTO_RAW), MP_ROM_INT(MOD_NETWORK_IPPROTO_RAW) }, + */ +}; + +STATIC MP_DEFINE_CONST_DICT(socket_globals, socket_globals_table); + +const mp_obj_module_t socket_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&socket_globals, +}; diff --git a/shared-bindings/wifi/Radio.c b/shared-bindings/wifi/Radio.c index 1d1423573..6884b83de 100644 --- a/shared-bindings/wifi/Radio.c +++ b/shared-bindings/wifi/Radio.c @@ -158,18 +158,31 @@ const mp_obj_property_t wifi_radio_ipv4_address_obj = { (mp_obj_t)&mp_const_none_obj }, }; -//| def ping(self, ip) -> int: -//| """Ping an IP to test connectivity. Returns echo time in milliseconds.""" +//| def ping(self, ip, *, timeout: float = 0.5) -> float: +//| """Ping an IP to test connectivity. Returns echo time in seconds.""" //| ... //| -STATIC mp_obj_t wifi_radio_ping(mp_obj_t self_in, mp_obj_t ip_address) { - wifi_radio_obj_t *self = MP_OBJ_TO_PTR(self_in); +STATIC mp_obj_t wifi_radio_ping(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_ip, ARG_timeout }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_ip, MP_ARG_REQUIRED | MP_ARG_OBJ, }, + { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; - common_hal_wifi_radio_ping(self, ip_address); + wifi_radio_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - return mp_const_none; + mp_float_t timeout = 0.5; + if (args[ARG_timeout].u_obj != mp_const_none) { + timeout = mp_obj_get_float(args[ARG_timeout].u_obj); + } + + mp_int_t time_ms = common_hal_wifi_radio_ping(self, args[ARG_ip].u_obj, timeout); + + return mp_obj_new_float(time_ms / 1000); } -STATIC MP_DEFINE_CONST_FUN_OBJ_2(wifi_radio_ping_obj, wifi_radio_ping); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wifi_radio_ping_obj, 1, wifi_radio_ping); STATIC const mp_rom_map_elem_t wifi_radio_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_enabled), MP_ROM_PTR(&wifi_radio_enabled_obj) }, diff --git a/shared-bindings/wifi/Radio.h b/shared-bindings/wifi/Radio.h index 3890885ae..c83a135a6 100644 --- a/shared-bindings/wifi/Radio.h +++ b/shared-bindings/wifi/Radio.h @@ -47,6 +47,6 @@ extern bool common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t* ssid, extern mp_obj_t common_hal_wifi_radio_get_ipv4_address(wifi_radio_obj_t *self); -extern mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address); +extern mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address, mp_float_t timeout); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_WIFI_RADIO_H diff --git a/shared-module/ipaddress/__init__.c b/shared-module/ipaddress/__init__.c index e5d857d5d..031f317aa 100644 --- a/shared-module/ipaddress/__init__.c +++ b/shared-module/ipaddress/__init__.c @@ -33,3 +33,8 @@ mp_obj_t common_hal_ipaddress_new_ipv4address(mp_int_t value) { common_hal_ipaddress_ipv4address_construct(self, (uint8_t*) &value, 4); return self; } + + +void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t* esp_ip_address) { + // FIX THIS TOMORROW! +} diff --git a/shared-module/ipaddress/__init__.h b/shared-module/ipaddress/__init__.h index 7d5f2c220..9f1e00777 100644 --- a/shared-module/ipaddress/__init__.h +++ b/shared-module/ipaddress/__init__.h @@ -31,6 +31,10 @@ #include "py/obj.h" +#include "lwip/api.h" + mp_obj_t common_hal_ipaddress_new_ipv4(uint32_t value); +void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t* esp_ip_address); + #endif // MICROPY_INCLUDED_SHARED_MODULE_IPADDRESS___INIT___H -- cgit v1.2.3 From 7bdd243bf6f3cd84ddfd9cf6f35a2d6d8a6a415f Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 11 Aug 2020 14:50:37 -0700 Subject: Ping works! --- ports/esp32s2/common-hal/wifi/Radio.c | 1 + ports/esp32s2/common-hal/wifi/__init__.c | 14 ++++++++++++++ ports/esp32s2/common-hal/wifi/__init__.h | 4 ++++ shared-bindings/ipaddress/IPv4Address.h | 2 +- shared-bindings/ipaddress/__init__.c | 9 +++++---- shared-bindings/ipaddress/__init__.h | 2 +- shared-bindings/wifi/Radio.c | 2 +- shared-module/ipaddress/__init__.c | 7 +------ shared-module/ipaddress/__init__.h | 4 ---- 9 files changed, 28 insertions(+), 17 deletions(-) (limited to 'shared-module') diff --git a/ports/esp32s2/common-hal/wifi/Radio.c b/ports/esp32s2/common-hal/wifi/Radio.c index 49ad0592e..d4f17f2bb 100644 --- a/ports/esp32s2/common-hal/wifi/Radio.c +++ b/ports/esp32s2/common-hal/wifi/Radio.c @@ -28,6 +28,7 @@ #include +#include "common-hal/wifi/__init__.h" #include "lib/utils/interrupt_char.h" #include "py/runtime.h" #include "shared-bindings/ipaddress/IPv4Address.h" diff --git a/ports/esp32s2/common-hal/wifi/__init__.c b/ports/esp32s2/common-hal/wifi/__init__.c index 1dc9ef9a8..eb033256d 100644 --- a/ports/esp32s2/common-hal/wifi/__init__.c +++ b/ports/esp32s2/common-hal/wifi/__init__.c @@ -24,6 +24,9 @@ * THE SOFTWARE. */ +#include "common-hal/wifi/__init__.h" + +#include "shared-bindings/ipaddress/IPv4Address.h" #include "shared-bindings/wifi/Radio.h" #include "py/runtime.h" @@ -148,3 +151,14 @@ void wifi_reset(void) { radio->netif = NULL; ESP_ERROR_CHECK(esp_netif_deinit()); } + +void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t* esp_ip_address) { + if (!MP_OBJ_IS_TYPE(ip_address, &ipaddress_ipv4address_type)) { + mp_raise_ValueError(translate("Only IPv4 addresses supported")); + } + mp_obj_t packed = common_hal_ipaddress_ipv4address_get_packed(ip_address); + size_t len; + const char* bytes = mp_obj_str_get_data(packed, &len); + + IP_ADDR4(esp_ip_address, bytes[0], bytes[1], bytes[2], bytes[3]); +} diff --git a/ports/esp32s2/common-hal/wifi/__init__.h b/ports/esp32s2/common-hal/wifi/__init__.h index bb68bcfdf..d2bd06c57 100644 --- a/ports/esp32s2/common-hal/wifi/__init__.h +++ b/ports/esp32s2/common-hal/wifi/__init__.h @@ -29,6 +29,10 @@ #include "py/obj.h" +#include "lwip/api.h" + void wifi_reset(void); +void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t* esp_ip_address); + #endif // MICROPY_INCLUDED_ESP32S2_COMMON_HAL_WIFI___INIT___H diff --git a/shared-bindings/ipaddress/IPv4Address.h b/shared-bindings/ipaddress/IPv4Address.h index cf66b92b3..b45cf3bac 100644 --- a/shared-bindings/ipaddress/IPv4Address.h +++ b/shared-bindings/ipaddress/IPv4Address.h @@ -31,7 +31,7 @@ extern const mp_obj_type_t ipaddress_ipv4address_type; -mp_obj_t common_hal_ipaddress_new_ipv4address(mp_int_t value); +mp_obj_t common_hal_ipaddress_new_ipv4address(uint32_t value); void common_hal_ipaddress_ipv4address_construct(ipaddress_ipv4address_obj_t* self, uint8_t* buf, size_t len); mp_obj_t common_hal_ipaddress_ipv4address_get_packed(ipaddress_ipv4address_obj_t* self); diff --git a/shared-bindings/ipaddress/__init__.c b/shared-bindings/ipaddress/__init__.c index b88b3afbb..1c0ac9153 100644 --- a/shared-bindings/ipaddress/__init__.c +++ b/shared-bindings/ipaddress/__init__.c @@ -43,8 +43,8 @@ //| STATIC mp_obj_t ipaddress_ip_address(mp_obj_t ip_in) { - mp_int_t value; - if (mp_obj_get_int_maybe(ip_in, &value)) { + uint32_t value; + if (mp_obj_get_int_maybe(ip_in, (mp_int_t*) &value)) { // We're done. } else if (MP_OBJ_IS_STR(ip_in)) { GET_STR_DATA_LEN(ip_in, str_data, str_len); @@ -63,11 +63,12 @@ STATIC mp_obj_t ipaddress_ip_address(mp_obj_t ip_in) { } size_t last_period = 0; + value = 0; for (size_t i = 0; i < 4; i++) { mp_obj_t octet = mp_parse_num_integer((const char*) str_data + last_period, period_index[i] - last_period, 10, NULL); last_period = period_index[i] + 1; - value |= MP_OBJ_SMALL_INT_VALUE(octet) << (24 - i * 8); - + mp_int_t int_octet = MP_OBJ_SMALL_INT_VALUE(octet); + value |= int_octet << (i * 8); } } else { mp_raise_ValueError(translate("Only raw int supported for ip.")); diff --git a/shared-bindings/ipaddress/__init__.h b/shared-bindings/ipaddress/__init__.h index a31629cca..76d8bfa76 100644 --- a/shared-bindings/ipaddress/__init__.h +++ b/shared-bindings/ipaddress/__init__.h @@ -29,6 +29,6 @@ #include "shared-module/ipaddress/__init__.h" -mp_obj_t common_hal_ipaddress_new_ipv4address(mp_int_t value); +mp_obj_t common_hal_ipaddress_new_ipv4address(uint32_t value); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_IPADDRESS___INIT___H diff --git a/shared-bindings/wifi/Radio.c b/shared-bindings/wifi/Radio.c index 6884b83de..260a280c2 100644 --- a/shared-bindings/wifi/Radio.c +++ b/shared-bindings/wifi/Radio.c @@ -180,7 +180,7 @@ STATIC mp_obj_t wifi_radio_ping(size_t n_args, const mp_obj_t *pos_args, mp_map_ mp_int_t time_ms = common_hal_wifi_radio_ping(self, args[ARG_ip].u_obj, timeout); - return mp_obj_new_float(time_ms / 1000); + return mp_obj_new_float(time_ms / 1000.0); } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(wifi_radio_ping_obj, 1, wifi_radio_ping); diff --git a/shared-module/ipaddress/__init__.c b/shared-module/ipaddress/__init__.c index 031f317aa..2fce9d8f5 100644 --- a/shared-module/ipaddress/__init__.c +++ b/shared-module/ipaddress/__init__.c @@ -27,14 +27,9 @@ #include "shared-bindings/ipaddress/__init__.h" #include "shared-bindings/ipaddress/IPv4Address.h" -mp_obj_t common_hal_ipaddress_new_ipv4address(mp_int_t value) { +mp_obj_t common_hal_ipaddress_new_ipv4address(uint32_t value) { ipaddress_ipv4address_obj_t* self = m_new_obj(ipaddress_ipv4address_obj_t); self->base.type = &ipaddress_ipv4address_type; common_hal_ipaddress_ipv4address_construct(self, (uint8_t*) &value, 4); return self; } - - -void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t* esp_ip_address) { - // FIX THIS TOMORROW! -} diff --git a/shared-module/ipaddress/__init__.h b/shared-module/ipaddress/__init__.h index 9f1e00777..7d5f2c220 100644 --- a/shared-module/ipaddress/__init__.h +++ b/shared-module/ipaddress/__init__.h @@ -31,10 +31,6 @@ #include "py/obj.h" -#include "lwip/api.h" - mp_obj_t common_hal_ipaddress_new_ipv4(uint32_t value); -void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t* esp_ip_address); - #endif // MICROPY_INCLUDED_SHARED_MODULE_IPADDRESS___INIT___H -- cgit v1.2.3 From dc502a5f26fdf5514eb835fae5f523c1b15c23b5 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Fri, 21 Aug 2020 19:08:25 -0500 Subject: remove extraneous files --- shared-bindings/_typing/__init__ 2.pyi | 54 --- shared-bindings/gnss/GNSS 2.c | 205 ---------- shared-bindings/gnss/GNSS 2.h | 27 -- shared-bindings/gnss/PositionFix 2.c | 80 ---- shared-bindings/gnss/PositionFix 2.h | 28 -- shared-bindings/gnss/SatelliteSystem 2.c | 113 ------ shared-bindings/gnss/SatelliteSystem 2.h | 33 -- shared-bindings/gnss/__init__ 2.c | 31 -- shared-bindings/i2cperipheral/I2CPeripheral 2.c | 436 -------------------- shared-bindings/i2cperipheral/I2CPeripheral 2.h | 60 --- shared-bindings/i2cperipheral/__init__ 2.c | 106 ----- shared-bindings/memorymonitor/AllocationAlarm 2.c | 137 ------- shared-bindings/memorymonitor/AllocationAlarm 2.h | 39 -- shared-bindings/memorymonitor/AllocationSize 2.c | 183 --------- shared-bindings/memorymonitor/AllocationSize 2.h | 42 -- shared-bindings/memorymonitor/__init__ 2.c | 76 ---- shared-bindings/memorymonitor/__init__ 2.h | 49 --- shared-bindings/sdcardio/SDCard 2.c | 183 --------- shared-bindings/sdcardio/SDCard 2.h | 30 -- shared-bindings/sdcardio/__init__ 2.c | 47 --- shared-bindings/sdcardio/__init__ 2.h | 0 shared-module/sdcardio/SDCard 2.c | 466 ---------------------- shared-module/sdcardio/SDCard 2.h | 51 --- shared-module/sdcardio/__init__ 2.c | 0 shared-module/sdcardio/__init__ 2.h | 0 supervisor/background_callback 2.h | 87 ---- supervisor/shared/background_callback 2.c | 138 ------- 27 files changed, 2701 deletions(-) delete mode 100644 shared-bindings/_typing/__init__ 2.pyi delete mode 100644 shared-bindings/gnss/GNSS 2.c delete mode 100644 shared-bindings/gnss/GNSS 2.h delete mode 100644 shared-bindings/gnss/PositionFix 2.c delete mode 100644 shared-bindings/gnss/PositionFix 2.h delete mode 100644 shared-bindings/gnss/SatelliteSystem 2.c delete mode 100644 shared-bindings/gnss/SatelliteSystem 2.h delete mode 100644 shared-bindings/gnss/__init__ 2.c delete mode 100644 shared-bindings/i2cperipheral/I2CPeripheral 2.c delete mode 100644 shared-bindings/i2cperipheral/I2CPeripheral 2.h delete mode 100644 shared-bindings/i2cperipheral/__init__ 2.c delete mode 100644 shared-bindings/memorymonitor/AllocationAlarm 2.c delete mode 100644 shared-bindings/memorymonitor/AllocationAlarm 2.h delete mode 100644 shared-bindings/memorymonitor/AllocationSize 2.c delete mode 100644 shared-bindings/memorymonitor/AllocationSize 2.h delete mode 100644 shared-bindings/memorymonitor/__init__ 2.c delete mode 100644 shared-bindings/memorymonitor/__init__ 2.h delete mode 100644 shared-bindings/sdcardio/SDCard 2.c delete mode 100644 shared-bindings/sdcardio/SDCard 2.h delete mode 100644 shared-bindings/sdcardio/__init__ 2.c delete mode 100644 shared-bindings/sdcardio/__init__ 2.h delete mode 100644 shared-module/sdcardio/SDCard 2.c delete mode 100644 shared-module/sdcardio/SDCard 2.h delete mode 100644 shared-module/sdcardio/__init__ 2.c delete mode 100644 shared-module/sdcardio/__init__ 2.h delete mode 100644 supervisor/background_callback 2.h delete mode 100644 supervisor/shared/background_callback 2.c (limited to 'shared-module') diff --git a/shared-bindings/_typing/__init__ 2.pyi b/shared-bindings/_typing/__init__ 2.pyi deleted file mode 100644 index 48e68a8d5..000000000 --- a/shared-bindings/_typing/__init__ 2.pyi +++ /dev/null @@ -1,54 +0,0 @@ -"""Types for the C-level protocols""" - -from typing import Union - -import array -import audiocore -import audiomixer -import audiomp3 -import rgbmatrix -import ulab - -ReadableBuffer = Union[ - bytes, bytearray, memoryview, array.array, ulab.array, rgbmatrix.RGBMatrix -] -"""Classes that implement the readable buffer protocol - - - `bytes` - - `bytearray` - - `memoryview` - - `array.array` - - `ulab.array` - - `rgbmatrix.RGBMatrix` -""" - -WriteableBuffer = Union[ - bytearray, memoryview, array.array, ulab.array, rgbmatrix.RGBMatrix -] -"""Classes that implement the writeable buffer protocol - - - `bytearray` - - `memoryview` - - `array.array` - - `ulab.array` - - `rgbmatrix.RGBMatrix` -""" - -AudioSample = Union[ - audiocore.WaveFile, audiocore.RawSample, audiomixer.Mixer, audiomp3.MP3Decoder -] -"""Classes that implement the audiosample protocol - - - `audiocore.WaveFile` - - `audiocore.RawSample` - - `audiomixer.Mixer` - - `audiomp3.MP3Decoder` - - You can play these back with `audioio.AudioOut`, `audiobusio.I2SOut` or `audiopwmio.PWMAudioOut`. -""" - -FrameBuffer = Union[rgbmatrix.RGBMatrix] -"""Classes that implement the framebuffer protocol - - - `rgbmatrix.RGBMatrix` -""" diff --git a/shared-bindings/gnss/GNSS 2.c b/shared-bindings/gnss/GNSS 2.c deleted file mode 100644 index 087c35395..000000000 --- a/shared-bindings/gnss/GNSS 2.c +++ /dev/null @@ -1,205 +0,0 @@ -// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation -// -// SPDX-License-Identifier: MIT - -#include "shared-bindings/gnss/GNSS.h" -#include "shared-bindings/time/__init__.h" -#include "shared-bindings/util.h" - -#include "py/objproperty.h" -#include "py/runtime.h" - -//| class GNSS: -//| """Get updated positioning information from Global Navigation Satellite System (GNSS) -//| -//| Usage:: -//| -//| import gnss -//| import time -//| -//| nav = gnss.GNSS([gnss.SatelliteSystem.GPS, gnss.SatelliteSystem.GLONASS]) -//| last_print = time.monotonic() -//| while True: -//| nav.update() -//| current = time.monotonic() -//| if current - last_print >= 1.0: -//| last_print = current -//| if nav.fix is gnss.PositionFix.INVALID: -//| print("Waiting for fix...") -//| continue -//| print("Latitude: {0:.6f} degrees".format(nav.latitude)) -//| print("Longitude: {0:.6f} degrees".format(nav.longitude))""" -//| - -//| def __init__(self, system: Union[SatelliteSystem, List[SatelliteSystem]]) -> None: -//| """Turn on the GNSS. -//| -//| :param system: satellite system to use""" -//| ... -//| -STATIC mp_obj_t gnss_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - gnss_obj_t *self = m_new_obj(gnss_obj_t); - self->base.type = &gnss_type; - enum { ARG_system }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_system, MP_ARG_REQUIRED | MP_ARG_OBJ }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - unsigned long selection = 0; - if (MP_OBJ_IS_TYPE(args[ARG_system].u_obj, &gnss_satellitesystem_type)) { - selection |= gnss_satellitesystem_obj_to_type(args[ARG_system].u_obj); - } else if (MP_OBJ_IS_TYPE(args[ARG_system].u_obj, &mp_type_list)) { - size_t systems_size = 0; - mp_obj_t *systems; - mp_obj_list_get(args[ARG_system].u_obj, &systems_size, &systems); - for (size_t i = 0; i < systems_size; ++i) { - if (!MP_OBJ_IS_TYPE(systems[i], &gnss_satellitesystem_type)) { - mp_raise_TypeError(translate("System entry must be gnss.SatelliteSystem")); - } - selection |= gnss_satellitesystem_obj_to_type(systems[i]); - } - } else { - mp_raise_TypeError(translate("System entry must be gnss.SatelliteSystem")); - } - - common_hal_gnss_construct(self, selection); - return MP_OBJ_FROM_PTR(self); -} - -//| def deinit(self) -> None: -//| """Turn off the GNSS.""" -//| ... -//| -STATIC mp_obj_t gnss_obj_deinit(mp_obj_t self_in) { - gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_gnss_deinit(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(gnss_deinit_obj, gnss_obj_deinit); - -STATIC void check_for_deinit(gnss_obj_t *self) { - if (common_hal_gnss_deinited(self)) { - raise_deinited_error(); - } -} - -//| def update(self) -> None: -//| """Update GNSS positioning information.""" -//| ... -//| -STATIC mp_obj_t gnss_obj_update(mp_obj_t self_in) { - gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - - common_hal_gnss_update(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(gnss_update_obj, gnss_obj_update); - -//| latitude: float -//| """Latitude of current position in degrees (float).""" -//| -STATIC mp_obj_t gnss_obj_get_latitude(mp_obj_t self_in) { - gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return mp_obj_new_float(common_hal_gnss_get_latitude(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_latitude_obj, gnss_obj_get_latitude); - -const mp_obj_property_t gnss_latitude_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&gnss_get_latitude_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| longitude: float -//| """Longitude of current position in degrees (float).""" -//| -STATIC mp_obj_t gnss_obj_get_longitude(mp_obj_t self_in) { - gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return mp_obj_new_float(common_hal_gnss_get_longitude(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_longitude_obj, gnss_obj_get_longitude); - -const mp_obj_property_t gnss_longitude_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&gnss_get_longitude_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| altitude: float -//| """Altitude of current position in meters (float).""" -//| -STATIC mp_obj_t gnss_obj_get_altitude(mp_obj_t self_in) { - gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return mp_obj_new_float(common_hal_gnss_get_altitude(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_altitude_obj, gnss_obj_get_altitude); - -const mp_obj_property_t gnss_altitude_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&gnss_get_altitude_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| timestamp: time.struct_time -//| """Time when the position data was updated.""" -//| -STATIC mp_obj_t gnss_obj_get_timestamp(mp_obj_t self_in) { - gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - timeutils_struct_time_t tm; - common_hal_gnss_get_timestamp(self, &tm); - return struct_time_from_tm(&tm); -} -MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_timestamp_obj, gnss_obj_get_timestamp); - -const mp_obj_property_t gnss_timestamp_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&gnss_get_timestamp_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| fix: PositionFix -//| """Fix mode.""" -//| -STATIC mp_obj_t gnss_obj_get_fix(mp_obj_t self_in) { - gnss_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return gnss_positionfix_type_to_obj(common_hal_gnss_get_fix(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(gnss_get_fix_obj, gnss_obj_get_fix); - -const mp_obj_property_t gnss_fix_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&gnss_get_fix_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -STATIC const mp_rom_map_elem_t gnss_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&gnss_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_update), MP_ROM_PTR(&gnss_update_obj) }, - - { MP_ROM_QSTR(MP_QSTR_latitude), MP_ROM_PTR(&gnss_latitude_obj) }, - { MP_ROM_QSTR(MP_QSTR_longitude), MP_ROM_PTR(&gnss_longitude_obj) }, - { MP_ROM_QSTR(MP_QSTR_altitude), MP_ROM_PTR(&gnss_altitude_obj) }, - { MP_ROM_QSTR(MP_QSTR_timestamp), MP_ROM_PTR(&gnss_timestamp_obj) }, - { MP_ROM_QSTR(MP_QSTR_fix), MP_ROM_PTR(&gnss_fix_obj) } -}; -STATIC MP_DEFINE_CONST_DICT(gnss_locals_dict, gnss_locals_dict_table); - -const mp_obj_type_t gnss_type = { - { &mp_type_type }, - .name = MP_QSTR_GNSS, - .make_new = gnss_make_new, - .locals_dict = (mp_obj_dict_t*)&gnss_locals_dict, -}; diff --git a/shared-bindings/gnss/GNSS 2.h b/shared-bindings/gnss/GNSS 2.h deleted file mode 100644 index 60069a90a..000000000 --- a/shared-bindings/gnss/GNSS 2.h +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation -// -// SPDX-License-Identifier: MIT - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_GNSS_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_GNSS_H - -#include "common-hal/gnss/GNSS.h" -#include "shared-bindings/gnss/SatelliteSystem.h" -#include "shared-bindings/gnss/PositionFix.h" - -#include "lib/timeutils/timeutils.h" - -extern const mp_obj_type_t gnss_type; - -void common_hal_gnss_construct(gnss_obj_t *self, unsigned long selection); -void common_hal_gnss_deinit(gnss_obj_t *self); -bool common_hal_gnss_deinited(gnss_obj_t *self); -void common_hal_gnss_update(gnss_obj_t *self); - -mp_float_t common_hal_gnss_get_latitude(gnss_obj_t *self); -mp_float_t common_hal_gnss_get_longitude(gnss_obj_t *self); -mp_float_t common_hal_gnss_get_altitude(gnss_obj_t *self); -void common_hal_gnss_get_timestamp(gnss_obj_t *self, timeutils_struct_time_t *tm); -gnss_positionfix_t common_hal_gnss_get_fix(gnss_obj_t *self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_GNSS_H diff --git a/shared-bindings/gnss/PositionFix 2.c b/shared-bindings/gnss/PositionFix 2.c deleted file mode 100644 index e60611d70..000000000 --- a/shared-bindings/gnss/PositionFix 2.c +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation -// -// SPDX-License-Identifier: MIT - -#include "shared-bindings/gnss/PositionFix.h" - -//| class PositionFix: -//| """Position fix mode""" -//| -//| def __init__(self) -> None: -//| """Enum-like class to define the position fix mode.""" -//| -//| INVALID: PositionFix -//| """No measurement.""" -//| -//| FIX_2D: PositionFix -//| """2D fix.""" -//| -//| FIX_3D: PositionFix -//| """3D fix.""" -//| -const mp_obj_type_t gnss_positionfix_type; - -const gnss_positionfix_obj_t gnss_positionfix_invalid_obj = { - { &gnss_positionfix_type }, -}; - -const gnss_positionfix_obj_t gnss_positionfix_fix2d_obj = { - { &gnss_positionfix_type }, -}; - -const gnss_positionfix_obj_t gnss_positionfix_fix3d_obj = { - { &gnss_positionfix_type }, -}; - -gnss_positionfix_t gnss_positionfix_obj_to_type(mp_obj_t obj) { - gnss_positionfix_t posfix = POSITIONFIX_INVALID; - if (obj == MP_ROM_PTR(&gnss_positionfix_fix2d_obj)) { - posfix = POSITIONFIX_2D; - } else if (obj == MP_ROM_PTR(&gnss_positionfix_fix3d_obj)) { - posfix = POSITIONFIX_3D; - } - return posfix; -} - -mp_obj_t gnss_positionfix_type_to_obj(gnss_positionfix_t posfix) { - switch (posfix) { - case POSITIONFIX_2D: - return (mp_obj_t)MP_ROM_PTR(&gnss_positionfix_fix2d_obj); - case POSITIONFIX_3D: - return (mp_obj_t)MP_ROM_PTR(&gnss_positionfix_fix3d_obj); - case POSITIONFIX_INVALID: - default: - return (mp_obj_t)MP_ROM_PTR(&gnss_positionfix_invalid_obj); - } -} - -STATIC const mp_rom_map_elem_t gnss_positionfix_locals_dict_table[] = { - {MP_ROM_QSTR(MP_QSTR_INVALID), MP_ROM_PTR(&gnss_positionfix_invalid_obj)}, - {MP_ROM_QSTR(MP_QSTR_FIX_2D), MP_ROM_PTR(&gnss_positionfix_fix2d_obj)}, - {MP_ROM_QSTR(MP_QSTR_FIX_3D), MP_ROM_PTR(&gnss_positionfix_fix3d_obj)}, -}; -STATIC MP_DEFINE_CONST_DICT(gnss_positionfix_locals_dict, gnss_positionfix_locals_dict_table); - -STATIC void gnss_positionfix_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - qstr posfix = MP_QSTR_INVALID; - if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_positionfix_fix2d_obj)) { - posfix = MP_QSTR_FIX_2D; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_positionfix_fix3d_obj)) { - posfix = MP_QSTR_FIX_3D; - } - mp_printf(print, "%q.%q.%q", MP_QSTR_gnss, MP_QSTR_PositionFix, posfix); -} - -const mp_obj_type_t gnss_positionfix_type = { - { &mp_type_type }, - .name = MP_QSTR_PositionFix, - .print = gnss_positionfix_print, - .locals_dict = (mp_obj_t)&gnss_positionfix_locals_dict, -}; diff --git a/shared-bindings/gnss/PositionFix 2.h b/shared-bindings/gnss/PositionFix 2.h deleted file mode 100644 index 34090872c..000000000 --- a/shared-bindings/gnss/PositionFix 2.h +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation -// -// SPDX-License-Identifier: MIT - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_POSITIONFIX_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_POSITIONFIX_H - -#include "py/obj.h" - -typedef enum { - POSITIONFIX_INVALID, - POSITIONFIX_2D, - POSITIONFIX_3D, -} gnss_positionfix_t; - -const mp_obj_type_t gnss_positionfix_type; - -gnss_positionfix_t gnss_positionfix_obj_to_type(mp_obj_t obj); -mp_obj_t gnss_positionfix_type_to_obj(gnss_positionfix_t mode); - -typedef struct { - mp_obj_base_t base; -} gnss_positionfix_obj_t; -extern const gnss_positionfix_obj_t gnss_positionfix_invalid_obj; -extern const gnss_positionfix_obj_t gnss_positionfix_fix2d_obj; -extern const gnss_positionfix_obj_t gnss_positionfix_fix3d_obj; - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_POSITIONFIX_H diff --git a/shared-bindings/gnss/SatelliteSystem 2.c b/shared-bindings/gnss/SatelliteSystem 2.c deleted file mode 100644 index 7d66727b8..000000000 --- a/shared-bindings/gnss/SatelliteSystem 2.c +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation -// -// SPDX-License-Identifier: MIT - -#include "shared-bindings/gnss/SatelliteSystem.h" - -//| class SatelliteSystem: -//| """Satellite system type""" -//| -//| def __init__(self) -> None: -//| """Enum-like class to define the satellite system type.""" -//| -//| GPS: SatelliteSystem -//| """Global Positioning System.""" -//| -//| GLONASS: SatelliteSystem -//| """GLObal NAvigation Satellite System.""" -//| -//| SBAS: SatelliteSystem -//| """Satellite Based Augmentation System.""" -//| -//| QZSS_L1CA: SatelliteSystem -//| """Quasi-Zenith Satellite System L1C/A.""" -//| -//| QZSS_L1S: SatelliteSystem -//| """Quasi-Zenith Satellite System L1S.""" -//| -const mp_obj_type_t gnss_satellitesystem_type; - -const gnss_satellitesystem_obj_t gnss_satellitesystem_gps_obj = { - { &gnss_satellitesystem_type }, -}; - -const gnss_satellitesystem_obj_t gnss_satellitesystem_glonass_obj = { - { &gnss_satellitesystem_type }, -}; - -const gnss_satellitesystem_obj_t gnss_satellitesystem_sbas_obj = { - { &gnss_satellitesystem_type }, -}; - -const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1ca_obj = { - { &gnss_satellitesystem_type }, -}; - -const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1s_obj = { - { &gnss_satellitesystem_type }, -}; - -gnss_satellitesystem_t gnss_satellitesystem_obj_to_type(mp_obj_t obj) { - if (obj == MP_ROM_PTR(&gnss_satellitesystem_gps_obj)) { - return SATELLITESYSTEM_GPS; - } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_glonass_obj)) { - return SATELLITESYSTEM_GLONASS; - } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_sbas_obj)) { - return SATELLITESYSTEM_SBAS; - } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj)) { - return SATELLITESYSTEM_QZSS_L1CA; - } else if (obj == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj)) { - return SATELLITESYSTEM_QZSS_L1S; - } - return SATELLITESYSTEM_NONE; -} - -mp_obj_t gnss_satellitesystem_type_to_obj(gnss_satellitesystem_t system) { - switch (system) { - case SATELLITESYSTEM_GPS: - return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_gps_obj); - case SATELLITESYSTEM_GLONASS: - return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_glonass_obj); - case SATELLITESYSTEM_SBAS: - return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_sbas_obj); - case SATELLITESYSTEM_QZSS_L1CA: - return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj); - case SATELLITESYSTEM_QZSS_L1S: - return (mp_obj_t)MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj); - case SATELLITESYSTEM_NONE: - default: - return (mp_obj_t)MP_ROM_PTR(&mp_const_none_obj); - } -} - -STATIC const mp_rom_map_elem_t gnss_satellitesystem_locals_dict_table[] = { - {MP_ROM_QSTR(MP_QSTR_GPS), MP_ROM_PTR(&gnss_satellitesystem_gps_obj)}, - {MP_ROM_QSTR(MP_QSTR_GLONASS), MP_ROM_PTR(&gnss_satellitesystem_glonass_obj)}, - {MP_ROM_QSTR(MP_QSTR_SBAS), MP_ROM_PTR(&gnss_satellitesystem_sbas_obj)}, - {MP_ROM_QSTR(MP_QSTR_QZSS_L1CA), MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj)}, - {MP_ROM_QSTR(MP_QSTR_QZSS_L1S), MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj)}, -}; -STATIC MP_DEFINE_CONST_DICT(gnss_satellitesystem_locals_dict, gnss_satellitesystem_locals_dict_table); - -STATIC void gnss_satellitesystem_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { - qstr system = MP_QSTR_None; - if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_gps_obj)) { - system = MP_QSTR_GPS; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_glonass_obj)) { - system = MP_QSTR_GLONASS; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_sbas_obj)) { - system = MP_QSTR_SBAS; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1ca_obj)) { - system = MP_QSTR_QZSS_L1CA; - } else if (MP_OBJ_TO_PTR(self_in) == MP_ROM_PTR(&gnss_satellitesystem_qzss_l1s_obj)) { - system = MP_QSTR_QZSS_L1S; - } - mp_printf(print, "%q.%q.%q", MP_QSTR_gnss, MP_QSTR_SatelliteSystem, system); -} - -const mp_obj_type_t gnss_satellitesystem_type = { - { &mp_type_type }, - .name = MP_QSTR_SatelliteSystem, - .print = gnss_satellitesystem_print, - .locals_dict = (mp_obj_t)&gnss_satellitesystem_locals_dict, -}; diff --git a/shared-bindings/gnss/SatelliteSystem 2.h b/shared-bindings/gnss/SatelliteSystem 2.h deleted file mode 100644 index 17f155002..000000000 --- a/shared-bindings/gnss/SatelliteSystem 2.h +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation -// -// SPDX-License-Identifier: MIT - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_SATELLITESYSTEM_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_SATELLITESYSTEM_H - -#include "py/obj.h" - -typedef enum { - SATELLITESYSTEM_NONE = 0, - SATELLITESYSTEM_GPS = (1U << 0), - SATELLITESYSTEM_GLONASS = (1U << 1), - SATELLITESYSTEM_SBAS = (1U << 2), - SATELLITESYSTEM_QZSS_L1CA = (1U << 3), - SATELLITESYSTEM_QZSS_L1S = (1U << 4), -} gnss_satellitesystem_t; - -const mp_obj_type_t gnss_satellitesystem_type; - -gnss_satellitesystem_t gnss_satellitesystem_obj_to_type(mp_obj_t obj); -mp_obj_t gnss_satellitesystem_type_to_obj(gnss_satellitesystem_t mode); - -typedef struct { - mp_obj_base_t base; -} gnss_satellitesystem_obj_t; -extern const gnss_satellitesystem_obj_t gnss_satellitesystem_gps_obj; -extern const gnss_satellitesystem_obj_t gnss_satellitesystem_glonass_obj; -extern const gnss_satellitesystem_obj_t gnss_satellitesystem_sbas_obj; -extern const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1ca_obj; -extern const gnss_satellitesystem_obj_t gnss_satellitesystem_qzss_l1s_obj; - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_GNSS_SATELLITESYSTEM_H diff --git a/shared-bindings/gnss/__init__ 2.c b/shared-bindings/gnss/__init__ 2.c deleted file mode 100644 index 4b0d312ae..000000000 --- a/shared-bindings/gnss/__init__ 2.c +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-FileCopyrightText: Sony Semiconductor Solutions Corporation -// -// SPDX-License-Identifier: MIT - -#include "py/obj.h" -#include "py/runtime.h" -#include "py/mphal.h" -#include "shared-bindings/gnss/GNSS.h" -#include "shared-bindings/gnss/SatelliteSystem.h" -#include "shared-bindings/gnss/PositionFix.h" -#include "shared-bindings/util.h" - -//| """Global Navigation Satellite System -//| -//| The `gnss` module contains classes to control the GNSS and acquire positioning information.""" -//| -STATIC const mp_rom_map_elem_t gnss_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_gnss) }, - { MP_ROM_QSTR(MP_QSTR_GNSS), MP_ROM_PTR(&gnss_type) }, - - // Enum-like Classes. - { MP_ROM_QSTR(MP_QSTR_SatelliteSystem), MP_ROM_PTR(&gnss_satellitesystem_type) }, - { MP_ROM_QSTR(MP_QSTR_PositionFix), MP_ROM_PTR(&gnss_positionfix_type) }, -}; - -STATIC MP_DEFINE_CONST_DICT(gnss_module_globals, gnss_module_globals_table); - -const mp_obj_module_t gnss_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&gnss_module_globals, -}; diff --git a/shared-bindings/i2cperipheral/I2CPeripheral 2.c b/shared-bindings/i2cperipheral/I2CPeripheral 2.c deleted file mode 100644 index b5ac861b4..000000000 --- a/shared-bindings/i2cperipheral/I2CPeripheral 2.c +++ /dev/null @@ -1,436 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Noralf Trønnes - * - * 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 "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/i2cperipheral/I2CPeripheral.h" -#include "shared-bindings/time/__init__.h" -#include "shared-bindings/util.h" - -#include "lib/utils/buffer_helper.h" -#include "lib/utils/context_manager_helpers.h" -#include "lib/utils/interrupt_char.h" - -#include "py/mperrno.h" -#include "py/mphal.h" -#include "py/obj.h" -#include "py/objproperty.h" -#include "py/runtime.h" - -STATIC mp_obj_t mp_obj_new_i2cperipheral_i2c_peripheral_request(i2cperipheral_i2c_peripheral_obj_t *peripheral, uint8_t address, bool is_read, bool is_restart) { - i2cperipheral_i2c_peripheral_request_obj_t *self = m_new_obj(i2cperipheral_i2c_peripheral_request_obj_t); - self->base.type = &i2cperipheral_i2c_peripheral_request_type; - self->peripheral = peripheral; - self->address = address; - self->is_read = is_read; - self->is_restart = is_restart; - return (mp_obj_t)self; -} - -//| class I2CPeripheral: -//| """Two wire serial protocol peripheral""" -//| -//| def __init__(self, scl: microcontroller.Pin, sda: microcontroller.Pin, addresses: Sequence[int], smbus: bool = False) -> None: -//| """I2C is a two-wire protocol for communicating between devices. -//| This implements the peripheral (sensor, secondary) side. -//| -//| :param ~microcontroller.Pin scl: The clock pin -//| :param ~microcontroller.Pin sda: The data pin -//| :param addresses: The I2C addresses to respond to (how many is hw dependent). -//| :type addresses: list[int] -//| :param bool smbus: Use SMBUS timings if the hardware supports it""" -//| ... -//| -STATIC mp_obj_t i2cperipheral_i2c_peripheral_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - i2cperipheral_i2c_peripheral_obj_t *self = m_new_obj(i2cperipheral_i2c_peripheral_obj_t); - self->base.type = &i2cperipheral_i2c_peripheral_type; - enum { ARG_scl, ARG_sda, ARG_addresses, ARG_smbus }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_sda, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_addresses, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_smbus, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - const mcu_pin_obj_t* scl = validate_obj_is_free_pin(args[ARG_scl].u_obj); - const mcu_pin_obj_t* sda = validate_obj_is_free_pin(args[ARG_sda].u_obj); - - mp_obj_iter_buf_t iter_buf; - mp_obj_t iterable = mp_getiter(args[ARG_addresses].u_obj, &iter_buf); - mp_obj_t item; - uint8_t *addresses = NULL; - unsigned int i = 0; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - mp_int_t value; - if (!mp_obj_get_int_maybe(item, &value)) { - mp_raise_TypeError_varg(translate("can't convert %q to %q"), MP_QSTR_address, MP_QSTR_int); - } - if (value < 0x00 || value > 0x7f) { - mp_raise_ValueError(translate("address out of bounds")); - } - addresses = m_renew(uint8_t, addresses, i, i + 1); - addresses[i++] = value; - } - if (i == 0) { - mp_raise_ValueError(translate("addresses is empty")); - } - - common_hal_i2cperipheral_i2c_peripheral_construct(self, scl, sda, addresses, i, args[ARG_smbus].u_bool); - return (mp_obj_t)self; -} - -//| def deinit(self) -> None: -//| """Releases control of the underlying hardware so other classes can use it.""" -//| ... -//| -STATIC mp_obj_t i2cperipheral_i2c_peripheral_obj_deinit(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_type)); - i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_i2cperipheral_i2c_peripheral_deinit(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(i2cperipheral_i2c_peripheral_deinit_obj, i2cperipheral_i2c_peripheral_obj_deinit); - -//| def __enter__(self) -> I2CPeripheral: -//| """No-op used in Context Managers.""" -//| ... -//| -// Provided by context manager helper. - -//| def __exit__(self) -> None: -//| """Automatically deinitializes the hardware on context exit. See -//| :ref:`lifetime-and-contextmanagers` for more info.""" -//| ... -//| -STATIC mp_obj_t i2cperipheral_i2c_peripheral_obj___exit__(size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_TYPE(args[0], &i2cperipheral_i2c_peripheral_type)); - i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(args[0]); - common_hal_i2cperipheral_i2c_peripheral_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral___exit___obj, 4, 4, i2cperipheral_i2c_peripheral_obj___exit__); - -//| def request(self, timeout: float = -1) -> I2CPeripheralRequest: -//| """Wait for an I2C request. -//| -//| :param float timeout: Timeout in seconds. Zero means wait forever, a negative value means check once -//| :return: I2C Slave Request or None if timeout=-1 and there's no request -//| :rtype: ~i2cperipheral.I2CPeripheralRequest""" -//| -STATIC mp_obj_t i2cperipheral_i2c_peripheral_request(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &i2cperipheral_i2c_peripheral_type)); - i2cperipheral_i2c_peripheral_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - if(common_hal_i2cperipheral_i2c_peripheral_deinited(self)) { - raise_deinited_error(); - } - enum { ARG_timeout }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - #if MICROPY_PY_BUILTINS_FLOAT - float f = mp_obj_get_float(args[ARG_timeout].u_obj) * 1000; - int timeout_ms = (int)f; - #else - int timeout_ms = mp_obj_get_int(args[ARG_timeout].u_obj) * 1000; - #endif - - bool forever = false; - uint64_t timeout_end = 0; - if (timeout_ms == 0) { - forever = true; - } else if (timeout_ms > 0) { - timeout_end = common_hal_time_monotonic() + timeout_ms; - } - - int last_error = 0; - - do { - uint8_t address; - bool is_read; - bool is_restart; - - RUN_BACKGROUND_TASKS; - if (mp_hal_is_interrupted()) { - return mp_const_none; - } - - int status = common_hal_i2cperipheral_i2c_peripheral_is_addressed(self, &address, &is_read, &is_restart); - if (status < 0) { - // On error try one more time before bailing out - if (last_error) { - mp_raise_OSError(last_error); - } - last_error = -status; - mp_hal_delay_ms(10); - continue; - } - - last_error = 0; - - if (status == 0) { - mp_hal_delay_us(10); - continue; - } - - return mp_obj_new_i2cperipheral_i2c_peripheral_request(self, address, is_read, is_restart); - } while (forever || common_hal_time_monotonic() < timeout_end); - - if (timeout_ms > 0) { - mp_raise_OSError(MP_ETIMEDOUT); - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(i2cperipheral_i2c_peripheral_request_obj, 1, i2cperipheral_i2c_peripheral_request); - -STATIC const mp_rom_map_elem_t i2cperipheral_i2c_peripheral_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&i2cperipheral_i2c_peripheral___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_request), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_obj) }, - -}; - -STATIC MP_DEFINE_CONST_DICT(i2cperipheral_i2c_peripheral_locals_dict, i2cperipheral_i2c_peripheral_locals_dict_table); - -const mp_obj_type_t i2cperipheral_i2c_peripheral_type = { - { &mp_type_type }, - .name = MP_QSTR_I2CPeripheral, - .make_new = i2cperipheral_i2c_peripheral_make_new, - .locals_dict = (mp_obj_dict_t*)&i2cperipheral_i2c_peripheral_locals_dict, -}; - -//| class I2CPeripheralRequest: -//| -//| def __init__(self, peripheral: i2cperipheral.I2CPeripheral, address: int, is_read: bool, is_restart: bool) -> None: -//| """Information about an I2C transfer request -//| This cannot be instantiated directly, but is returned by :py:meth:`I2CPeripheral.request`. -//| -//| :param peripheral: The I2CPeripheral object receiving this request -//| :param address: I2C address -//| :param is_read: True if the main peripheral is requesting data -//| :param is_restart: Repeated Start Condition""" -//| -STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - mp_arg_check_num(n_args, kw_args, 4, 4, false); - return mp_obj_new_i2cperipheral_i2c_peripheral_request(args[0], mp_obj_get_int(args[1]), mp_obj_is_true(args[2]), mp_obj_is_true(args[3])); -} - -//| def __enter__(self) -> I2CPeripheralRequest: -//| """No-op used in Context Managers.""" -//| ... -//| -// Provided by context manager helper. - -//| def __exit__(self) -> None: -//| """Close the request.""" -//| ... -//| -STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_obj___exit__(size_t n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_TYPE(args[0], &i2cperipheral_i2c_peripheral_request_type)); - i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(args[0]); - common_hal_i2cperipheral_i2c_peripheral_close(self->peripheral); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral_request___exit___obj, 4, 4, i2cperipheral_i2c_peripheral_request_obj___exit__); - -//| address: int -//| """The I2C address of the request.""" -//| -STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_address(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); - i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int(self->address); -} -MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_address_obj, i2cperipheral_i2c_peripheral_request_get_address); - -//| is_read: bool -//| """The I2C main controller is reading from this peripheral.""" -//| -STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_is_read(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); - i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_bool(self->is_read); -} -MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_is_read_obj, i2cperipheral_i2c_peripheral_request_get_is_read); - -//| is_restart: bool -//| """Is Repeated Start Condition.""" -//| -STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_get_is_restart(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); - i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_bool(self->is_restart); -} -MP_DEFINE_CONST_PROP_GET(i2cperipheral_i2c_peripheral_request_is_restart_obj, i2cperipheral_i2c_peripheral_request_get_is_restart); - -//| def read(self, n: int = -1, ack: bool = True) -> bytearray: -//| """Read data. -//| If ack=False, the caller is responsible for calling :py:meth:`I2CPeripheralRequest.ack`. -//| -//| :param n: Number of bytes to read (negative means all) -//| :param ack: Whether or not to send an ACK after the n'th byte -//| :return: Bytes read""" -//| ... -//| -STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - mp_check_self(MP_OBJ_IS_TYPE(pos_args[0], &i2cperipheral_i2c_peripheral_request_type)); - i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - enum { ARG_n, ARG_ack }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_n, MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_ack, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - if (self->is_read) { - mp_raise_OSError(MP_EACCES); - } - - int n = args[ARG_n].u_int; - if (n == 0) { - return mp_obj_new_bytearray(0, NULL); - } - bool ack = args[ARG_ack].u_bool; - - int i = 0; - uint8_t *buffer = NULL; - uint64_t timeout_end = common_hal_time_monotonic() + 10 * 1000; - while (common_hal_time_monotonic() < timeout_end) { - RUN_BACKGROUND_TASKS; - if (mp_hal_is_interrupted()) { - break; - } - - uint8_t data; - int num = common_hal_i2cperipheral_i2c_peripheral_read_byte(self->peripheral, &data); - if (num == 0) { - break; - } - - buffer = m_renew(uint8_t, buffer, i, i + 1); - buffer[i++] = data; - if (i == n) { - if (ack) { - common_hal_i2cperipheral_i2c_peripheral_ack(self->peripheral, true); - } - break; - } - common_hal_i2cperipheral_i2c_peripheral_ack(self->peripheral, true); - } - - return mp_obj_new_bytearray(i, buffer); -} -MP_DEFINE_CONST_FUN_OBJ_KW(i2cperipheral_i2c_peripheral_request_read_obj, 1, i2cperipheral_i2c_peripheral_request_read); - -//| def write(self, buffer: ReadableBuffer) -> int: -//| """Write the data contained in buffer. -//| -//| :param ~_typing.ReadableBuffer buffer: Write out the data in this buffer -//| :return: Number of bytes written""" -//| ... -//| -STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_write(mp_obj_t self_in, mp_obj_t buf_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); - i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); - - if (!self->is_read) { - mp_raise_OSError(MP_EACCES); - } - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); - - for (size_t i = 0; i < bufinfo.len; i++) { - RUN_BACKGROUND_TASKS; - if (mp_hal_is_interrupted()) { - break; - } - - int num = common_hal_i2cperipheral_i2c_peripheral_write_byte(self->peripheral, ((uint8_t *)(bufinfo.buf))[i]); - if (num == 0) { - return mp_obj_new_int(i); - } - } - - return mp_obj_new_int(bufinfo.len); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(i2cperipheral_i2c_peripheral_request_write_obj, i2cperipheral_i2c_peripheral_request_write); - -//| def ack(self, ack: bool = True) -> None: -//| """Acknowledge or Not Acknowledge last byte received. -//| Use together with :py:meth:`I2CPeripheralRequest.read` ack=False. -//| -//| :param ack: Whether to send an ACK or NACK""" -//| ... -//| -STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_ack(uint n_args, const mp_obj_t *args) { - mp_check_self(MP_OBJ_IS_TYPE(args[0], &i2cperipheral_i2c_peripheral_request_type)); - i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(args[0]); - bool ack = (n_args == 1) ? true : mp_obj_is_true(args[1]); - - if (self->is_read) { - mp_raise_OSError(MP_EACCES); - } - - common_hal_i2cperipheral_i2c_peripheral_ack(self->peripheral, ack); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cperipheral_i2c_peripheral_request_ack_obj, 1, 2, i2cperipheral_i2c_peripheral_request_ack); - -STATIC mp_obj_t i2cperipheral_i2c_peripheral_request_close(mp_obj_t self_in) { - mp_check_self(MP_OBJ_IS_TYPE(self_in, &i2cperipheral_i2c_peripheral_request_type)); - i2cperipheral_i2c_peripheral_request_obj_t *self = MP_OBJ_TO_PTR(self_in); - - common_hal_i2cperipheral_i2c_peripheral_close(self->peripheral); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(i2cperipheral_i2c_peripheral_request_close_obj, i2cperipheral_i2c_peripheral_request_close); - -STATIC const mp_rom_map_elem_t i2cperipheral_i2c_peripheral_request_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_address_obj) }, - { MP_ROM_QSTR(MP_QSTR_is_read), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_is_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_is_restart), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_is_restart_obj) }, - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_ack), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_ack_obj) }, - { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_request_close_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(i2cperipheral_i2c_peripheral_request_locals_dict, i2cperipheral_i2c_peripheral_request_locals_dict_table); - -const mp_obj_type_t i2cperipheral_i2c_peripheral_request_type = { - { &mp_type_type }, - .name = MP_QSTR_I2CPeripheralRequest, - .make_new = i2cperipheral_i2c_peripheral_request_make_new, - .locals_dict = (mp_obj_dict_t*)&i2cperipheral_i2c_peripheral_request_locals_dict, -}; diff --git a/shared-bindings/i2cperipheral/I2CPeripheral 2.h b/shared-bindings/i2cperipheral/I2CPeripheral 2.h deleted file mode 100644 index 3035cfbfe..000000000 --- a/shared-bindings/i2cperipheral/I2CPeripheral 2.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Noralf Trønnes - * - * 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_SHARED_BINDINGS_BUSIO_I2C_SLAVE_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_SLAVE_H - -#include "py/obj.h" - -#include "common-hal/microcontroller/Pin.h" -#include "common-hal/i2cperipheral/I2CPeripheral.h" - -typedef struct { - mp_obj_base_t base; - i2cperipheral_i2c_peripheral_obj_t *peripheral; - uint16_t address; - bool is_read; - bool is_restart; -} i2cperipheral_i2c_peripheral_request_obj_t; - -extern const mp_obj_type_t i2cperipheral_i2c_peripheral_request_type; - -extern const mp_obj_type_t i2cperipheral_i2c_peripheral_type; - -extern void common_hal_i2cperipheral_i2c_peripheral_construct(i2cperipheral_i2c_peripheral_obj_t *self, - const mcu_pin_obj_t* scl, const mcu_pin_obj_t* sda, - uint8_t *addresses, unsigned int num_addresses, bool smbus); -extern void common_hal_i2cperipheral_i2c_peripheral_deinit(i2cperipheral_i2c_peripheral_obj_t *self); -extern bool common_hal_i2cperipheral_i2c_peripheral_deinited(i2cperipheral_i2c_peripheral_obj_t *self); - -extern int common_hal_i2cperipheral_i2c_peripheral_is_addressed(i2cperipheral_i2c_peripheral_obj_t *self, - uint8_t *address, bool *is_read, bool *is_restart); -extern int common_hal_i2cperipheral_i2c_peripheral_read_byte(i2cperipheral_i2c_peripheral_obj_t *self, uint8_t *data); -extern int common_hal_i2cperipheral_i2c_peripheral_write_byte(i2cperipheral_i2c_peripheral_obj_t *self, uint8_t data); -extern void common_hal_i2cperipheral_i2c_peripheral_ack(i2cperipheral_i2c_peripheral_obj_t *self, bool ack); -extern void common_hal_i2cperipheral_i2c_peripheral_close(i2cperipheral_i2c_peripheral_obj_t *self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_I2C_SLAVE_H diff --git a/shared-bindings/i2cperipheral/__init__ 2.c b/shared-bindings/i2cperipheral/__init__ 2.c deleted file mode 100644 index e2cb8509d..000000000 --- a/shared-bindings/i2cperipheral/__init__ 2.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018 Noralf Trønnes - * - * 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 - -#include "py/obj.h" -#include "py/runtime.h" - -#include "shared-bindings/microcontroller/Pin.h" -//#include "shared-bindings/i2cperipheral/__init__.h" -#include "shared-bindings/i2cperipheral/I2CPeripheral.h" - -#include "py/runtime.h" - -//| """Two wire serial protocol peripheral -//| -//| The `i2cperipheral` module contains classes to support an I2C peripheral. -//| -//| Example emulating a peripheral with 2 addresses (read and write):: -//| -//| import board -//| from i2cperipheral import I2CPeripheral -//| -//| regs = [0] * 16 -//| index = 0 -//| -//| with I2CPeripheral(board.SCL, board.SDA, (0x40, 0x41)) as device: -//| while True: -//| r = device.request() -//| if not r: -//| # Maybe do some housekeeping -//| continue -//| with r: # Closes the transfer if necessary by sending a NACK or feeding dummy bytes -//| if r.address == 0x40: -//| if not r.is_read: # Main write which is Selected read -//| b = r.read(1) -//| if not b or b[0] > 15: -//| break -//| index = b[0] -//| b = r.read(1) -//| if b: -//| regs[index] = b[0] -//| elif r.is_restart: # Combined transfer: This is the Main read message -//| n = r.write(bytes([regs[index]])) -//| #else: -//| # A read transfer is not supported in this example -//| # If the microcontroller tries, it will get 0xff byte(s) by the ctx manager (r.close()) -//| elif r.address == 0x41: -//| if not r.is_read: -//| b = r.read(1) -//| if b and b[0] == 0xde: -//| # do something -//| pass -//| -//| This example sets up an I2C device that can be accessed from Linux like this:: -//| -//| $ i2cget -y 1 0x40 0x01 -//| 0x00 -//| $ i2cset -y 1 0x40 0x01 0xaa -//| $ i2cget -y 1 0x40 0x01 -//| 0xaa -//| -//| .. warning:: -//| I2CPeripheral makes use of clock stretching in order to slow down -//| the host. -//| Make sure the I2C host supports this. -//| -//| Raspberry Pi in particular does not support this with its I2C hw block. -//| This can be worked around by using the ``i2c-gpio`` bit banging driver. -//| Since the RPi firmware uses the hw i2c, it's not possible to emulate a HAT eeprom.""" -//| - -STATIC const mp_rom_map_elem_t i2cperipheral_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_i2cperipheral) }, - { MP_ROM_QSTR(MP_QSTR_I2CPeripheral), MP_ROM_PTR(&i2cperipheral_i2c_peripheral_type) }, -}; - -STATIC MP_DEFINE_CONST_DICT(i2cperipheral_module_globals, i2cperipheral_module_globals_table); - -const mp_obj_module_t i2cperipheral_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&i2cperipheral_module_globals, -}; diff --git a/shared-bindings/memorymonitor/AllocationAlarm 2.c b/shared-bindings/memorymonitor/AllocationAlarm 2.c deleted file mode 100644 index 7de8c1287..000000000 --- a/shared-bindings/memorymonitor/AllocationAlarm 2.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries - * - * 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 - -#include "py/objproperty.h" -#include "py/runtime.h" -#include "py/runtime0.h" -#include "shared-bindings/memorymonitor/AllocationAlarm.h" -#include "shared-bindings/util.h" -#include "supervisor/shared/translate.h" - -//| class AllocationAlarm: -//| -//| def __init__(self, *, minimum_block_count: int = 1) -> None: -//| """Throw an exception when an allocation of ``minimum_block_count`` or more blocks -//| occurs while active. -//| -//| Track allocations:: -//| -//| import memorymonitor -//| -//| aa = memorymonitor.AllocationAlarm(minimum_block_count=2) -//| x = 2 -//| # Should not allocate any blocks. -//| with aa: -//| x = 5 -//| -//| # Should throw an exception when allocating storage for the 20 bytes. -//| with aa: -//| x = bytearray(20) -//| -//| """ -//| ... -//| -STATIC mp_obj_t memorymonitor_allocationalarm_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_minimum_block_count }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_minimum_block_count, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mp_int_t minimum_block_count = args[ARG_minimum_block_count].u_int; - if (minimum_block_count < 1) { - mp_raise_ValueError_varg(translate("%q must be >= 1"), MP_QSTR_minimum_block_count); - } - - memorymonitor_allocationalarm_obj_t *self = m_new_obj(memorymonitor_allocationalarm_obj_t); - self->base.type = &memorymonitor_allocationalarm_type; - - common_hal_memorymonitor_allocationalarm_construct(self, minimum_block_count); - - return MP_OBJ_FROM_PTR(self); -} - -//| def ignore(self, count: int) -> AllocationAlarm: -//| """Sets the number of applicable allocations to ignore before raising the exception. -//| Automatically set back to zero at context exit. -//| -//| Use it within a ``with`` block:: -//| -//| # Will not alarm because the bytearray allocation will be ignored. -//| with aa.ignore(2): -//| x = bytearray(20) -//| """ -//| ... -//| -STATIC mp_obj_t memorymonitor_allocationalarm_obj_ignore(mp_obj_t self_in, mp_obj_t count_obj) { - mp_int_t count = mp_obj_get_int(count_obj); - if (count < 0) { - mp_raise_ValueError_varg(translate("%q must be >= 0"), MP_QSTR_count); - } - common_hal_memorymonitor_allocationalarm_set_ignore(self_in, count); - return self_in; -} -MP_DEFINE_CONST_FUN_OBJ_2(memorymonitor_allocationalarm_ignore_obj, memorymonitor_allocationalarm_obj_ignore); - -//| def __enter__(self) -> AllocationAlarm: -//| """Enables the alarm.""" -//| ... -//| -STATIC mp_obj_t memorymonitor_allocationalarm_obj___enter__(mp_obj_t self_in) { - common_hal_memorymonitor_allocationalarm_resume(self_in); - return self_in; -} -MP_DEFINE_CONST_FUN_OBJ_1(memorymonitor_allocationalarm___enter___obj, memorymonitor_allocationalarm_obj___enter__); - -//| def __exit__(self) -> None: -//| """Automatically disables the allocation alarm when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info.""" -//| ... -//| -STATIC mp_obj_t memorymonitor_allocationalarm_obj___exit__(size_t n_args, const mp_obj_t *args) { - (void)n_args; - common_hal_memorymonitor_allocationalarm_set_ignore(args[0], 0); - common_hal_memorymonitor_allocationalarm_pause(args[0]); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(memorymonitor_allocationalarm___exit___obj, 4, 4, memorymonitor_allocationalarm_obj___exit__); - -STATIC const mp_rom_map_elem_t memorymonitor_allocationalarm_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR_ignore), MP_ROM_PTR(&memorymonitor_allocationalarm_ignore_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&memorymonitor_allocationalarm___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&memorymonitor_allocationalarm___exit___obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(memorymonitor_allocationalarm_locals_dict, memorymonitor_allocationalarm_locals_dict_table); - -const mp_obj_type_t memorymonitor_allocationalarm_type = { - { &mp_type_type }, - .name = MP_QSTR_AllocationAlarm, - .make_new = memorymonitor_allocationalarm_make_new, - .locals_dict = (mp_obj_dict_t*)&memorymonitor_allocationalarm_locals_dict, -}; diff --git a/shared-bindings/memorymonitor/AllocationAlarm 2.h b/shared-bindings/memorymonitor/AllocationAlarm 2.h deleted file mode 100644 index 304b9c5a7..000000000 --- a/shared-bindings/memorymonitor/AllocationAlarm 2.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries - * - * 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_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONALARM_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONALARM_H - -#include "shared-module/memorymonitor/AllocationAlarm.h" - -extern const mp_obj_type_t memorymonitor_allocationalarm_type; - -void common_hal_memorymonitor_allocationalarm_construct(memorymonitor_allocationalarm_obj_t* self, size_t minimum_block_count); -void common_hal_memorymonitor_allocationalarm_pause(memorymonitor_allocationalarm_obj_t* self); -void common_hal_memorymonitor_allocationalarm_resume(memorymonitor_allocationalarm_obj_t* self); -void common_hal_memorymonitor_allocationalarm_set_ignore(memorymonitor_allocationalarm_obj_t* self, mp_int_t count); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONALARM_H diff --git a/shared-bindings/memorymonitor/AllocationSize 2.c b/shared-bindings/memorymonitor/AllocationSize 2.c deleted file mode 100644 index b35bae360..000000000 --- a/shared-bindings/memorymonitor/AllocationSize 2.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries - * - * 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 - -#include "py/objproperty.h" -#include "py/runtime.h" -#include "py/runtime0.h" -#include "shared-bindings/memorymonitor/AllocationSize.h" -#include "shared-bindings/util.h" -#include "supervisor/shared/translate.h" - -//| class AllocationSize: -//| -//| def __init__(self) -> None: -//| """Tracks the number of allocations in power of two buckets. -//| -//| It will have 16 16-bit buckets to track allocation counts. It is total allocations -//| meaning frees are ignored. Reallocated memory is counted twice, at allocation and when -//| reallocated with the larger size. -//| -//| The buckets are measured in terms of blocks which is the finest granularity of the heap. -//| This means bucket 0 will count all allocations less than or equal to the number of bytes -//| per block, typically 16. Bucket 2 will be less than or equal to 4 blocks. See -//| `bytes_per_block` to convert blocks to bytes. -//| -//| Multiple AllocationSizes can be used to track different code boundaries. -//| -//| Track allocations:: -//| -//| import memorymonitor -//| -//| mm = memorymonitor.AllocationSize() -//| with mm: -//| print("hello world" * 3) -//| -//| for bucket, count in enumerate(mm): -//| print("<", 2 ** bucket, count) -//| -//| """ -//| ... -//| -STATIC mp_obj_t memorymonitor_allocationsize_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - memorymonitor_allocationsize_obj_t *self = m_new_obj(memorymonitor_allocationsize_obj_t); - self->base.type = &memorymonitor_allocationsize_type; - - common_hal_memorymonitor_allocationsize_construct(self); - - return MP_OBJ_FROM_PTR(self); -} - -//| def __enter__(self) -> AllocationSize: -//| """Clears counts and resumes tracking.""" -//| ... -//| -STATIC mp_obj_t memorymonitor_allocationsize_obj___enter__(mp_obj_t self_in) { - common_hal_memorymonitor_allocationsize_clear(self_in); - common_hal_memorymonitor_allocationsize_resume(self_in); - return self_in; -} -MP_DEFINE_CONST_FUN_OBJ_1(memorymonitor_allocationsize___enter___obj, memorymonitor_allocationsize_obj___enter__); - -//| def __exit__(self) -> None: -//| """Automatically pauses allocation tracking when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info.""" -//| ... -//| -STATIC mp_obj_t memorymonitor_allocationsize_obj___exit__(size_t n_args, const mp_obj_t *args) { - (void)n_args; - common_hal_memorymonitor_allocationsize_pause(args[0]); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(memorymonitor_allocationsize___exit___obj, 4, 4, memorymonitor_allocationsize_obj___exit__); - -//| bytes_per_block: int -//| """Number of bytes per block""" -//| -STATIC mp_obj_t memorymonitor_allocationsize_obj_get_bytes_per_block(mp_obj_t self_in) { - memorymonitor_allocationsize_obj_t *self = MP_OBJ_TO_PTR(self_in); - - return MP_OBJ_NEW_SMALL_INT(common_hal_memorymonitor_allocationsize_get_bytes_per_block(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(memorymonitor_allocationsize_get_bytes_per_block_obj, memorymonitor_allocationsize_obj_get_bytes_per_block); - -const mp_obj_property_t memorymonitor_allocationsize_bytes_per_block_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&memorymonitor_allocationsize_get_bytes_per_block_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| def __len__(self) -> int: -//| """Returns the number of allocation buckets. -//| -//| This allows you to:: -//| -//| mm = memorymonitor.AllocationSize() -//| print(len(mm))""" -//| ... -//| -STATIC mp_obj_t memorymonitor_allocationsize_unary_op(mp_unary_op_t op, mp_obj_t self_in) { - memorymonitor_allocationsize_obj_t *self = MP_OBJ_TO_PTR(self_in); - uint16_t len = common_hal_memorymonitor_allocationsize_get_len(self); - switch (op) { - case MP_UNARY_OP_BOOL: return mp_obj_new_bool(len != 0); - case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(len); - default: return MP_OBJ_NULL; // op not supported - } -} - -//| def __getitem__(self, index: int) -> Optional[int]: -//| """Returns the allocation count for the given bucket. -//| -//| This allows you to:: -//| -//| mm = memorymonitor.AllocationSize() -//| print(mm[0])""" -//| ... -//| -STATIC mp_obj_t memorymonitor_allocationsize_subscr(mp_obj_t self_in, mp_obj_t index_obj, mp_obj_t value) { - if (value == mp_const_none) { - // delete item - mp_raise_AttributeError(translate("Cannot delete values")); - } else { - memorymonitor_allocationsize_obj_t *self = MP_OBJ_TO_PTR(self_in); - - if (MP_OBJ_IS_TYPE(index_obj, &mp_type_slice)) { - mp_raise_NotImplementedError(translate("Slices not supported")); - } else { - size_t index = mp_get_index(&memorymonitor_allocationsize_type, common_hal_memorymonitor_allocationsize_get_len(self), index_obj, false); - if (value == MP_OBJ_SENTINEL) { - // load - return MP_OBJ_NEW_SMALL_INT(common_hal_memorymonitor_allocationsize_get_item(self, index)); - } else { - mp_raise_AttributeError(translate("Read-only")); - } - } - } - return mp_const_none; -} - -STATIC const mp_rom_map_elem_t memorymonitor_allocationsize_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&memorymonitor_allocationsize___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&memorymonitor_allocationsize___exit___obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_bytes_per_block), MP_ROM_PTR(&memorymonitor_allocationsize_bytes_per_block_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(memorymonitor_allocationsize_locals_dict, memorymonitor_allocationsize_locals_dict_table); - -const mp_obj_type_t memorymonitor_allocationsize_type = { - { &mp_type_type }, - .name = MP_QSTR_AllocationSize, - .make_new = memorymonitor_allocationsize_make_new, - .subscr = memorymonitor_allocationsize_subscr, - .unary_op = memorymonitor_allocationsize_unary_op, - .getiter = mp_obj_new_generic_iterator, - .locals_dict = (mp_obj_dict_t*)&memorymonitor_allocationsize_locals_dict, -}; diff --git a/shared-bindings/memorymonitor/AllocationSize 2.h b/shared-bindings/memorymonitor/AllocationSize 2.h deleted file mode 100644 index bcd9514bf..000000000 --- a/shared-bindings/memorymonitor/AllocationSize 2.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries - * - * 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_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONSIZE_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONSIZE_H - -#include "shared-module/memorymonitor/AllocationSize.h" - -extern const mp_obj_type_t memorymonitor_allocationsize_type; - -extern void common_hal_memorymonitor_allocationsize_construct(memorymonitor_allocationsize_obj_t* self); -extern void common_hal_memorymonitor_allocationsize_pause(memorymonitor_allocationsize_obj_t* self); -extern void common_hal_memorymonitor_allocationsize_resume(memorymonitor_allocationsize_obj_t* self); -extern void common_hal_memorymonitor_allocationsize_clear(memorymonitor_allocationsize_obj_t* self); -extern size_t common_hal_memorymonitor_allocationsize_get_bytes_per_block(memorymonitor_allocationsize_obj_t* self); -extern uint16_t common_hal_memorymonitor_allocationsize_get_len(memorymonitor_allocationsize_obj_t* self); -extern uint16_t common_hal_memorymonitor_allocationsize_get_item(memorymonitor_allocationsize_obj_t* self, int16_t index); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR_ALLOCATIONSIZE_H diff --git a/shared-bindings/memorymonitor/__init__ 2.c b/shared-bindings/memorymonitor/__init__ 2.c deleted file mode 100644 index c101ba5e0..000000000 --- a/shared-bindings/memorymonitor/__init__ 2.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Scott Shawcroft - * - * 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 - -#include "py/obj.h" -#include "py/runtime.h" - -#include "shared-bindings/memorymonitor/__init__.h" -#include "shared-bindings/memorymonitor/AllocationAlarm.h" -#include "shared-bindings/memorymonitor/AllocationSize.h" - -//| """Memory monitoring helpers""" -//| - -//| class AllocationError(Exception): -//| """Catchall exception for allocation related errors.""" -//| ... -MP_DEFINE_MEMORYMONITOR_EXCEPTION(AllocationError, Exception) - -NORETURN void mp_raise_memorymonitor_AllocationError(const compressed_string_t* fmt, ...) { - va_list argptr; - va_start(argptr,fmt); - mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_memorymonitor_AllocationError, fmt, argptr); - va_end(argptr); - nlr_raise(exception); -} - -STATIC const mp_rom_map_elem_t memorymonitor_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_memorymonitor) }, - { MP_ROM_QSTR(MP_QSTR_AllocationAlarm), MP_ROM_PTR(&memorymonitor_allocationalarm_type) }, - { MP_ROM_QSTR(MP_QSTR_AllocationSize), MP_ROM_PTR(&memorymonitor_allocationsize_type) }, - - // Errors - { MP_ROM_QSTR(MP_QSTR_AllocationError), MP_ROM_PTR(&mp_type_memorymonitor_AllocationError) }, -}; - -STATIC MP_DEFINE_CONST_DICT(memorymonitor_module_globals, memorymonitor_module_globals_table); - -void memorymonitor_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { - mp_print_kind_t k = kind & ~PRINT_EXC_SUBCLASS; - bool is_subclass = kind & PRINT_EXC_SUBCLASS; - if (!is_subclass && (k == PRINT_EXC)) { - mp_print_str(print, qstr_str(MP_OBJ_QSTR_VALUE(memorymonitor_module_globals_table[0].value))); - mp_print_str(print, "."); - } - mp_obj_exception_print(print, o_in, kind); -} - -const mp_obj_module_t memorymonitor_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&memorymonitor_module_globals, -}; diff --git a/shared-bindings/memorymonitor/__init__ 2.h b/shared-bindings/memorymonitor/__init__ 2.h deleted file mode 100644 index 60fcdc3f6..000000000 --- a/shared-bindings/memorymonitor/__init__ 2.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 Scott Shawcroft - * - * 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_SHARED_BINDINGS_MEMORYMONITOR___INIT___H -#define MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR___INIT___H - -#include "py/obj.h" - - -void memorymonitor_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); - -#define MP_DEFINE_MEMORYMONITOR_EXCEPTION(exc_name, base_name) \ -const mp_obj_type_t mp_type_memorymonitor_ ## exc_name = { \ - { &mp_type_type }, \ - .name = MP_QSTR_ ## exc_name, \ - .print = memorymonitor_exception_print, \ - .make_new = mp_obj_exception_make_new, \ - .attr = mp_obj_exception_attr, \ - .parent = &mp_type_ ## base_name, \ -}; - -extern const mp_obj_type_t mp_type_memorymonitor_AllocationError; - -NORETURN void mp_raise_memorymonitor_AllocationError(const compressed_string_t* msg, ...); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MEMORYMONITOR___INIT___H diff --git a/shared-bindings/sdcardio/SDCard 2.c b/shared-bindings/sdcardio/SDCard 2.c deleted file mode 100644 index 975f8b095..000000000 --- a/shared-bindings/sdcardio/SDCard 2.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * 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/obj.h" -#include "py/objproperty.h" -#include "py/runtime.h" -#include "py/objarray.h" - -#include "shared-bindings/sdcardio/SDCard.h" -#include "shared-module/sdcardio/SDCard.h" -#include "common-hal/busio/SPI.h" -#include "shared-bindings/busio/SPI.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "supervisor/flash.h" - -//| class SDCard: -//| """SD Card Block Interface -//| -//| Controls an SD card over SPI. This built-in module has higher read -//| performance than the library adafruit_sdcard, but it is only compatible with -//| `busio.SPI`, not `bitbangio.SPI`. Usually an SDCard object is used -//| with ``storage.VfsFat`` to allow file I/O to an SD card.""" -//| -//| def __init__(self, bus: busio.SPI, cs: microcontroller.Pin, baudrate: int = 8000000) -> None: -//| """Construct an SPI SD Card object with the given properties -//| -//| :param busio.SPI spi: The SPI bus -//| :param microcontroller.Pin cs: The chip select connected to the card -//| :param int baudrate: The SPI data rate to use after card setup -//| -//| Note that during detection and configuration, a hard-coded low baudrate is used. -//| Data transfers use the specified baurate (rounded down to one that is supported by -//| the microcontroller) -//| -//| Example usage: -//| -//| .. code-block:: python -//| -//| import os -//| -//| import board -//| import sdcardio -//| import storage -//| -//| sd = sdcardio.SDCard(board.SPI(), board.SD_CS) -//| vfs = storage.VfsFat(sd) -//| storage.mount(vfs, '/sd') -//| os.listdir('/sd')""" - -STATIC mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_spi, ARG_cs, ARG_baudrate, ARG_sdio, NUM_ARGS }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_spi, MP_ARG_OBJ, {.u_obj = mp_const_none } }, - { MP_QSTR_cs, MP_ARG_OBJ, {.u_obj = mp_const_none } }, - { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 8000000} }, - { MP_QSTR_sdio, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_int = 8000000} }, - }; - MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi].u_obj); - mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj); - - sdcardio_sdcard_obj_t *self = m_new_obj(sdcardio_sdcard_obj_t); - self->base.type = &sdcardio_SDCard_type; - - common_hal_sdcardio_sdcard_construct(self, spi, cs, args[ARG_baudrate].u_int); - - return self; -} - - -//| def count(self) -> int: -//| """Returns the total number of sectors -//| -//| Due to technical limitations, this is a function and not a property. -//| -//| :return: The number of 512-byte blocks, as a number""" -//| -mp_obj_t sdcardio_sdcard_count(mp_obj_t self_in) { - sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t*)self_in; - return mp_obj_new_int_from_ull(common_hal_sdcardio_sdcard_get_blockcount(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_count_obj, sdcardio_sdcard_count); - -//| def deinit(self) -> None: -//| """Disable permanently. -//| -//| :return: None""" -//| -mp_obj_t sdcardio_sdcard_deinit(mp_obj_t self_in) { - sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t*)self_in; - common_hal_sdcardio_sdcard_deinit(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_deinit_obj, sdcardio_sdcard_deinit); - - -//| def readblocks(self, start_block: int, buf: WriteableBuffer) -> None: -//| -//| """Read one or more blocks from the card -//| -//| :param int start_block: The block to start reading from -//| :param ~_typing.WriteableBuffer buf: The buffer to write into. Length must be multiple of 512. -//| -//| :return: None""" -//| - -mp_obj_t sdcardio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { - uint32_t start_block = mp_obj_get_int(start_block_in); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); - sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t*)self_in; - int result = common_hal_sdcardio_sdcard_readblocks(self, start_block, &bufinfo); - if (result < 0) { - mp_raise_OSError(-result); - } - return mp_const_none; -} - -MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_readblocks_obj, sdcardio_sdcard_readblocks); - -//| def writeblocks(self, start_block: int, buf: ReadableBuffer) -> None: -//| -//| """Write one or more blocks to the card -//| -//| :param int start_block: The block to start writing from -//| :param ~_typing.ReadableBuffer buf: The buffer to read from. Length must be multiple of 512. -//| -//| :return: None""" -//| - -mp_obj_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { - uint32_t start_block = mp_obj_get_int(start_block_in); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); - sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t*)self_in; - int result = common_hal_sdcardio_sdcard_writeblocks(self, start_block, &bufinfo); - if (result < 0) { - mp_raise_OSError(-result); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_writeblocks_obj, sdcardio_sdcard_writeblocks); - -STATIC const mp_rom_map_elem_t sdcardio_sdcard_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&sdcardio_sdcard_count_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sdcardio_sdcard_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&sdcardio_sdcard_readblocks_obj) }, - { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&sdcardio_sdcard_writeblocks_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(sdcardio_sdcard_locals_dict, sdcardio_sdcard_locals_dict_table); - -const mp_obj_type_t sdcardio_SDCard_type = { - { &mp_type_type }, - .name = MP_QSTR_SDCard, - .make_new = sdcardio_sdcard_make_new, - .locals_dict = (mp_obj_dict_t*)&sdcardio_sdcard_locals_dict, -}; diff --git a/shared-bindings/sdcardio/SDCard 2.h b/shared-bindings/sdcardio/SDCard 2.h deleted file mode 100644 index 5986d5b81..000000000 --- a/shared-bindings/sdcardio/SDCard 2.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2017, 2018 Scott Shawcroft for Adafruit Industries - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * 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. - */ - -#pragma once - -extern const mp_obj_type_t sdcardio_SDCard_type; diff --git a/shared-bindings/sdcardio/__init__ 2.c b/shared-bindings/sdcardio/__init__ 2.c deleted file mode 100644 index 746aa5588..000000000 --- a/shared-bindings/sdcardio/__init__ 2.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * 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 - -#include "py/obj.h" -#include "py/runtime.h" - -#include "shared-bindings/sdcardio/SDCard.h" - -//| """Interface to an SD card via the SPI bus""" - -STATIC const mp_rom_map_elem_t sdcardio_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdcardio) }, - { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&sdcardio_SDCard_type) }, -}; - -STATIC MP_DEFINE_CONST_DICT(sdcardio_module_globals, sdcardio_module_globals_table); - -const mp_obj_module_t sdcardio_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&sdcardio_module_globals, -}; diff --git a/shared-bindings/sdcardio/__init__ 2.h b/shared-bindings/sdcardio/__init__ 2.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/shared-module/sdcardio/SDCard 2.c b/shared-module/sdcardio/SDCard 2.c deleted file mode 100644 index 9e861279d..000000000 --- a/shared-module/sdcardio/SDCard 2.c +++ /dev/null @@ -1,466 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * 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. - */ - -// This implementation largely follows the structure of adafruit_sdcard.py - -#include "shared-bindings/busio/SPI.h" -#include "shared-bindings/digitalio/DigitalInOut.h" -#include "shared-bindings/time/__init__.h" -#include "shared-bindings/util.h" -#include "shared-module/sdcardio/SDCard.h" - -#include "py/mperrno.h" - -#if 0 -#define DEBUG_PRINT(...) ((void)mp_printf(&mp_plat_print, ## __VA_ARGS__)) -#else -#define DEBUG_PRINT(...) ((void)0) -#endif - -#define CMD_TIMEOUT (200) - -#define R1_IDLE_STATE (1<<0) -#define R1_ILLEGAL_COMMAND (1<<2) - -#define TOKEN_CMD25 (0xFC) -#define TOKEN_STOP_TRAN (0xFD) -#define TOKEN_DATA (0xFE) - -STATIC bool lock_and_configure_bus(sdcardio_sdcard_obj_t *self) { - if (!common_hal_busio_spi_try_lock(self->bus)) { - return false; - } - common_hal_busio_spi_configure(self->bus, self->baudrate, 0, 0, 8); - common_hal_digitalio_digitalinout_set_value(&self->cs, false); - return true; -} - -STATIC void lock_bus_or_throw(sdcardio_sdcard_obj_t *self) { - if (!lock_and_configure_bus(self)) { - mp_raise_OSError(EAGAIN); - } -} - -STATIC void clock_card(sdcardio_sdcard_obj_t *self, int bytes) { - uint8_t buf[] = {0xff}; - common_hal_digitalio_digitalinout_set_value(&self->cs, true); - for (int i=0; ibus, buf, 1); - } -} - -STATIC void extraclock_and_unlock_bus(sdcardio_sdcard_obj_t *self) { - clock_card(self, 1); - common_hal_busio_spi_unlock(self->bus); -} - -static uint8_t CRC7(const uint8_t* data, uint8_t n) { - uint8_t crc = 0; - for (uint8_t i = 0; i < n; i++) { - uint8_t d = data[i]; - for (uint8_t j = 0; j < 8; j++) { - crc <<= 1; - if ((d & 0x80) ^ (crc & 0x80)) { - crc ^= 0x09; - } - d <<= 1; - } - } - return (crc << 1) | 1; -} - -#define READY_TIMEOUT_NS (300 * 1000 * 1000) // 300ms -STATIC void wait_for_ready(sdcardio_sdcard_obj_t *self) { - uint64_t deadline = common_hal_time_monotonic_ns() + READY_TIMEOUT_NS; - while (common_hal_time_monotonic_ns() < deadline) { - uint8_t b; - common_hal_busio_spi_read(self->bus, &b, 1, 0xff); - if (b == 0xff) { - break; - } - } -} - -// In Python API, defaults are response=None, data_block=True, wait=True -STATIC int cmd(sdcardio_sdcard_obj_t *self, int cmd, int arg, void *response_buf, size_t response_len, bool data_block, bool wait) { - DEBUG_PRINT("cmd % 3d [%02x] arg=% 11d [%08x] len=%d%s%s\n", cmd, cmd, arg, arg, response_len, data_block ? " data" : "", wait ? " wait" : ""); - uint8_t cmdbuf[6]; - cmdbuf[0] = cmd | 0x40; - cmdbuf[1] = (arg >> 24) & 0xff; - cmdbuf[2] = (arg >> 16) & 0xff; - cmdbuf[3] = (arg >> 8) & 0xff; - cmdbuf[4] = arg & 0xff; - cmdbuf[5] = CRC7(cmdbuf, 5); - - if (wait) { - wait_for_ready(self); - } - - common_hal_busio_spi_write(self->bus, cmdbuf, sizeof(cmdbuf)); - - // Wait for the response (response[7] == 0) - bool response_received = false; - for (int i=0; ibus, cmdbuf, 1, 0xff); - if ((cmdbuf[0] & 0x80) == 0) { - response_received = true; - break; - } - } - - if (!response_received) { - return -EIO; - } - - if (response_buf) { - - if (data_block) { - cmdbuf[1] = 0xff; - do { - // Wait for the start block byte - common_hal_busio_spi_read(self->bus, cmdbuf+1, 1, 0xff); - } while (cmdbuf[1] != 0xfe); - } - - common_hal_busio_spi_read(self->bus, response_buf, response_len, 0xff); - - if (data_block) { - // Read and discard the CRC-CCITT checksum - common_hal_busio_spi_read(self->bus, cmdbuf+1, 2, 0xff); - } - - } - - return cmdbuf[0]; -} - -STATIC int block_cmd(sdcardio_sdcard_obj_t *self, int cmd_, int block, void *response_buf, size_t response_len, bool data_block, bool wait) { - return cmd(self, cmd_, block * self->cdv, response_buf, response_len, true, true); -} - -STATIC bool cmd_nodata(sdcardio_sdcard_obj_t* self, int cmd, int response) { - uint8_t cmdbuf[2] = {cmd, 0xff}; - - common_hal_busio_spi_write(self->bus, cmdbuf, sizeof(cmdbuf)); - - // Wait for the response (response[7] == response) - for (int i=0; ibus, cmdbuf, 1, 0xff); - if (cmdbuf[0] == response) { - return 0; - } - } - return -EIO; -} - -STATIC const compressed_string_t *init_card_v1(sdcardio_sdcard_obj_t *self) { - for (int i=0; icdv = 1; - } - return NULL; - } - } - return translate("timeout waiting for v2 card"); -} - -STATIC const compressed_string_t *init_card(sdcardio_sdcard_obj_t *self) { - clock_card(self, 10); - - common_hal_digitalio_digitalinout_set_value(&self->cs, false); - - // CMD0: init card: should return _R1_IDLE_STATE (allow 5 attempts) - { - bool reached_idle_state = false; - for (int i=0; i<5; i++) { - if (cmd(self, 0, 0, NULL, 0, true, true) == R1_IDLE_STATE) { - reached_idle_state = true; - break; - } - } - if (!reached_idle_state) { - return translate("no SD card"); - } - } - - // CMD8: determine card version - { - uint8_t rb7[4]; - int response = cmd(self, 8, 0x1AA, rb7, sizeof(rb7), false, true); - if (response == R1_IDLE_STATE) { - const compressed_string_t *result =init_card_v2(self); - if (result != NULL) { - return result; - } - } else if (response == (R1_IDLE_STATE | R1_ILLEGAL_COMMAND)) { - const compressed_string_t *result =init_card_v1(self); - if (result != NULL) { - return result; - } - } else { - return translate("couldn't determine SD card version"); - } - } - - // CMD9: get number of sectors - { - uint8_t csd[16]; - int response = cmd(self, 9, 0, csd, sizeof(csd), true, true); - if (response != 0) { - return translate("no response from SD card"); - } - int csd_version = (csd[0] & 0xC0) >> 6; - if (csd_version >= 2) { - return translate("SD card CSD format not supported"); - } - - if (csd_version == 1) { - self->sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024; - } else { - uint32_t block_length = 1 << (csd[5] & 0xF); - uint32_t c_size = ((csd[6] & 0x3) << 10) | (csd[7] << 2) | ((csd[8] & 0xC) >> 6); - uint32_t mult = 1 << (((csd[9] & 0x3) << 1 | (csd[10] & 0x80) >> 7) + 2); - self->sectors = block_length / 512 * mult * (c_size + 1); - } - } - - // CMD16: set block length to 512 bytes - { - int response = cmd(self, 16, 512, NULL, 0, true, true); - if (response != 0) { - return translate("can't set 512 block size"); - } - } - - return NULL; -} - -void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, mcu_pin_obj_t *cs, int baudrate) { - self->bus = bus; - common_hal_digitalio_digitalinout_construct(&self->cs, cs); - common_hal_digitalio_digitalinout_switch_to_output(&self->cs, true, DRIVE_MODE_PUSH_PULL); - - self->cdv = 512; - self->sectors = 0; - self->baudrate = 250000; - - lock_bus_or_throw(self); - const compressed_string_t *result = init_card(self); - extraclock_and_unlock_bus(self); - - if (result != NULL) { - common_hal_digitalio_digitalinout_deinit(&self->cs); - mp_raise_OSError_msg(result); - } - - self->baudrate = baudrate; -} - -void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self) { - if (!self->bus) { - return; - } - self->bus = 0; - common_hal_digitalio_digitalinout_deinit(&self->cs); -} - -void common_hal_sdcardio_check_for_deinit(sdcardio_sdcard_obj_t *self) { - if (!self->bus) { - raise_deinited_error(); - } -} - -int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self) { - common_hal_sdcardio_check_for_deinit(self); - return self->sectors; -} - -int readinto(sdcardio_sdcard_obj_t *self, void *buf, size_t size) { - uint8_t aux[2] = {0, 0}; - while (aux[0] != 0xfe) { - common_hal_busio_spi_read(self->bus, aux, 1, 0xff); - } - - common_hal_busio_spi_read(self->bus, buf, size, 0xff); - - // Read checksum and throw it away - common_hal_busio_spi_read(self->bus, aux, sizeof(aux), 0xff); - return 0; -} - -int readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { - uint32_t nblocks = buf->len / 512; - if (nblocks == 1) { - // Use CMD17 to read a single block - return block_cmd(self, 17, start_block, buf->buf, buf->len, true, true); - } else { - // Use CMD18 to read multiple blocks - int r = block_cmd(self, 18, start_block, NULL, 0, true, true); - if (r < 0) { - return r; - } - - uint8_t *ptr = buf->buf; - while (nblocks--) { - r = readinto(self, ptr, 512); - if (r < 0) { - return r; - } - ptr += 512; - } - - // End the multi-block read - r = cmd(self, 12, 0, NULL, 0, true, false); - - // Return first status 0 or last before card ready (0xff) - while (r != 0) { - uint8_t single_byte; - common_hal_busio_spi_read(self->bus, &single_byte, 1, 0xff); - if (single_byte & 0x80) { - return r; - } - r = single_byte; - } - } - return 0; -} - -int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { - common_hal_sdcardio_check_for_deinit(self); - if (buf->len % 512 != 0) { - mp_raise_ValueError(translate("Buffer length must be a multiple of 512")); - } - - lock_and_configure_bus(self); - int r = readblocks(self, start_block, buf); - extraclock_and_unlock_bus(self); - return r; -} - -int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t size) { - wait_for_ready(self); - - uint8_t cmd[2]; - cmd[0] = token; - - common_hal_busio_spi_write(self->bus, cmd, 1); - common_hal_busio_spi_write(self->bus, buf, size); - - cmd[0] = cmd[1] = 0xff; - common_hal_busio_spi_write(self->bus, cmd, 2); - - // Check the response - // This differs from the traditional adafruit_sdcard handling, - // but adafruit_sdcard also ignored the return value of SDCard._write(!) - // so nobody noticed - // - // - // Response is as follows: - // x x x 0 STAT 1 - // 7 6 5 4 3..1 0 - // with STATUS 010 indicating "data accepted", and other status bit - // combinations indicating failure. - // In practice, I was seeing cmd[0] as 0xe5, indicating success - for (int i=0; ibus, cmd, 1, 0xff); - DEBUG_PRINT("i=%02d cmd[0] = 0x%02x\n", i, cmd[0]); - if ((cmd[0] & 0b00010001) == 0b00000001) { - if ((cmd[0] & 0x1f) != 0x5) { - return -EIO; - } else { - break; - } - } - } - - // Wait for the write to finish - do { - common_hal_busio_spi_read(self->bus, cmd, 1, 0xff); - } while (cmd[0] == 0); - - // Success - return 0; -} - -int writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { - common_hal_sdcardio_check_for_deinit(self); - uint32_t nblocks = buf->len / 512; - if (nblocks == 1) { - // Use CMD24 to write a single block - int r = block_cmd(self, 24, start_block, NULL, 0, true, true); - if (r < 0) { - return r; - } - r = _write(self, TOKEN_DATA, buf->buf, buf->len); - if (r < 0) { - return r; - } - } else { - // Use CMD25 to write multiple block - int r = block_cmd(self, 25, start_block, NULL, 0, true, true); - if (r < 0) { - return r; - } - - uint8_t *ptr = buf->buf; - while (nblocks--) { - r = _write(self, TOKEN_CMD25, ptr, 512); - if (r < 0) { - return r; - } - ptr += 512; - } - - cmd_nodata(self, TOKEN_STOP_TRAN, 0); - } - return 0; -} - -int common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { - common_hal_sdcardio_check_for_deinit(self); - if (buf->len % 512 != 0) { - mp_raise_ValueError(translate("Buffer length must be a multiple of 512")); - } - lock_and_configure_bus(self); - int r = writeblocks(self, start_block, buf); - extraclock_and_unlock_bus(self); - return r; -} diff --git a/shared-module/sdcardio/SDCard 2.h b/shared-module/sdcardio/SDCard 2.h deleted file mode 100644 index 76c906029..000000000 --- a/shared-module/sdcardio/SDCard 2.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * 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. - */ - -#pragma once - -#include "py/obj.h" -#include "py/objproperty.h" -#include "py/runtime.h" -#include "py/objarray.h" - -#include "common-hal/busio/SPI.h" -#include "common-hal/digitalio/DigitalInOut.h" - -typedef struct { - mp_obj_base_t base; - busio_spi_obj_t *bus; - digitalio_digitalinout_obj_t cs; - int cdv; - int baudrate; - uint32_t sectors; -} sdcardio_sdcard_obj_t; - -void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *spi, mcu_pin_obj_t *cs, int baudrate); -void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self); -void common_hal_sdcardio_sdcard_check_for_deinit(sdcardio_sdcard_obj_t *self); -int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self); -int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); -int common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); diff --git a/shared-module/sdcardio/__init__ 2.c b/shared-module/sdcardio/__init__ 2.c deleted file mode 100644 index e69de29bb..000000000 diff --git a/shared-module/sdcardio/__init__ 2.h b/shared-module/sdcardio/__init__ 2.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/supervisor/background_callback 2.h b/supervisor/background_callback 2.h deleted file mode 100644 index 535dd656b..000000000 --- a/supervisor/background_callback 2.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * 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 CIRCUITPY_INCLUDED_SUPERVISOR_BACKGROUND_CALLBACK_H -#define CIRCUITPY_INCLUDED_SUPERVISOR_BACKGROUND_CALLBACK_H - -/** Background callbacks are a linked list of tasks to call in the background. - * - * Include a member of type `background_callback_t` inside an object - * which needs to queue up background work, and zero-initialize it. - * - * To schedule the work, use background_callback_add, with fun as the - * function to call and data pointing to the object itself. - * - * Next time run_background_tasks_if_tick is called, the callback will - * be run and removed from the linked list. - * - * Queueing a task that is already queued does nothing. Unconditionally - * re-queueing it from its own background task will cause it to run during the - * very next background-tasks invocation, leading to a CircuitPython freeze, so - * don't do that. - * - * background_callback_add can be called from interrupt context. - */ -typedef void (*background_callback_fun)(void *data); -typedef struct background_callback { - background_callback_fun fun; - void *data; - struct background_callback *next; - struct background_callback *prev; -} background_callback_t; - -/* Add a background callback for which 'fun' and 'data' were previously set */ -void background_callback_add_core(background_callback_t *cb); - -/* Add a background callback to the given function with the given data. When - * the callback involves an object on the GC heap, the 'data' must be a pointer - * to that object itself, not an internal pointer. Otherwise, it can be the - * case that no other references to the object itself survive, and the object - * becomes garbage collected while an outstanding background callback still - * exists. - */ -void background_callback_add(background_callback_t *cb, background_callback_fun fun, void *data); - -/* Run all background callbacks. Normally, this is done by the supervisor - * whenever the list is non-empty */ -void background_callback_run_all(void); - -/* During soft reset, remove all pending callbacks and clear the critical section flag */ -void background_callback_reset(void); - -/* Sometimes background callbacks must be blocked. Use these functions to - * bracket the section of code where this is the case. These calls nest, and - * begins must be balanced with ends. - */ -void background_callback_begin_critical_section(void); -void background_callback_end_critical_section(void); - -/* - * Background callbacks may stop objects from being collected - */ -void background_callback_gc_collect(void); - -#endif diff --git a/supervisor/shared/background_callback 2.c b/supervisor/shared/background_callback 2.c deleted file mode 100644 index 8e12dd362..000000000 --- a/supervisor/shared/background_callback 2.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * 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 - -#include "py/gc.h" -#include "py/mpconfig.h" -#include "supervisor/background_callback.h" -#include "supervisor/shared/tick.h" -#include "shared-bindings/microcontroller/__init__.h" - -STATIC volatile background_callback_t *callback_head, *callback_tail; - -#define CALLBACK_CRITICAL_BEGIN (common_hal_mcu_disable_interrupts()) -#define CALLBACK_CRITICAL_END (common_hal_mcu_enable_interrupts()) - -void background_callback_add_core(background_callback_t *cb) { - CALLBACK_CRITICAL_BEGIN; - if (cb->prev || callback_head == cb) { - CALLBACK_CRITICAL_END; - return; - } - cb->next = 0; - cb->prev = (background_callback_t*)callback_tail; - if (callback_tail) { - callback_tail->next = cb; - cb->prev = (background_callback_t*)callback_tail; - } - if (!callback_head) { - callback_head = cb; - } - callback_tail = cb; - CALLBACK_CRITICAL_END; -} - -void background_callback_add(background_callback_t *cb, background_callback_fun fun, void *data) { - cb->fun = fun; - cb->data = data; - background_callback_add_core(cb); -} - -static bool in_background_callback; -void background_callback_run_all() { - if (!callback_head) { - return; - } - CALLBACK_CRITICAL_BEGIN; - if (in_background_callback) { - CALLBACK_CRITICAL_END; - return; - } - in_background_callback = true; - background_callback_t *cb = (background_callback_t*)callback_head; - callback_head = NULL; - callback_tail = NULL; - while (cb) { - background_callback_t *next = cb->next; - cb->next = cb->prev = NULL; - background_callback_fun fun = cb->fun; - void *data = cb->data; - CALLBACK_CRITICAL_END; - // Leave the critical section in order to run the callback function - if (fun) { - fun(data); - } - CALLBACK_CRITICAL_BEGIN; - cb = next; - } - in_background_callback = false; - CALLBACK_CRITICAL_END; -} - -void background_callback_begin_critical_section() { - CALLBACK_CRITICAL_BEGIN; -} - -void background_callback_end_critical_section() { - CALLBACK_CRITICAL_END; -} - -void background_callback_reset() { - CALLBACK_CRITICAL_BEGIN; - background_callback_t *cb = (background_callback_t*)callback_head; - while(cb) { - background_callback_t *next = cb->next; - memset(cb, 0, sizeof(*cb)); - cb = next; - } - callback_head = NULL; - callback_tail = NULL; - in_background_callback = false; - CALLBACK_CRITICAL_END; -} - -void background_callback_gc_collect(void) { - // We don't enter the callback critical section here. We rely on - // gc_collect_ptr _NOT_ entering background callbacks, so it is not - // possible for the list to be cleared. - // - // However, it is possible for the list to be extended. We make the - // minor assumption that no newly added callback is for a - // collectable object. That is, we only plug the hole where an - // object becomes collectable AFTER it is added but before the - // callback is run, not the hole where an object was ALREADY - // collectable but adds a background task for itself. - // - // It's necessary to traverse the whole list here, as the callbacks - // themselves can be in non-gc memory, and some of the cb->data - // objects themselves might be in non-gc memory. - background_callback_t *cb = (background_callback_t*)callback_head; - while(cb) { - gc_collect_ptr(cb->data); - cb = cb->next; - } -} -- cgit v1.2.3 From 983e1af33d0440329aa4f34109994f8597f0737a Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Fri, 21 Aug 2020 19:10:13 -0500 Subject: remove other extraneous files --- shared-bindings/sdioio/SDCard 2.c | 296 ------------------------ shared-bindings/sdioio/SDCard 2.h | 66 ------ shared-bindings/sdioio/__init__ 2.c | 47 ---- shared-bindings/sdioio/__init__ 2.h | 0 shared-module/memorymonitor/AllocationAlarm 2.c | 94 -------- shared-module/memorymonitor/AllocationAlarm 2.h | 51 ---- shared-module/memorymonitor/AllocationSize 2.c | 91 -------- shared-module/memorymonitor/AllocationSize 2.h | 51 ---- shared-module/memorymonitor/__init__ 2.c | 39 ---- shared-module/memorymonitor/__init__ 2.h | 35 --- 10 files changed, 770 deletions(-) delete mode 100644 shared-bindings/sdioio/SDCard 2.c delete mode 100644 shared-bindings/sdioio/SDCard 2.h delete mode 100644 shared-bindings/sdioio/__init__ 2.c delete mode 100644 shared-bindings/sdioio/__init__ 2.h delete mode 100644 shared-module/memorymonitor/AllocationAlarm 2.c delete mode 100644 shared-module/memorymonitor/AllocationAlarm 2.h delete mode 100644 shared-module/memorymonitor/AllocationSize 2.c delete mode 100644 shared-module/memorymonitor/AllocationSize 2.h delete mode 100644 shared-module/memorymonitor/__init__ 2.c delete mode 100644 shared-module/memorymonitor/__init__ 2.h (limited to 'shared-module') diff --git a/shared-bindings/sdioio/SDCard 2.c b/shared-bindings/sdioio/SDCard 2.c deleted file mode 100644 index aba414cd6..000000000 --- a/shared-bindings/sdioio/SDCard 2.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 Scott Shawcroft - * - * 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. - */ - -// This file contains all of the Python API definitions for the -// sdioio.SDCard class. - -#include - -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/sdioio/SDCard.h" -#include "shared-bindings/util.h" - -#include "lib/utils/buffer_helper.h" -#include "lib/utils/context_manager_helpers.h" -#include "py/mperrno.h" -#include "py/objproperty.h" -#include "py/runtime.h" -#include "supervisor/shared/translate.h" - -//| class SDCard: -//| """SD Card Block Interface with SDIO -//| -//| Controls an SD card over SDIO. SDIO is a parallel protocol designed -//| for SD cards. It uses a clock pin, a command pin, and 1 or 4 -//| data pins. It can be operated at a high frequency such as -//| 25MHz. Usually an SDCard object is used with ``storage.VfsFat`` -//| to allow file I/O to an SD card.""" -//| -//| def __init__(self, clock: microcontroller.Pin, command: microcontroller.Pin, data: Sequence[microcontroller.Pin], frequency: int) -> None: -//| """Construct an SDIO SD Card object with the given properties -//| -//| :param ~microcontroller.Pin clock: the pin to use for the clock. -//| :param ~microcontroller.Pin command: the pin to use for the command. -//| :param data: A sequence of pins to use for data. -//| :param frequency: The frequency of the bus in Hz -//| -//| Example usage: -//| -//| .. code-block:: python -//| -//| import os -//| -//| import board -//| import sdioio -//| import storage -//| -//| sd = sdioio.SDCard( -//| clock=board.SDIO_CLOCK, -//| command=board.SDIO_COMMAND, -//| data=board.SDIO_DATA, -//| frequency=25000000) -//| vfs = storage.VfsFat(sd) -//| storage.mount(vfs, '/sd') -//| os.listdir('/sd')""" -//| ... -//| - -STATIC mp_obj_t sdioio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - sdioio_sdcard_obj_t *self = m_new_obj(sdioio_sdcard_obj_t); - self->base.type = &sdioio_SDCard_type; - enum { ARG_clock, ARG_command, ARG_data, ARG_frequency, NUM_ARGS }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ }, - { MP_QSTR_command, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ }, - { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ }, - { MP_QSTR_frequency, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_INT }, - }; - MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - - mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - const mcu_pin_obj_t* clock = validate_obj_is_free_pin(args[ARG_clock].u_obj); - const mcu_pin_obj_t* command = validate_obj_is_free_pin(args[ARG_command].u_obj); - mcu_pin_obj_t *data_pins[4]; - uint8_t num_data; - validate_list_is_free_pins(MP_QSTR_data, data_pins, MP_ARRAY_SIZE(data_pins), args[ARG_data].u_obj, &num_data); - - common_hal_sdioio_sdcard_construct(self, clock, command, num_data, data_pins, args[ARG_frequency].u_int); - return MP_OBJ_FROM_PTR(self); -} - -STATIC void check_for_deinit(sdioio_sdcard_obj_t *self) { - if (common_hal_sdioio_sdcard_deinited(self)) { - raise_deinited_error(); - } -} - -//| def configure(self, frequency: int = 0, width: int = 0) -> None: -//| """Configures the SDIO bus. -//| -//| :param int frequency: the desired clock rate in Hertz. The actual clock rate may be higher or lower due to the granularity of available clock settings. Check the `frequency` attribute for the actual clock rate. -//| :param int width: the number of data lines to use. Must be 1 or 4 and must also not exceed the number of data lines at construction -//| -//| .. note:: Leaving a value unspecified or 0 means the current setting is kept""" -//| -STATIC mp_obj_t sdioio_sdcard_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_frequency, ARG_width, NUM_ARGS }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - }; - sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - check_for_deinit(self); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_int_t frequency = args[ARG_frequency].u_int; - if (frequency < 0) { - mp_raise_ValueError_varg(translate("Invalid %q"), MP_QSTR_baudrate); - } - - uint8_t width = args[ARG_width].u_int; - if (width != 0 && width != 1 && width != 4) { - mp_raise_ValueError_varg(translate("Invalid %q"), MP_QSTR_width); - } - - if (!common_hal_sdioio_sdcard_configure(self, frequency, width)) { - mp_raise_OSError(MP_EIO); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(sdioio_sdcard_configure_obj, 1, sdioio_sdcard_configure); - -//| def count(self) -> int: -//| """Returns the total number of sectors -//| -//| Due to technical limitations, this is a function and not a property. -//| -//| :return: The number of 512-byte blocks, as a number""" -//| -STATIC mp_obj_t sdioio_sdcard_count(mp_obj_t self_in) { - sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_sdioio_sdcard_get_count(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_count_obj, sdioio_sdcard_count); - -//| def readblocks(self, start_block: int, buf: WriteableBuffer) -> None: -//| -//| """Read one or more blocks from the card -//| -//| :param int start_block: The block to start reading from -//| :param ~_typing.WriteableBuffer buf: The buffer to write into. Length must be multiple of 512. -//| -//| :return: None""" -mp_obj_t sdioio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { - uint32_t start_block = mp_obj_get_int(start_block_in); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); - sdioio_sdcard_obj_t *self = (sdioio_sdcard_obj_t*)self_in; - int result = common_hal_sdioio_sdcard_readblocks(self, start_block, &bufinfo); - if (result < 0) { - mp_raise_OSError(-result); - } - return mp_const_none; -} - -MP_DEFINE_CONST_FUN_OBJ_3(sdioio_sdcard_readblocks_obj, sdioio_sdcard_readblocks); - -//| def writeblocks(self, start_block: int, buf: ReadableBuffer) -> None: -//| -//| """Write one or more blocks to the card -//| -//| :param int start_block: The block to start writing from -//| :param ~_typing.ReadableBuffer buf: The buffer to read from. Length must be multiple of 512. -//| -//| :return: None""" -//| -mp_obj_t sdioio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { - uint32_t start_block = mp_obj_get_int(start_block_in); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); - sdioio_sdcard_obj_t *self = (sdioio_sdcard_obj_t*)self_in; - int result = common_hal_sdioio_sdcard_writeblocks(self, start_block, &bufinfo); - if (result < 0) { - mp_raise_OSError(-result); - } - return mp_const_none; -} - -MP_DEFINE_CONST_FUN_OBJ_3(sdioio_sdcard_writeblocks_obj, sdioio_sdcard_writeblocks); - -//| @property -//| def frequency(self) -> int: -//| """The actual SDIO bus frequency. This may not match the frequency -//| requested due to internal limitations.""" -//| ... -//| -STATIC mp_obj_t sdioio_sdcard_obj_get_frequency(mp_obj_t self_in) { - sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_sdioio_sdcard_get_frequency(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_get_frequency_obj, sdioio_sdcard_obj_get_frequency); - -const mp_obj_property_t sdioio_sdcard_frequency_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&sdioio_sdcard_get_frequency_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| @property -//| def width(self) -> int: -//| """The actual SDIO bus width, in bits""" -//| ... -//| -STATIC mp_obj_t sdioio_sdcard_obj_get_width(mp_obj_t self_in) { - sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_sdioio_sdcard_get_width(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_get_width_obj, sdioio_sdcard_obj_get_width); - -const mp_obj_property_t sdioio_sdcard_width_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&sdioio_sdcard_get_width_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| def deinit(self) -> None: -//| """Disable permanently. -//| -//| :return: None""" -STATIC mp_obj_t sdioio_sdcard_obj_deinit(mp_obj_t self_in) { - sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_sdioio_sdcard_deinit(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(sdioio_sdcard_deinit_obj, sdioio_sdcard_obj_deinit); - -//| def __enter__(self) -> SDCard: -//| """No-op used by Context Managers. -//| Provided by context manager helper.""" -//| ... -//| - -//| def __exit__(self) -> None: -//| """Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info.""" -//| ... -//| -STATIC mp_obj_t sdioio_sdcard_obj___exit__(size_t n_args, const mp_obj_t *args) { - (void)n_args; - common_hal_sdioio_sdcard_deinit(args[0]); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(sdioio_sdcard_obj___exit___obj, 4, 4, sdioio_sdcard_obj___exit__); - -STATIC const mp_rom_map_elem_t sdioio_sdcard_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sdioio_sdcard_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&sdioio_sdcard_obj___exit___obj) }, - - { MP_ROM_QSTR(MP_QSTR_configure), MP_ROM_PTR(&sdioio_sdcard_configure_obj) }, - { MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&sdioio_sdcard_frequency_obj) }, - { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&sdioio_sdcard_width_obj) }, - - { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&sdioio_sdcard_count_obj) }, - { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&sdioio_sdcard_readblocks_obj) }, - { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&sdioio_sdcard_writeblocks_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(sdioio_sdcard_locals_dict, sdioio_sdcard_locals_dict_table); - -const mp_obj_type_t sdioio_SDCard_type = { - { &mp_type_type }, - .name = MP_QSTR_SDCard, - .make_new = sdioio_sdcard_make_new, - .locals_dict = (mp_obj_dict_t*)&sdioio_sdcard_locals_dict, -}; diff --git a/shared-bindings/sdioio/SDCard 2.h b/shared-bindings/sdioio/SDCard 2.h deleted file mode 100644 index 7f62ee7a6..000000000 --- a/shared-bindings/sdioio/SDCard 2.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 Scott Shawcroft - * - * 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_SHARED_BINDINGS_BUSIO_SDIO_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SDIO_H - -#include "py/obj.h" - -#include "common-hal/microcontroller/Pin.h" -#include "common-hal/sdioio/SDCard.h" - -// Type object used in Python. Should be shared between ports. -extern const mp_obj_type_t sdioio_SDCard_type; - -// Construct an underlying SDIO object. -extern void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, - const mcu_pin_obj_t * clock, const mcu_pin_obj_t * command, - uint8_t num_data, mcu_pin_obj_t ** data, uint32_t frequency); - -extern void common_hal_sdioio_sdcard_deinit(sdioio_sdcard_obj_t *self); -extern bool common_hal_sdioio_sdcard_deinited(sdioio_sdcard_obj_t *self); - -extern bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t baudrate, uint8_t width); - -extern void common_hal_sdioio_sdcard_unlock(sdioio_sdcard_obj_t *self); - -// Return actual SDIO bus frequency. -uint32_t common_hal_sdioio_sdcard_get_frequency(sdioio_sdcard_obj_t* self); - -// Return SDIO bus width. -uint8_t common_hal_sdioio_sdcard_get_width(sdioio_sdcard_obj_t* self); - -// Return number of device blocks -uint32_t common_hal_sdioio_sdcard_get_count(sdioio_sdcard_obj_t* self); - -// Read or write blocks -int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t* self, uint32_t start_block, mp_buffer_info_t *bufinfo); -int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t* self, uint32_t start_block, mp_buffer_info_t *bufinfo); - -// This is used by the supervisor to claim SDIO devices indefinitely. -extern void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SDIO_H diff --git a/shared-bindings/sdioio/__init__ 2.c b/shared-bindings/sdioio/__init__ 2.c deleted file mode 100644 index b88e5c3a9..000000000 --- a/shared-bindings/sdioio/__init__ 2.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Jeff Epler for Adafruit Industries - * - * 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 - -#include "py/obj.h" -#include "py/runtime.h" - -#include "shared-bindings/sdioio/SDCard.h" - -//| """Interface to an SD card via the SDIO bus""" - -STATIC const mp_rom_map_elem_t sdioio_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdio) }, - { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&sdioio_SDCard_type) }, -}; - -STATIC MP_DEFINE_CONST_DICT(sdioio_module_globals, sdioio_module_globals_table); - -const mp_obj_module_t sdioio_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&sdioio_module_globals, -}; diff --git a/shared-bindings/sdioio/__init__ 2.h b/shared-bindings/sdioio/__init__ 2.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/shared-module/memorymonitor/AllocationAlarm 2.c b/shared-module/memorymonitor/AllocationAlarm 2.c deleted file mode 100644 index 35f4e4c63..000000000 --- a/shared-module/memorymonitor/AllocationAlarm 2.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries - * - * 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 "shared-bindings/memorymonitor/__init__.h" -#include "shared-bindings/memorymonitor/AllocationAlarm.h" - -#include "py/gc.h" -#include "py/mpstate.h" -#include "py/runtime.h" - -void common_hal_memorymonitor_allocationalarm_construct(memorymonitor_allocationalarm_obj_t* self, size_t minimum_block_count) { - self->minimum_block_count = minimum_block_count; - self->next = NULL; - self->previous = NULL; -} - -void common_hal_memorymonitor_allocationalarm_set_ignore(memorymonitor_allocationalarm_obj_t* self, mp_int_t count) { - self->count = count; -} - -void common_hal_memorymonitor_allocationalarm_pause(memorymonitor_allocationalarm_obj_t* self) { - // Check to make sure we aren't already paused. We can be if we're exiting from an exception we - // caused. - if (self->previous == NULL) { - return; - } - *self->previous = self->next; - self->next = NULL; - self->previous = NULL; -} - -void common_hal_memorymonitor_allocationalarm_resume(memorymonitor_allocationalarm_obj_t* self) { - if (self->previous != NULL) { - mp_raise_RuntimeError(translate("Already running")); - } - self->next = MP_STATE_VM(active_allocationalarms); - self->previous = (memorymonitor_allocationalarm_obj_t**) &MP_STATE_VM(active_allocationalarms); - if (self->next != NULL) { - self->next->previous = &self->next; - } - MP_STATE_VM(active_allocationalarms) = self; -} - -void memorymonitor_allocationalarms_allocation(size_t block_count) { - memorymonitor_allocationalarm_obj_t* alarm = MP_OBJ_TO_PTR(MP_STATE_VM(active_allocationalarms)); - size_t alert_count = 0; - while (alarm != NULL) { - // Hold onto next in case we remove the alarm from the list. - memorymonitor_allocationalarm_obj_t* next = alarm->next; - if (block_count >= alarm->minimum_block_count) { - if (alarm->count > 0) { - alarm->count--; - } else { - // Uncomment the breakpoint below if you want to use a C debugger to figure out the C - // call stack for an allocation. - // asm("bkpt"); - // Pause now because we may alert when throwing the exception too. - common_hal_memorymonitor_allocationalarm_pause(alarm); - alert_count++; - } - } - alarm = next; - } - if (alert_count > 0) { - mp_raise_memorymonitor_AllocationError(translate("Attempt to allocate %d blocks"), block_count); - } -} - -void memorymonitor_allocationalarms_reset(void) { - MP_STATE_VM(active_allocationalarms) = NULL; -} diff --git a/shared-module/memorymonitor/AllocationAlarm 2.h b/shared-module/memorymonitor/AllocationAlarm 2.h deleted file mode 100644 index 172c24f6c..000000000 --- a/shared-module/memorymonitor/AllocationAlarm 2.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries - * - * 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_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONALARM_H -#define MICROPY_INCLUDED_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONALARM_H - -#include -#include - -#include "py/obj.h" - -typedef struct _memorymonitor_allocationalarm_obj_t memorymonitor_allocationalarm_obj_t; - -#define ALLOCATION_SIZE_BUCKETS 16 - -typedef struct _memorymonitor_allocationalarm_obj_t { - mp_obj_base_t base; - size_t minimum_block_count; - mp_int_t count; - // Store the location that points to us so we can remove ourselves. - memorymonitor_allocationalarm_obj_t** previous; - memorymonitor_allocationalarm_obj_t* next; -} memorymonitor_allocationalarm_obj_t; - -void memorymonitor_allocationalarms_allocation(size_t block_count); -void memorymonitor_allocationalarms_reset(void); - -#endif // MICROPY_INCLUDED_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONALARM_H diff --git a/shared-module/memorymonitor/AllocationSize 2.c b/shared-module/memorymonitor/AllocationSize 2.c deleted file mode 100644 index c28e65592..000000000 --- a/shared-module/memorymonitor/AllocationSize 2.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries - * - * 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 "shared-bindings/memorymonitor/AllocationSize.h" - -#include "py/gc.h" -#include "py/mpstate.h" -#include "py/runtime.h" - -void common_hal_memorymonitor_allocationsize_construct(memorymonitor_allocationsize_obj_t* self) { - common_hal_memorymonitor_allocationsize_clear(self); - self->next = NULL; - self->previous = NULL; -} - -void common_hal_memorymonitor_allocationsize_pause(memorymonitor_allocationsize_obj_t* self) { - *self->previous = self->next; - self->next = NULL; - self->previous = NULL; -} - -void common_hal_memorymonitor_allocationsize_resume(memorymonitor_allocationsize_obj_t* self) { - if (self->previous != NULL) { - mp_raise_RuntimeError(translate("Already running")); - } - self->next = MP_STATE_VM(active_allocationsizes); - self->previous = (memorymonitor_allocationsize_obj_t**) &MP_STATE_VM(active_allocationsizes); - if (self->next != NULL) { - self->next->previous = &self->next; - } - MP_STATE_VM(active_allocationsizes) = self; -} - -void common_hal_memorymonitor_allocationsize_clear(memorymonitor_allocationsize_obj_t* self) { - for (size_t i = 0; i < ALLOCATION_SIZE_BUCKETS; i++) { - self->buckets[i] = 0; - } -} - -uint16_t common_hal_memorymonitor_allocationsize_get_len(memorymonitor_allocationsize_obj_t* self) { - return ALLOCATION_SIZE_BUCKETS; -} - -size_t common_hal_memorymonitor_allocationsize_get_bytes_per_block(memorymonitor_allocationsize_obj_t* self) { - return BYTES_PER_BLOCK; -} - -uint16_t common_hal_memorymonitor_allocationsize_get_item(memorymonitor_allocationsize_obj_t* self, int16_t index) { - return self->buckets[index]; -} - -void memorymonitor_allocationsizes_track_allocation(size_t block_count) { - memorymonitor_allocationsize_obj_t* as = MP_OBJ_TO_PTR(MP_STATE_VM(active_allocationsizes)); - size_t power_of_two = 0; - block_count >>= 1; - while (block_count != 0) { - power_of_two++; - block_count >>= 1; - } - while (as != NULL) { - as->buckets[power_of_two]++; - as = as->next; - } -} - -void memorymonitor_allocationsizes_reset(void) { - MP_STATE_VM(active_allocationsizes) = NULL; -} diff --git a/shared-module/memorymonitor/AllocationSize 2.h b/shared-module/memorymonitor/AllocationSize 2.h deleted file mode 100644 index 3baab2213..000000000 --- a/shared-module/memorymonitor/AllocationSize 2.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of the Micro Python project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries - * - * 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_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONSIZE_H -#define MICROPY_INCLUDED_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONSIZE_H - -#include -#include - -#include "py/obj.h" - -typedef struct _memorymonitor_allocationsize_obj_t memorymonitor_allocationsize_obj_t; - -#define ALLOCATION_SIZE_BUCKETS 16 - -typedef struct _memorymonitor_allocationsize_obj_t { - mp_obj_base_t base; - uint16_t buckets[ALLOCATION_SIZE_BUCKETS]; - // Store the location that points to us so we can remove ourselves. - memorymonitor_allocationsize_obj_t** previous; - memorymonitor_allocationsize_obj_t* next; - bool paused; -} memorymonitor_allocationsize_obj_t; - -void memorymonitor_allocationsizes_track_allocation(size_t block_count); -void memorymonitor_allocationsizes_reset(void); - -#endif // MICROPY_INCLUDED_SHARED_MODULE_MEMORYMONITOR_ALLOCATIONSIZE_H diff --git a/shared-module/memorymonitor/__init__ 2.c b/shared-module/memorymonitor/__init__ 2.c deleted file mode 100644 index 6cb424153..000000000 --- a/shared-module/memorymonitor/__init__ 2.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Scott Shawcroft - * - * 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 "shared-module/memorymonitor/__init__.h" -#include "shared-module/memorymonitor/AllocationAlarm.h" -#include "shared-module/memorymonitor/AllocationSize.h" - -void memorymonitor_track_allocation(size_t block_count) { - memorymonitor_allocationalarms_allocation(block_count); - memorymonitor_allocationsizes_track_allocation(block_count); -} - -void memorymonitor_reset(void) { - memorymonitor_allocationalarms_reset(); - memorymonitor_allocationsizes_reset(); -} diff --git a/shared-module/memorymonitor/__init__ 2.h b/shared-module/memorymonitor/__init__ 2.h deleted file mode 100644 index f47f6434b..000000000 --- a/shared-module/memorymonitor/__init__ 2.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2016 Scott Shawcroft for Adafruit Industries - * - * 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_MEMORYMONITOR___INIT___H -#define MICROPY_INCLUDED_MEMORYMONITOR___INIT___H - -#include - -void memorymonitor_track_allocation(size_t block_count); -void memorymonitor_reset(void); - -#endif // MICROPY_INCLUDED_MEMORYMONITOR___INIT___H -- cgit v1.2.3 From fc513956be8cb0389d450308f6363c6b742af072 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Tue, 1 Sep 2020 09:36:29 -0500 Subject: Update refresh to force immediate redraw with display.refresh() or display.refresh(target_frames_per_second=None), even with auto_refresh=False --- shared-bindings/displayio/Display.c | 19 +++++++++++++++++-- shared-module/displayio/Display.c | 2 +- 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index c4fbdab2e..ff003ab4b 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -227,6 +227,9 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show //| When auto refresh is on, updates the display immediately. (The display will also update //| without calls to this.) //| +//| When auto refresh is off, refresh() or refresh(target_frames_per_second=None) will update +//| the display immediately. +//| //| :param int target_frames_per_second: How many times a second `refresh` should be called and the screen updated. //| :param int minimum_frames_per_second: The minimum number of times the screen should be updated per second.""" //| ... @@ -234,9 +237,11 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_display_show_obj, displayio_display_obj_show STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_target_frames_per_second, ARG_minimum_frames_per_second }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_target_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 60} }, + //{ MP_QSTR_target_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 60} }, + { MP_QSTR_target_frames_per_second, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(60)} }, { MP_QSTR_minimum_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -246,8 +251,18 @@ STATIC mp_obj_t displayio_display_obj_refresh(size_t n_args, const mp_obj_t *pos if (minimum_frames_per_second > 0) { maximum_ms_per_real_frame = 1000 / minimum_frames_per_second; } - return mp_obj_new_bool(common_hal_displayio_display_refresh(self, 1000 / args[ARG_target_frames_per_second].u_int, maximum_ms_per_real_frame)); + + uint32_t target_ms_per_frame; + if ( (args[ARG_target_frames_per_second].u_obj == mp_const_none) || (n_args == 1) ) { // if None or no arguments + target_ms_per_frame = 0xffffffff; + } + else { + target_ms_per_frame = 1000 / mp_obj_get_int(args[ARG_target_frames_per_second].u_obj); + } + + return mp_obj_new_bool(common_hal_displayio_display_refresh(self, target_ms_per_frame, maximum_ms_per_real_frame)); } + MP_DEFINE_CONST_FUN_OBJ_KW(displayio_display_refresh_obj, 1, displayio_display_obj_refresh); //| auto_refresh: bool diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 4f92f249f..021159c0d 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -352,7 +352,7 @@ uint16_t common_hal_displayio_display_get_rotation(displayio_display_obj_t* self bool common_hal_displayio_display_refresh(displayio_display_obj_t* self, uint32_t target_ms_per_frame, uint32_t maximum_ms_per_real_frame) { - if (!self->auto_refresh && !self->first_manual_refresh) { + if (!self->auto_refresh && !self->first_manual_refresh && (target_ms_per_frame != 0xffffffff) ) { uint64_t current_time = supervisor_ticks_ms64(); uint32_t current_ms_since_real_refresh = current_time - self->core.last_refresh; // Test to see if the real frame time is below our minimum. -- cgit v1.2.3 From 2f120c70eee692b8e036f8f0778af2b723e1f0e7 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 28 Aug 2020 11:17:07 -0500 Subject: rgbmatrix: recover gracefully from allocation errors e.g., allocating a 192x32x6bpp matrix would be enough to trigger this reliably on a Metro M4 Express using the "memory hogging" layout. Allocating 64x32x6bpp could trigger it, but somewhat unreliably. There are several things going on here: * we make the failing call with interrupts off * we were throwing an exception with interrupts off * protomatter failed badly in _PM_free when it was partially-initialized Incorporate the fix from protomatter, switch to a non-throwing malloc variant, and ensure that interrupts get turned back on. This decreases the quality of the MemoryError (it cannot report the size of the failed allocation) but allows CircuitPython to survive, rather than faulting. --- lib/protomatter | 2 +- shared-module/rgbmatrix/RGBMatrix.c | 17 +++++++++++------ shared-module/rgbmatrix/allocator.h | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) (limited to 'shared-module') diff --git a/lib/protomatter b/lib/protomatter index 761d6437e..2a1ba8fa4 160000 --- a/lib/protomatter +++ b/lib/protomatter @@ -1 +1 @@ -Subproject commit 761d6437e8cd6a131d51de96974337121a9c7164 +Subproject commit 2a1ba8fa4753b2bcb158c9b17351cf18eade0d2b diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index 6dad91679..a020ef089 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -89,6 +89,7 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW; } + memset(&self->core, 0, sizeof(self->core)); ProtomatterStatus stat = _PM_init(&self->core, self->width, self->bit_depth, self->rgb_count/6, self->rgb_pins, @@ -101,14 +102,17 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, common_hal_mcu_disable_interrupts(); common_hal_rgbmatrix_timer_enable(self->timer); stat = _PM_begin(&self->core); - _PM_convert_565(&self->core, self->bufinfo.buf, self->width); + + if (stat == PROTOMATTER_OK) { + _PM_convert_565(&self->core, self->bufinfo.buf, self->width); + } common_hal_mcu_enable_interrupts(); - _PM_swapbuffer_maybe(&self->core); + if (stat == PROTOMATTER_OK) { + _PM_swapbuffer_maybe(&self->core); + } } if (stat != PROTOMATTER_OK) { - // XXX this deinit() actually makes crashy-crashy - // can trigger it by sending inappropriate pins common_hal_rgbmatrix_rgbmatrix_deinit(self); switch (stat) { case PROTOMATTER_ERR_PINS: @@ -117,7 +121,9 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, case PROTOMATTER_ERR_ARG: mp_raise_ValueError(translate("Invalid argument")); break; - case PROTOMATTER_ERR_MALLOC: /// should have already been signaled as NLR + case PROTOMATTER_ERR_MALLOC: + mp_raise_msg(&mp_type_MemoryError, NULL); + break; default: mp_raise_msg_varg(&mp_type_RuntimeError, translate("Internal error #%d"), (int)stat); @@ -126,7 +132,6 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, } self->paused = 0; - } STATIC void free_pin(uint8_t *pin) { diff --git a/shared-module/rgbmatrix/allocator.h b/shared-module/rgbmatrix/allocator.h index 5e6f0b41d..172d82684 100644 --- a/shared-module/rgbmatrix/allocator.h +++ b/shared-module/rgbmatrix/allocator.h @@ -11,7 +11,7 @@ static inline void *_PM_allocator_impl(size_t sz) { if (gc_alloc_possible()) { - return m_malloc(sz + sizeof(void*), true); + return m_malloc_maybe(sz + sizeof(void*), true); } else { supervisor_allocation *allocation = allocate_memory(align32_size(sz), false); return allocation ? allocation->ptr : NULL; -- cgit v1.2.3 From e01ade3848cf828620ea25ada2b2b829dbe180f3 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 28 Aug 2020 11:24:59 -0500 Subject: rgbmatrix: Don't inline the allocator functions --- shared-module/rgbmatrix/RGBMatrix.c | 19 ++++++++++++++++++- shared-module/rgbmatrix/allocator.h | 28 +++++----------------------- 2 files changed, 23 insertions(+), 24 deletions(-) (limited to 'shared-module') diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index a020ef089..6fb36f6e3 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -84,7 +84,7 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, _PM_FREE(self->core.screenData); self->framebuffer = NULL; - self->bufinfo.buf = _PM_allocator_impl(self->bufsize); + self->bufinfo.buf = common_hal_rgbmatrix_allocator_impl(self->bufsize); self->bufinfo.len = self->bufsize; self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW; } @@ -211,3 +211,20 @@ int common_hal_rgbmatrix_rgbmatrix_get_height(rgbmatrix_rgbmatrix_obj_t* self) { int computed_height = (self->rgb_count / 3) << (self->addr_count); return computed_height; } + +void *common_hal_rgbmatrix_allocator_impl(size_t sz) { + if (gc_alloc_possible()) { + return m_malloc_maybe(sz + sizeof(void*), true); + } else { + supervisor_allocation *allocation = allocate_memory(align32_size(sz), false); + return allocation ? allocation->ptr : NULL; + } +} + +void common_hal_rgbmatrix_free_impl(void *ptr_in) { + supervisor_allocation *allocation = allocation_from_ptr(ptr_in); + + if (allocation) { + free_memory(allocation); + } +} diff --git a/shared-module/rgbmatrix/allocator.h b/shared-module/rgbmatrix/allocator.h index 172d82684..3191565a3 100644 --- a/shared-module/rgbmatrix/allocator.h +++ b/shared-module/rgbmatrix/allocator.h @@ -1,29 +1,11 @@ -#ifndef MICROPY_INCLUDED_SHARED_MODULE_RGBMATRIX_ALLOCATOR_H -#define MICROPY_INCLUDED_SHARED_MODULE_RGBMATRIX_ALLOCATOR_H +#pragma once #include #include "py/gc.h" #include "py/misc.h" #include "supervisor/memory.h" -#define _PM_ALLOCATOR _PM_allocator_impl -#define _PM_FREE(x) (_PM_free_impl((x)), (x)=NULL, (void)0) - -static inline void *_PM_allocator_impl(size_t sz) { - if (gc_alloc_possible()) { - return m_malloc_maybe(sz + sizeof(void*), true); - } else { - supervisor_allocation *allocation = allocate_memory(align32_size(sz), false); - return allocation ? allocation->ptr : NULL; - } -} - -static inline void _PM_free_impl(void *ptr_in) { - supervisor_allocation *allocation = allocation_from_ptr(ptr_in); - - if (allocation) { - free_memory(allocation); - } -} - -#endif +#define _PM_ALLOCATOR common_hal_rgbmatrix_allocator_impl +#define _PM_FREE(x) (common_hal_rgbmatrix_free_impl((x)), (x)=NULL, (void)0) +extern void *common_hal_rgbmatrix_allocator_impl(size_t sz); +extern void common_hal_rgbmatrix_free_impl(void *); -- cgit v1.2.3 From dfa90cc11ddf7cd719c448ae9c516bf2b117aa3a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 1 Sep 2020 11:00:19 -0500 Subject: allocator.h: add a missing license notice --- shared-module/rgbmatrix/allocator.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'shared-module') diff --git a/shared-module/rgbmatrix/allocator.h b/shared-module/rgbmatrix/allocator.h index 3191565a3..323fa5ec0 100644 --- a/shared-module/rgbmatrix/allocator.h +++ b/shared-module/rgbmatrix/allocator.h @@ -1,3 +1,29 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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. + */ + #pragma once #include -- cgit v1.2.3 From ce603dfebfa9a6ef057110c14c5d5b819eb93069 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 31 Aug 2020 16:00:41 -0500 Subject: rgbmatrix: Disable timer while reconstructing the display --- shared-module/rgbmatrix/RGBMatrix.c | 1 + 1 file changed, 1 insertion(+) (limited to 'shared-module') diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index 6fb36f6e3..edeef7c1f 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -66,6 +66,7 @@ void common_hal_rgbmatrix_rgbmatrix_construct(rgbmatrix_rgbmatrix_obj_t *self, i } void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, mp_obj_t framebuffer) { + common_hal_rgbmatrix_timer_disable(self->timer); if (framebuffer) { self->framebuffer = framebuffer; framebuffer = mp_obj_new_bytearray_of_zeros(self->bufsize); -- cgit v1.2.3 From 71c63c2812ce63ceabdc74aac1b2dda5eb1ca338 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 1 Sep 2020 10:30:14 -0500 Subject: FramebufferDisplay: Don't set rotation via core_construct The expectations of displayio.Display and frambufferio.FramebufferDisplay are different when it comes to rotation. In displayio.Display, if you call core_construct with a WxH = 64x32 and rotation=90, you get something that is 32 pixels wide and 64 pixels tall in the LCD's coordinate system. This is fine, as the existing definitions were written to work like this. With framebuffer displays, however, the underlying framebuffer (such as RGBMatrix) says "I am WxH pixels wide in my coordinate system" and the constructor is given a rotation; when the rotation indicates a transpose that means "exchange rows and columns, so that to the Groups displayed on it, there is an effectively HxW pixel region for use". Happily, we already have a set_rotation method. Thus (modulo the time spent debugging things anyway:) the fix is simple: Always request no rotation from core_construct, then immediately fix up the rotation to match what was requested. Testing performed: 32x16 RGBMatrix on Metro M4 Express (but using the Airlift firmware, as this is the configuration the error was reported on): * initially construct display at 0, 90, 180, 270 degrees * later change angle to 0, 90, 180, 270 degrees * no garbled display * no safe mode crashes --- shared-module/framebufferio/FramebufferDisplay.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 6b5346877..5163c3a7b 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -66,7 +66,7 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu ram_height, 0, 0, - rotation, + 0, // rotation depth, fb_getter_default(get_grayscale, (depth < 8)), fb_getter_default(get_pixels_in_byte_share_row, false), @@ -92,6 +92,10 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu self->native_frames_per_second = fb_getter_default(get_native_frames_per_second, 60); self->native_ms_per_frame = 1000 / self->native_frames_per_second; + if (rotation != 0) { + common_hal_framebufferio_framebufferdisplay_set_rotation(self, rotation); + } + supervisor_start_terminal(self->core.width, self->core.height); // Set the group after initialization otherwise we may send pixels while we delay in -- cgit v1.2.3 From 3c083330f8a201d74b120c1f9f83baef8124fae5 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 1 Sep 2020 10:58:54 -0500 Subject: RGBMatrix: Remove unused, dead allocation @tannewt noticed this in a pull request review. The allocated memory was never used, but the GC would have collected it eventually. --- shared-module/rgbmatrix/RGBMatrix.c | 1 - 1 file changed, 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index edeef7c1f..c39ec99a2 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -69,7 +69,6 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, common_hal_rgbmatrix_timer_disable(self->timer); if (framebuffer) { self->framebuffer = framebuffer; - framebuffer = mp_obj_new_bytearray_of_zeros(self->bufsize); mp_get_buffer_raise(self->framebuffer, &self->bufinfo, MP_BUFFER_READ); if (mp_get_buffer(self->framebuffer, &self->bufinfo, MP_BUFFER_RW)) { self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW; -- cgit v1.2.3 From 17a5a85528525352ec1821127fafec2acb239196 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 2 Sep 2020 13:34:16 -0500 Subject: rgbmatrix: Move struct definition to shared-module, rename 'core' member --- shared-bindings/rgbmatrix/RGBMatrix.c | 2 +- shared-bindings/rgbmatrix/RGBMatrix.h | 21 +--------------- shared-module/rgbmatrix/RGBMatrix.c | 40 ++++++++++++++--------------- shared-module/rgbmatrix/RGBMatrix.h | 47 +++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 41 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/rgbmatrix/RGBMatrix.c b/shared-bindings/rgbmatrix/RGBMatrix.c index 9cfc0d409..e4683af92 100644 --- a/shared-bindings/rgbmatrix/RGBMatrix.c +++ b/shared-bindings/rgbmatrix/RGBMatrix.c @@ -252,7 +252,7 @@ STATIC mp_obj_t rgbmatrix_rgbmatrix_deinit(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(rgbmatrix_rgbmatrix_deinit_obj, rgbmatrix_rgbmatrix_deinit); static void check_for_deinit(rgbmatrix_rgbmatrix_obj_t *self) { - if (!self->core.rgbPins) { + if (!self->protomatter.rgbPins) { raise_deinited_error(); } } diff --git a/shared-bindings/rgbmatrix/RGBMatrix.h b/shared-bindings/rgbmatrix/RGBMatrix.h index 027f817bb..1dc5a406c 100644 --- a/shared-bindings/rgbmatrix/RGBMatrix.h +++ b/shared-bindings/rgbmatrix/RGBMatrix.h @@ -24,29 +24,12 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_RGBMATRIX_RGBMATRIX_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_RGBMATRIX_RGBMATRIX_H +#pragma once #include "shared-module/rgbmatrix/RGBMatrix.h" #include "lib/protomatter/core.h" extern const mp_obj_type_t rgbmatrix_RGBMatrix_type; -typedef struct { - mp_obj_base_t base; - mp_obj_t framebuffer; - mp_buffer_info_t bufinfo; - Protomatter_core core; - void *timer; - uint16_t bufsize, width; - uint8_t rgb_pins[30]; - uint8_t addr_pins[10]; - uint8_t clock_pin, latch_pin, oe_pin; - uint8_t rgb_count, addr_count; - uint8_t bit_depth; - bool core_is_initialized; - bool paused; - bool doublebuffer; -} rgbmatrix_rgbmatrix_obj_t; void common_hal_rgbmatrix_rgbmatrix_construct(rgbmatrix_rgbmatrix_obj_t* self, int width, int bit_depth, uint8_t rgb_count, uint8_t* rgb_pins, uint8_t addr_count, uint8_t* addr_pins, uint8_t clock_pin, uint8_t latch_pin, uint8_t oe_pin, bool doublebuffer, mp_obj_t framebuffer, void* timer); void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t*); @@ -57,5 +40,3 @@ bool common_hal_rgbmatrix_rgbmatrix_get_paused(rgbmatrix_rgbmatrix_obj_t* self); void common_hal_rgbmatrix_rgbmatrix_refresh(rgbmatrix_rgbmatrix_obj_t* self); int common_hal_rgbmatrix_rgbmatrix_get_width(rgbmatrix_rgbmatrix_obj_t* self); int common_hal_rgbmatrix_rgbmatrix_get_height(rgbmatrix_rgbmatrix_obj_t* self); - -#endif diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index c39ec99a2..3007ca4db 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -79,9 +79,9 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, mp_get_index(mp_obj_get_type(self->framebuffer), self->bufinfo.len, MP_OBJ_NEW_SMALL_INT(self->bufsize-1), false); } else { _PM_FREE(self->bufinfo.buf); - _PM_FREE(self->core.rgbPins); - _PM_FREE(self->core.addr); - _PM_FREE(self->core.screenData); + _PM_FREE(self->protomatter.rgbPins); + _PM_FREE(self->protomatter.addr); + _PM_FREE(self->protomatter.screenData); self->framebuffer = NULL; self->bufinfo.buf = common_hal_rgbmatrix_allocator_impl(self->bufsize); @@ -89,8 +89,8 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, self->bufinfo.typecode = 'H' | MP_OBJ_ARRAY_TYPECODE_FLAG_RW; } - memset(&self->core, 0, sizeof(self->core)); - ProtomatterStatus stat = _PM_init(&self->core, + memset(&self->protomatter, 0, sizeof(self->protomatter)); + ProtomatterStatus stat = _PM_init(&self->protomatter, self->width, self->bit_depth, self->rgb_count/6, self->rgb_pins, self->addr_count, self->addr_pins, @@ -98,17 +98,17 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, self->doublebuffer, self->timer); if (stat == PROTOMATTER_OK) { - _PM_protoPtr = &self->core; + _PM_protoPtr = &self->protomatter; common_hal_mcu_disable_interrupts(); common_hal_rgbmatrix_timer_enable(self->timer); - stat = _PM_begin(&self->core); + stat = _PM_begin(&self->protomatter); if (stat == PROTOMATTER_OK) { - _PM_convert_565(&self->core, self->bufinfo.buf, self->width); + _PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width); } common_hal_mcu_enable_interrupts(); if (stat == PROTOMATTER_OK) { - _PM_swapbuffer_maybe(&self->core); + _PM_swapbuffer_maybe(&self->protomatter); } } @@ -153,7 +153,7 @@ void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t* self) { self->timer = 0; } - if (_PM_protoPtr == &self->core) { + if (_PM_protoPtr == &self->protomatter) { _PM_protoPtr = NULL; } @@ -163,10 +163,10 @@ void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t* self) { free_pin(&self->latch_pin); free_pin(&self->oe_pin); - if (self->core.rgbPins) { - _PM_free(&self->core); + if (self->protomatter.rgbPins) { + _PM_free(&self->protomatter); } - memset(&self->core, 0, sizeof(self->core)); + memset(&self->protomatter, 0, sizeof(self->protomatter)); // If it was supervisor-allocated, it is supervisor-freed and the pointer // is zeroed, otherwise the pointer is just zeroed @@ -180,16 +180,16 @@ void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t* self) { void rgbmatrix_rgbmatrix_collect_ptrs(rgbmatrix_rgbmatrix_obj_t* self) { gc_collect_ptr(self->framebuffer); - gc_collect_ptr(self->core.rgbPins); - gc_collect_ptr(self->core.addr); - gc_collect_ptr(self->core.screenData); + gc_collect_ptr(self->protomatter.rgbPins); + gc_collect_ptr(self->protomatter.addr); + gc_collect_ptr(self->protomatter.screenData); } void common_hal_rgbmatrix_rgbmatrix_set_paused(rgbmatrix_rgbmatrix_obj_t* self, bool paused) { if (paused && !self->paused) { - _PM_stop(&self->core); + _PM_stop(&self->protomatter); } else if (!paused && self->paused) { - _PM_resume(&self->core); + _PM_resume(&self->protomatter); } self->paused = paused; } @@ -199,8 +199,8 @@ bool common_hal_rgbmatrix_rgbmatrix_get_paused(rgbmatrix_rgbmatrix_obj_t* self) } void common_hal_rgbmatrix_rgbmatrix_refresh(rgbmatrix_rgbmatrix_obj_t* self) { - _PM_convert_565(&self->core, self->bufinfo.buf, self->width); - _PM_swapbuffer_maybe(&self->core); + _PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width); + _PM_swapbuffer_maybe(&self->protomatter); } int common_hal_rgbmatrix_rgbmatrix_get_width(rgbmatrix_rgbmatrix_obj_t* self) { diff --git a/shared-module/rgbmatrix/RGBMatrix.h b/shared-module/rgbmatrix/RGBMatrix.h index e69de29bb..19d7d5f2e 100644 --- a/shared-module/rgbmatrix/RGBMatrix.h +++ b/shared-module/rgbmatrix/RGBMatrix.h @@ -0,0 +1,47 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * + * 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. + */ + +#pragma once + +#include "lib/protomatter/core.h" + +extern const mp_obj_type_t rgbmatrix_RGBMatrix_type; +typedef struct { + mp_obj_base_t base; + mp_obj_t framebuffer; + mp_buffer_info_t bufinfo; + Protomatter_core protomatter; + void *timer; + uint16_t bufsize, width; + uint8_t rgb_pins[30]; + uint8_t addr_pins[10]; + uint8_t clock_pin, latch_pin, oe_pin; + uint8_t rgb_count, addr_count; + uint8_t bit_depth; + bool core_is_initialized; + bool paused; + bool doublebuffer; +} rgbmatrix_rgbmatrix_obj_t; -- cgit v1.2.3 From 0b94638aeb667f2a417d859487083241a5749128 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 3 Sep 2020 16:32:12 -0700 Subject: Changes based on Dan's feedback --- locale/circuitpython.pot | 14 ++-- ports/esp32s2/common-hal/socketpool/Socket.c | 11 +-- ports/esp32s2/common-hal/socketpool/SocketPool.c | 4 +- ports/esp32s2/common-hal/socketpool/__init__.c | 6 -- ports/esp32s2/common-hal/wifi/Radio.c | 14 ++-- ports/esp32s2/common-hal/wifi/ScannedNetworks.c | 1 + ports/esp32s2/common-hal/wifi/__init__.c | 91 +++++++++++------------- ports/esp32s2/mpconfigport.mk | 3 +- ports/esp32s2/partitions.csv | 12 ++-- py/circuitpy_mpconfig.mk | 2 +- shared-bindings/ipaddress/IPv4Address.c | 4 +- shared-bindings/ipaddress/__init__.c | 4 +- shared-bindings/socketpool/SocketPool.c | 2 +- shared-bindings/ssl/SSLContext.c | 2 +- shared-bindings/wifi/Radio.c | 11 ++- shared-module/ipaddress/__init__.c | 2 +- 16 files changed, 78 insertions(+), 105 deletions(-) (limited to 'shared-module') diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 2ba112d00..5122e7ba8 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-27 11:21-0400\n" +"POT-Creation-Date: 2020-09-03 15:16-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -1238,7 +1238,7 @@ msgid "Nordic Soft Device failure assertion." msgstr "" #: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string." +msgid "Not a valid IP string" msgstr "" #: ports/nrf/common-hal/_bleio/__init__.c @@ -1282,7 +1282,7 @@ msgid "" msgstr "" #: shared-bindings/ipaddress/__init__.c -msgid "Only raw int supported for ip." +msgid "Only raw int supported for ip" msgstr "" #: shared-bindings/audiobusio/PDMIn.c @@ -1365,10 +1365,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "" -#: ports/stm/ref/pulseout-pre-timeralloc.c -msgid "PulseOut not supported on this chip" -msgstr "" - #: ports/stm/common-hal/os/__init__.c msgid "RNG DeInit Error" msgstr "" @@ -1486,7 +1482,7 @@ msgid "Serializer in use" msgstr "" #: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname." +msgid "Server side context cannot have hostname" msgstr "" #: shared-bindings/nvm/ByteArray.c @@ -1792,7 +1788,7 @@ msgid "" msgstr "" #: shared-bindings/wifi/Radio.c -msgid "WiFi password must be between 8 and 63 characters." +msgid "WiFi password must be between 8 and 63 characters" msgstr "" #: ports/nrf/common-hal/_bleio/PacketBuffer.c diff --git a/ports/esp32s2/common-hal/socketpool/Socket.c b/ports/esp32s2/common-hal/socketpool/Socket.c index 654ea42d5..0a994c604 100644 --- a/ports/esp32s2/common-hal/socketpool/Socket.c +++ b/ports/esp32s2/common-hal/socketpool/Socket.c @@ -55,7 +55,6 @@ bool common_hal_socketpool_socket_connect(socketpool_socket_obj_t* self, const c if (err == ESP_ERR_MBEDTLS_SSL_SETUP_FAILED) { mp_raise_espidf_MemoryError(); } else if (ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED) { - // What should this error be? mp_raise_OSError_msg_varg(translate("Failed SSL handshake")); } else { mp_raise_OSError_msg_varg(translate("Unhandled ESP TLS error %d %d %x %d"), esp_tls_code, flags, err, result); @@ -123,15 +122,9 @@ mp_uint_t common_hal_socketpool_socket_recv_into(socketpool_socket_obj_t* self, } void common_hal_socketpool_socket_close(socketpool_socket_obj_t* self) { - if (self->connected) { - self->connected = false; - } + self->connected = false; if (self->tcp != NULL) { - int status = esp_tls_conn_destroy(self->tcp); - - if (status < 0) { - // raise an error - } + esp_tls_conn_destroy(self->tcp); self->tcp = NULL; } } diff --git a/ports/esp32s2/common-hal/socketpool/SocketPool.c b/ports/esp32s2/common-hal/socketpool/SocketPool.c index dbc9c9192..4a07f21c4 100644 --- a/ports/esp32s2/common-hal/socketpool/SocketPool.c +++ b/ports/esp32s2/common-hal/socketpool/SocketPool.c @@ -35,7 +35,7 @@ void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t* self, mp_obj_t radio) { if (radio != MP_OBJ_FROM_PTR(&common_hal_wifi_radio_obj)) { - mp_raise_ValueError(translate("SocketPool can only be used with wifi.radio.")); + mp_raise_ValueError(translate("SocketPool can only be used with wifi.radio")); } } @@ -63,7 +63,7 @@ socketpool_socket_obj_t* common_hal_socketpool_socket(socketpool_socketpool_obj_ if (socket_type == SOCK_DGRAM || socket_type == SOCK_RAW || addr_family == AF_INET6 || ipproto == IPPROTO_IPV6) { - mp_raise_NotImplementedError(translate("Only IPv4 SOCK_STREAM sockets supported.")); + mp_raise_NotImplementedError(translate("Only IPv4 SOCK_STREAM sockets supported")); } int socknum = -1; diff --git a/ports/esp32s2/common-hal/socketpool/__init__.c b/ports/esp32s2/common-hal/socketpool/__init__.c index 8f9565b46..fa0e7d5f3 100644 --- a/ports/esp32s2/common-hal/socketpool/__init__.c +++ b/ports/esp32s2/common-hal/socketpool/__init__.c @@ -23,9 +23,3 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - -#ifndef MICROPY_INCLUDED_ESP32S2_COMMON_HAL_SOCKETPOOL___INIT___H -#define MICROPY_INCLUDED_ESP32S2_COMMON_HAL_SOCKETPOOL___INIT___H - - -#endif // MICROPY_INCLUDED_ESP32S2_COMMON_HAL_SOCKETPOOL___INIT___H diff --git a/ports/esp32s2/common-hal/wifi/Radio.c b/ports/esp32s2/common-hal/wifi/Radio.c index ae3fa2f17..3c6ab5757 100644 --- a/ports/esp32s2/common-hal/wifi/Radio.c +++ b/ports/esp32s2/common-hal/wifi/Radio.c @@ -73,10 +73,12 @@ void common_hal_wifi_radio_set_enabled(wifi_radio_obj_t *self, bool enabled) { } } +#define MAC_ADDRESS_LENGTH 6 + mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) { - uint8_t mac[6]; + uint8_t mac[MAC_ADDRESS_LENGTH]; esp_wifi_get_mac(ESP_IF_WIFI_STA, mac); - return mp_const_none; + return mp_obj_new_bytes(mac, MAC_ADDRESS_LENGTH); } mp_obj_t common_hal_wifi_radio_start_scanning_networks(wifi_radio_obj_t *self) { @@ -87,8 +89,8 @@ mp_obj_t common_hal_wifi_radio_start_scanning_networks(wifi_radio_obj_t *self) { start_station(self); wifi_scannednetworks_obj_t *scan = m_new_obj(wifi_scannednetworks_obj_t); - self->current_scan = scan; scan->base.type = &wifi_scannednetworks_type; + self->current_scan = scan; scan->start_channel = 1; scan->end_channel = 11; scan->radio_event_group = self->event_group_handle; @@ -107,9 +109,7 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t wifi_config_t* config = &self->sta_config; memcpy(&config->sta.ssid, ssid, ssid_len); config->sta.ssid[ssid_len] = 0; - if (password_len > 0) { - memcpy(&config->sta.password, password, password_len); - } + memcpy(&config->sta.password, password, password_len); config->sta.password[password_len] = 0; config->sta.channel = channel; esp_wifi_set_config(ESP_IF_WIFI_STA, config); @@ -159,7 +159,7 @@ mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address, uint32_t received = 0; uint32_t total_time_ms = 0; - while (received == 0 && total_time_ms < timeout_ms) { + while (received == 0 && total_time_ms < timeout_ms && !mp_hal_is_interrupted()) { RUN_BACKGROUND_TASKS; esp_ping_get_profile(ping, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms)); esp_ping_get_profile(ping, ESP_PING_PROF_REPLY, &received, sizeof(received)); diff --git a/ports/esp32s2/common-hal/wifi/ScannedNetworks.c b/ports/esp32s2/common-hal/wifi/ScannedNetworks.c index c13fef071..507c6d186 100644 --- a/ports/esp32s2/common-hal/wifi/ScannedNetworks.c +++ b/ports/esp32s2/common-hal/wifi/ScannedNetworks.c @@ -162,6 +162,7 @@ void wifi_scannednetworks_deinit(wifi_scannednetworks_obj_t* self) { if (self->scanning) { esp_wifi_scan_stop(); if (wifi_scannednetworks_wait_for_scan(self)) { + // Ignore the number of records since we're throwing them away. uint16_t number = 0; esp_wifi_scan_get_ap_records(&number, NULL); self->scanning = false; diff --git a/ports/esp32s2/common-hal/wifi/__init__.c b/ports/esp32s2/common-hal/wifi/__init__.c index d45567946..b9ea9da06 100644 --- a/ports/esp32s2/common-hal/wifi/__init__.c +++ b/ports/esp32s2/common-hal/wifi/__init__.c @@ -44,51 +44,42 @@ static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { wifi_radio_obj_t* radio = arg; if (event_base == WIFI_EVENT) { - if (event_id == WIFI_EVENT_SCAN_DONE) { - xEventGroupSetBits(radio->event_group_handle, WIFI_SCAN_DONE_BIT); - } else if (event_id == WIFI_EVENT_STA_START) { - } else if (event_id == WIFI_EVENT_STA_STOP) { - } else if (event_id == WIFI_EVENT_STA_CONNECTED) { - ESP_EARLY_LOGW(TAG, "connected"); - } else if (event_id == WIFI_EVENT_STA_DISCONNECTED) { - ESP_EARLY_LOGW(TAG, "disconnected"); - wifi_event_sta_disconnected_t* d = (wifi_event_sta_disconnected_t*) event_data; - uint8_t reason = d->reason; - ESP_EARLY_LOGW(TAG, "reason %d 0x%02x", reason, reason); - if (radio->retries_left > 0 && - (reason == WIFI_REASON_AUTH_EXPIRE || - reason == WIFI_REASON_ASSOC_EXPIRE || - reason == WIFI_REASON_CONNECTION_FAIL || - reason == WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT)) { - radio->retries_left--; - ESP_EARLY_LOGI(TAG, "Retrying connect. %d retries remaining", radio->retries_left); - esp_wifi_connect(); - return; + switch (event_id) { + case WIFI_EVENT_SCAN_DONE: + xEventGroupSetBits(radio->event_group_handle, WIFI_SCAN_DONE_BIT); + break; + case WIFI_EVENT_STA_CONNECTED: + ESP_EARLY_LOGW(TAG, "connected"); + break; + case WIFI_EVENT_STA_DISCONNECTED: { + ESP_EARLY_LOGW(TAG, "disconnected"); + wifi_event_sta_disconnected_t* d = (wifi_event_sta_disconnected_t*) event_data; + uint8_t reason = d->reason; + ESP_EARLY_LOGW(TAG, "reason %d 0x%02x", reason, reason); + if (radio->retries_left > 0 && + (reason == WIFI_REASON_AUTH_EXPIRE || + reason == WIFI_REASON_ASSOC_EXPIRE || + reason == WIFI_REASON_CONNECTION_FAIL || + reason == WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT)) { + radio->retries_left--; + ESP_EARLY_LOGI(TAG, "Retrying connect. %d retries remaining", radio->retries_left); + esp_wifi_connect(); + return; + } + + radio->last_disconnect_reason = reason; + xEventGroupSetBits(radio->event_group_handle, WIFI_DISCONNECTED_BIT); } - radio->last_disconnect_reason = reason; - xEventGroupSetBits(radio->event_group_handle, WIFI_DISCONNECTED_BIT); - - // if (reason != WIFI_REASON_ASSOC_LEAVE) { - // // reconnect - // } - } else if (event_id == WIFI_EVENT_STA_AUTHMODE_CHANGE) { + // Cases to handle later. + // case WIFI_EVENT_STA_START: + // case WIFI_EVENT_STA_STOP: + // case WIFI_EVENT_STA_AUTHMODE_CHANGE: + default: + break; } } - // esp_wifi_connect(); - // if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { - // esp_wifi_connect(); - // } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { - // if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) { - // esp_wifi_connect(); - // s_retry_num++; - // ESP_LOGI(TAG, "retry to connect to the AP"); - // } else { - // xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); - // } - // ESP_LOGI(TAG,"connect to the AP fail"); - // } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { ESP_EARLY_LOGW(TAG, "got ip"); radio->retries_left = radio->starting_retries; @@ -100,7 +91,7 @@ static bool wifi_inited; void common_hal_wifi_init(void) { wifi_inited = true; - common_hal_wifi_radio_obj.base.type = &wifi_radio_type; + common_hal_wifi_radio_obj.base.type = &wifi_radio_type; ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); @@ -120,13 +111,13 @@ void common_hal_wifi_init(void) { self, &self->handler_instance_got_ip)); - wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT(); - esp_err_t result = esp_wifi_init(&config); - if (result == ESP_ERR_NO_MEM) { - mp_raise_msg(&mp_type_MemoryError, translate("Failed to allocate Wifi memory")); - } else if (result != ESP_OK) { - // handle this - } + wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT(); + esp_err_t result = esp_wifi_init(&config); + if (result == ESP_ERR_NO_MEM) { + mp_raise_msg(&mp_type_MemoryError, translate("Failed to allocate Wifi memory")); + } else if (result != ESP_OK) { + mp_raise_RuntimeError(translate("Failed to init wifi")); + } common_hal_wifi_radio_set_enabled(self, true); } @@ -135,14 +126,14 @@ void wifi_reset(void) { return; } wifi_radio_obj_t* radio = &common_hal_wifi_radio_obj; - common_hal_wifi_radio_set_enabled(radio, false); + common_hal_wifi_radio_set_enabled(radio, false); ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, radio->handler_instance_all_wifi)); ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, radio->handler_instance_got_ip)); - ESP_ERROR_CHECK(esp_wifi_deinit()); + ESP_ERROR_CHECK(esp_wifi_deinit()); esp_netif_destroy(radio->netif); radio->netif = NULL; ESP_ERROR_CHECK(esp_netif_deinit()); diff --git a/ports/esp32s2/mpconfigport.mk b/ports/esp32s2/mpconfigport.mk index 525271438..ee98ce1f4 100644 --- a/ports/esp32s2/mpconfigport.mk +++ b/ports/esp32s2/mpconfigport.mk @@ -23,7 +23,8 @@ CIRCUITPY_I2CPERIPHERAL = 0 CIRCUITPY_ROTARYIO = 0 CIRCUITPY_RTC = 0 CIRCUITPY_NVM = 0 -CIRCUITPY_USB_MIDI = 0 # We don't have enough endpoints to include MIDI. +# We don't have enough endpoints to include MIDI. +CIRCUITPY_USB_MIDI = 0 CIRCUITPY_WIFI = 1 CIRCUITPY_ESPIDF = 1 diff --git a/ports/esp32s2/partitions.csv b/ports/esp32s2/partitions.csv index 7c9a1cac9..cf9b3cca8 100644 --- a/ports/esp32s2/partitions.csv +++ b/ports/esp32s2/partitions.csv @@ -1,10 +1,10 @@ # ESP-IDF Partition Table # Name, Type, SubType, Offset, Size, Flags -# bootloader.bin 0x1000 -# partition table 0x8000, 0xC00 -otadata, data, ota, 0xd000, 0x2000, -phy_init, data, phy, 0xf000, 0x1000, -ota_0, 0, ota_0, 0x10000, 0x160000, -ota_1, 0, ota_1, 0x170000, 0x160000, +# bootloader.bin,, 0x1000, 32K +# partition table,, 0x8000, 4K +nvs, data, nvs, 0x9000, 20K, +otadata, data, ota, 0xe000, 8K, +ota_0, 0, ota_0, 0x10000, 1408K, +ota_1, 0, ota_1, 0x170000, 1408K, uf2, app, factory,0x2d0000, 256K, user_fs, data, fat, 0x310000, 960K, diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 2629883f8..ca2f60508 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -95,7 +95,7 @@ CFLAGS += -DCIRCUITPY_COUNTIO=$(CIRCUITPY_COUNTIO) CIRCUITPY_DISPLAYIO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_DISPLAYIO=$(CIRCUITPY_DISPLAYIO) -# CIRCUITPY_ESPIDF is handled in the atmel-samd tree. +# CIRCUITPY_ESPIDF is handled in the esp32s2 tree. # Only for ESP32S chips. # Assume not a ESP build. CIRCUITPY_ESPIDF ?= 0 diff --git a/shared-bindings/ipaddress/IPv4Address.c b/shared-bindings/ipaddress/IPv4Address.c index 03d1874cf..b2a10158a 100644 --- a/shared-bindings/ipaddress/IPv4Address.c +++ b/shared-bindings/ipaddress/IPv4Address.c @@ -39,7 +39,7 @@ //| """Encapsulates an IPv4 address.""" //| -//| def __init__(self, address: Union[str, bytes]) -> None: +//| def __init__(self, address: Union[int, str, bytes]) -> None: //| """Create a new IPv4Address object encapsulating the address value. //| //| The value itself can either be bytes or a string formatted address.""" @@ -64,7 +64,7 @@ STATIC mp_obj_t ipaddress_ipv4address_make_new(const mp_obj_type_t *type, size_t } else if (MP_OBJ_IS_STR(address)) { GET_STR_DATA_LEN(address, str_data, str_len); if (!ipaddress_parse_ipv4address((const char*) str_data, str_len, &value)) { - mp_raise_ValueError(translate("Not a valid IP string.")); + mp_raise_ValueError(translate("Not a valid IP string")); } } else { mp_buffer_info_t buf_info; diff --git a/shared-bindings/ipaddress/__init__.c b/shared-bindings/ipaddress/__init__.c index 76b63202c..7ec2984ef 100644 --- a/shared-bindings/ipaddress/__init__.c +++ b/shared-bindings/ipaddress/__init__.c @@ -88,10 +88,10 @@ STATIC mp_obj_t ipaddress_ip_address(mp_obj_t ip_in) { } else if (MP_OBJ_IS_STR(ip_in)) { GET_STR_DATA_LEN(ip_in, str_data, str_len); if (!ipaddress_parse_ipv4address((const char*) str_data, str_len, &value)) { - mp_raise_ValueError(translate("Not a valid IP string.")); + mp_raise_ValueError(translate("Not a valid IP string")); } } else { - mp_raise_ValueError(translate("Only raw int supported for ip.")); + mp_raise_ValueError(translate("Only raw int supported for ip")); } return common_hal_ipaddress_new_ipv4address(value); diff --git a/shared-bindings/socketpool/SocketPool.c b/shared-bindings/socketpool/SocketPool.c index 5624a6632..0eeebd691 100644 --- a/shared-bindings/socketpool/SocketPool.c +++ b/shared-bindings/socketpool/SocketPool.c @@ -61,7 +61,7 @@ STATIC mp_obj_t socketpool_socketpool_make_new(const mp_obj_type_t *type, size_t } -//| def socket(self, family: int, type: int, proto: int) -> None: +//| def socket(self, family: int = AF_INET, type: int = SOCK_STREAM, proto: int = IPPROTO_TCP) -> None: //| """Create a new socket //| //| :param ~int family: AF_INET or AF_INET6 diff --git a/shared-bindings/ssl/SSLContext.c b/shared-bindings/ssl/SSLContext.c index 5d44dc0f5..d2c236d3b 100644 --- a/shared-bindings/ssl/SSLContext.c +++ b/shared-bindings/ssl/SSLContext.c @@ -72,7 +72,7 @@ STATIC mp_obj_t ssl_sslcontext_wrap_socket(size_t n_args, const mp_obj_t *pos_ar const char *server_hostname = mp_obj_str_get_str(args[ARG_server_hostname].u_obj); bool server_side = args[ARG_server_side].u_bool; if (server_side && server_hostname != NULL) { - mp_raise_ValueError(translate("Server side context cannot have hostname.")); + mp_raise_ValueError(translate("Server side context cannot have hostname")); } socketpool_socket_obj_t* sock = args[ARG_sock].u_obj; diff --git a/shared-bindings/wifi/Radio.c b/shared-bindings/wifi/Radio.c index 2d356e5d9..329dcb1b5 100644 --- a/shared-bindings/wifi/Radio.c +++ b/shared-bindings/wifi/Radio.c @@ -61,7 +61,7 @@ const mp_obj_property_t wifi_radio_enabled_obj = { (mp_obj_t)&mp_const_none_obj }, }; -//| mac_address: Address +//| mac_address: bytes //| """MAC address of the wifi radio. (read-only)""" //| STATIC mp_obj_t wifi_radio_get_mac_address(mp_obj_t self) { @@ -110,7 +110,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_stop_scanning_networks_obj, wifi_rad STATIC mp_obj_t wifi_radio_connect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_ssid, ARG_password, ARG_channel, ARG_timeout }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_ssid, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_password, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, @@ -127,17 +127,14 @@ STATIC mp_obj_t wifi_radio_connect(size_t n_args, const mp_obj_t *pos_args, mp_m mp_buffer_info_t ssid; - ssid.len = 0; - if (args[ARG_ssid].u_obj != MP_OBJ_NULL) { - mp_get_buffer_raise(args[ARG_ssid].u_obj, &ssid, MP_BUFFER_READ); - } + mp_get_buffer_raise(args[ARG_ssid].u_obj, &ssid, MP_BUFFER_READ); mp_buffer_info_t password; password.len = 0; if (args[ARG_password].u_obj != MP_OBJ_NULL) { mp_get_buffer_raise(args[ARG_password].u_obj, &password, MP_BUFFER_READ); if (password.len > 0 && (password.len < 8 || password.len > 63)) { - mp_raise_ValueError(translate("WiFi password must be between 8 and 63 characters.")); + mp_raise_ValueError(translate("WiFi password must be between 8 and 63 characters")); } } diff --git a/shared-module/ipaddress/__init__.c b/shared-module/ipaddress/__init__.c index 2fce9d8f5..a8f8e1caf 100644 --- a/shared-module/ipaddress/__init__.c +++ b/shared-module/ipaddress/__init__.c @@ -31,5 +31,5 @@ mp_obj_t common_hal_ipaddress_new_ipv4address(uint32_t value) { ipaddress_ipv4address_obj_t* self = m_new_obj(ipaddress_ipv4address_obj_t); self->base.type = &ipaddress_ipv4address_type; common_hal_ipaddress_ipv4address_construct(self, (uint8_t*) &value, 4); - return self; + return MP_OBJ_FROM_PTR(self); } -- cgit v1.2.3 From f7714649eeb1b8be97099e848a800a4dea941867 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Fri, 4 Sep 2020 14:15:15 -0500 Subject: Add dirty rectangle tracking to Shape display element --- shared-module/displayio/Shape.c | 74 ++++++++++++++++++++++++++++++++++++++ shared-module/displayio/Shape.h | 5 +++ shared-module/displayio/TileGrid.c | 8 ++++- 3 files changed, 86 insertions(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Shape.c b/shared-module/displayio/Shape.c index ab9ca735b..b8412ed9a 100644 --- a/shared-module/displayio/Shape.c +++ b/shared-module/displayio/Shape.c @@ -49,10 +49,16 @@ void common_hal_displayio_shape_construct(displayio_shape_t *self, uint32_t widt self->half_height = height; self->data = m_malloc(height * sizeof(uint32_t), false); + //for (uint16_t i = 0; i < height; i++) { for (uint16_t i = 0; i <= height; i++) { self->data[2 * i] = 0; self->data[2 * i + 1] = width; } + + self->dirty_area.x1=0; + self->dirty_area.x2=width; + self->dirty_area.y1=0; + self->dirty_area.y2=height; } void common_hal_displayio_shape_set_boundary(displayio_shape_t *self, uint16_t y, uint16_t start_x, uint16_t end_x) { @@ -66,8 +72,58 @@ void common_hal_displayio_shape_set_boundary(displayio_shape_t *self, uint16_t y if (self->mirror_x && (start_x > half_width || end_x > half_width)) { mp_raise_ValueError_varg(translate("Maximum x value when mirrored is %d"), half_width); } + + uint16_t lower_x, upper_x; + + // find x-boundaries for updating based on current data and start_x, end_x + if (start_x < self->data[2 * y]) { + lower_x = start_x; + } else { + lower_x = self->data[2 * y]; + } + + if (self->mirror_x) { + upper_x = self->width-lower_x; + } else { + if (end_x > self->data[2 * y + 1]) { + upper_x = end_x + 1; + } else { + upper_x = self->data[2 * y + 1] + 1; + } + } + self->data[2 * y] = start_x; self->data[2 * y + 1] = end_x; + + if (self->dirty_area.x1 == self->dirty_area.x2) { // Dirty region is empty + self->dirty_area.x1=lower_x; + self->dirty_area.x2=upper_x; + self->dirty_area.y1 = y; + if (self->mirror_y) { + self->dirty_area.y2 = self->height-y; + } else { + self->dirty_area.y2 = y+1; + } + } else { // Dirty region is not empty + if (lower_x < self->dirty_area.x1) { + self->dirty_area.x1 = lower_x; + } + if (upper_x > self->dirty_area.x2) { + self->dirty_area.x2 = upper_x; + } + if (y < self->dirty_area.y1) { + self->dirty_area.y1=y; + if (self->mirror_y) { // if y is mirrored and the lower y was updated, the upper y must be updated too + self->dirty_area.y2=self->height-y; + } + } + else { + if ( !self->mirror_y && (y >= self->dirty_area.y2) ) { // y is not mirrored + self->dirty_area.y2=y+1; + } + } + } + } uint32_t common_hal_displayio_shape_get_pixel(void *obj, int16_t x, int16_t y) { @@ -88,3 +144,21 @@ uint32_t common_hal_displayio_shape_get_pixel(void *obj, int16_t x, int16_t y) { } return 1; } + +displayio_area_t* displayio_shape_get_refresh_areas(displayio_shape_t *self, displayio_area_t* tail) { + if (self->dirty_area.x1 == self->dirty_area.x2) { + return tail; + } + self->dirty_area.next = tail; + return &self->dirty_area; +} + +void displayio_shape_finish_refresh(displayio_shape_t *self) { + self->dirty_area.x1 = 0; + self->dirty_area.x2 = 0; +} + + + + + diff --git a/shared-module/displayio/Shape.h b/shared-module/displayio/Shape.h index ca054fe00..e59ad586e 100644 --- a/shared-module/displayio/Shape.h +++ b/shared-module/displayio/Shape.h @@ -31,6 +31,7 @@ #include #include "py/obj.h" +#include "shared-module/displayio/area.h" typedef struct { mp_obj_base_t base; @@ -41,6 +42,10 @@ typedef struct { uint16_t* data; bool mirror_x; bool mirror_y; + displayio_area_t dirty_area; } displayio_shape_t; +void displayio_shape_finish_refresh(displayio_shape_t *self); +displayio_area_t* displayio_shape_get_refresh_areas(displayio_shape_t *self, displayio_area_t* tail); + #endif // MICROPY_INCLUDED_SHARED_MODULE_DISPLAYIO_SHAPE_H diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index 2766cbecd..e3642107f 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -499,7 +499,7 @@ void displayio_tilegrid_finish_refresh(displayio_tilegrid_t *self) { if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_bitmap_type)) { displayio_bitmap_finish_refresh(self->bitmap); } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_shape_type)) { - // TODO: Support shape changes. + displayio_shape_finish_refresh(self->bitmap); } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_ondiskbitmap_type)) { // OnDiskBitmap changes will trigger a complete reload so no need to // track changes. @@ -543,6 +543,12 @@ displayio_area_t* displayio_tilegrid_get_refresh_areas(displayio_tilegrid_t *sel self->full_change = true; } } + } else if (MP_OBJ_IS_TYPE(self->bitmap, &displayio_shape_type)) { + displayio_area_t* refresh_area = displayio_shape_get_refresh_areas(self->bitmap, tail); + if (refresh_area != tail) { + displayio_area_copy(refresh_area, &self->dirty_area); + self->partial_change = true; + } } self->full_change = self->full_change || -- cgit v1.2.3 From 9edad9ea851528b1be4ee924c49fa3ecc67f9fe1 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Fri, 4 Sep 2020 14:21:49 -0500 Subject: Delete trailing blank lines from Shape.c --- shared-module/displayio/Shape.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Shape.c b/shared-module/displayio/Shape.c index b8412ed9a..a0cce60b2 100644 --- a/shared-module/displayio/Shape.c +++ b/shared-module/displayio/Shape.c @@ -156,9 +156,4 @@ displayio_area_t* displayio_shape_get_refresh_areas(displayio_shape_t *self, dis void displayio_shape_finish_refresh(displayio_shape_t *self) { self->dirty_area.x1 = 0; self->dirty_area.x2 = 0; -} - - - - - +} \ No newline at end of file -- cgit v1.2.3 From 95db456a7ea3db6b4f8047e2fe8b0351354ac7d7 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Fri, 4 Sep 2020 14:23:53 -0500 Subject: Add final newline --- shared-module/displayio/Shape.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Shape.c b/shared-module/displayio/Shape.c index a0cce60b2..ac2abd150 100644 --- a/shared-module/displayio/Shape.c +++ b/shared-module/displayio/Shape.c @@ -156,4 +156,4 @@ displayio_area_t* displayio_shape_get_refresh_areas(displayio_shape_t *self, dis void displayio_shape_finish_refresh(displayio_shape_t *self) { self->dirty_area.x1 = 0; self->dirty_area.x2 = 0; -} \ No newline at end of file +} -- cgit v1.2.3 From 297b7195b089f08cd40f97f8a244484a82d2094e Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Fri, 4 Sep 2020 22:03:57 -0500 Subject: Delete unnecessary comment --- shared-module/displayio/Shape.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Shape.c b/shared-module/displayio/Shape.c index ac2abd150..a09191cce 100644 --- a/shared-module/displayio/Shape.c +++ b/shared-module/displayio/Shape.c @@ -49,7 +49,7 @@ void common_hal_displayio_shape_construct(displayio_shape_t *self, uint32_t widt self->half_height = height; self->data = m_malloc(height * sizeof(uint32_t), false); - //for (uint16_t i = 0; i < height; i++) { + for (uint16_t i = 0; i <= height; i++) { self->data[2 * i] = 0; self->data[2 * i + 1] = width; -- cgit v1.2.3 From 8d27533cd45f0dc759f84e68408839f118c0c9d2 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 6 Sep 2020 18:03:25 -0500 Subject: Make sure SPI lock is free initially --- shared-module/board/__init__.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'shared-module') diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 265c6517f..903b8fa71 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -89,6 +89,8 @@ mp_obj_t common_hal_board_create_spi(void) { const mcu_pin_obj_t* mosi = MP_OBJ_TO_PTR(DEFAULT_SPI_BUS_MOSI); const mcu_pin_obj_t* miso = MP_OBJ_TO_PTR(DEFAULT_SPI_BUS_MISO); common_hal_busio_spi_construct(self, clock, mosi, miso); + // make sure lock is not held initially + common_hal_busio_spi_unlock(self); spi_singleton = (mp_obj_t)self; return spi_singleton; } -- cgit v1.2.3 From d600759bc808c5e78d429b6da8c824f5574cee82 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Tue, 8 Sep 2020 20:02:34 -0500 Subject: Utilize MIN and MAX functions from py/misc.h --- shared-module/displayio/Shape.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Shape.c b/shared-module/displayio/Shape.c index a09191cce..4f481f224 100644 --- a/shared-module/displayio/Shape.c +++ b/shared-module/displayio/Shape.c @@ -29,6 +29,7 @@ #include #include "py/runtime.h" +#include "py/misc.h" void common_hal_displayio_shape_construct(displayio_shape_t *self, uint32_t width, uint32_t height, bool mirror_x, bool mirror_y) { @@ -76,20 +77,12 @@ void common_hal_displayio_shape_set_boundary(displayio_shape_t *self, uint16_t y uint16_t lower_x, upper_x; // find x-boundaries for updating based on current data and start_x, end_x - if (start_x < self->data[2 * y]) { - lower_x = start_x; - } else { - lower_x = self->data[2 * y]; - } + lower_x = MIN(start_x, self->data[2 * y]); if (self->mirror_x) { upper_x = self->width-lower_x; } else { - if (end_x > self->data[2 * y + 1]) { - upper_x = end_x + 1; - } else { - upper_x = self->data[2 * y + 1] + 1; - } + upper_x = 1 + MAX(end_x, self->data[2 * y + 1]); } self->data[2 * y] = start_x; @@ -105,12 +98,10 @@ void common_hal_displayio_shape_set_boundary(displayio_shape_t *self, uint16_t y self->dirty_area.y2 = y+1; } } else { // Dirty region is not empty - if (lower_x < self->dirty_area.x1) { - self->dirty_area.x1 = lower_x; - } - if (upper_x > self->dirty_area.x2) { - self->dirty_area.x2 = upper_x; - } + + self->dirty_area.x1 = MIN(lower_x, self->dirty_area.x1); + self->dirty_area.x2 = MAX(upper_x, self->dirty_area.x2); + if (y < self->dirty_area.y1) { self->dirty_area.y1=y; if (self->mirror_y) { // if y is mirrored and the lower y was updated, the upper y must be updated too -- cgit v1.2.3 From 24a18c63f9d3990661cc58888896faba9c8fad50 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 9 Sep 2020 09:32:25 -0500 Subject: Moved SPI unlock to reset_board_busses() --- shared-module/board/__init__.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 903b8fa71..153aa086c 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -89,8 +89,6 @@ mp_obj_t common_hal_board_create_spi(void) { const mcu_pin_obj_t* mosi = MP_OBJ_TO_PTR(DEFAULT_SPI_BUS_MOSI); const mcu_pin_obj_t* miso = MP_OBJ_TO_PTR(DEFAULT_SPI_BUS_MISO); common_hal_busio_spi_construct(self, clock, mosi, miso); - // make sure lock is not held initially - common_hal_busio_spi_unlock(self); spi_singleton = (mp_obj_t)self; return spi_singleton; } @@ -153,6 +151,7 @@ void reset_board_busses(void) { #endif #if BOARD_SPI bool display_using_spi = false; + busio_spi_obj_t *self = &spi_obj; #if CIRCUITPY_DISPLAYIO for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { mp_const_obj_t bus_type = displays[i].bus_base.type; @@ -169,6 +168,8 @@ void reset_board_busses(void) { } #endif if (!display_using_spi) { + // make sure lock is not held over a soft reset + common_hal_busio_spi_unlock(self); spi_singleton = NULL; } #endif -- cgit v1.2.3 From 59165cabbe1c27260678c4e252465b11e1cf8c0e Mon Sep 17 00:00:00 2001 From: root Date: Wed, 9 Sep 2020 10:36:55 -0500 Subject: Removed unneeded pointer --- shared-module/board/__init__.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 153aa086c..ae0659791 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -151,7 +151,6 @@ void reset_board_busses(void) { #endif #if BOARD_SPI bool display_using_spi = false; - busio_spi_obj_t *self = &spi_obj; #if CIRCUITPY_DISPLAYIO for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { mp_const_obj_t bus_type = displays[i].bus_base.type; @@ -169,7 +168,7 @@ void reset_board_busses(void) { #endif if (!display_using_spi) { // make sure lock is not held over a soft reset - common_hal_busio_spi_unlock(self); + common_hal_busio_spi_unlock(&spi_obj); spi_singleton = NULL; } #endif -- cgit v1.2.3 From 37e85aebd25502e7c1213797cde8b0c02359d029 Mon Sep 17 00:00:00 2001 From: Kevin Matocha Date: Thu, 10 Sep 2020 21:34:03 -0500 Subject: Fix off-by-one error, simplify the logic, add comments --- shared-module/displayio/Shape.c | 68 +++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 37 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Shape.c b/shared-module/displayio/Shape.c index 4f481f224..b94a392bc 100644 --- a/shared-module/displayio/Shape.c +++ b/shared-module/displayio/Shape.c @@ -38,20 +38,20 @@ void common_hal_displayio_shape_construct(displayio_shape_t *self, uint32_t widt self->width = width; if (self->mirror_x) { width /= 2; - width += self->width % 2 - 1; + width += self->width % 2; } self->half_width = width; self->height = height; if (self->mirror_y) { height /= 2; - height += self->height % 2 - 1; + height += self->height % 2; } self->half_height = height; self->data = m_malloc(height * sizeof(uint32_t), false); - for (uint16_t i = 0; i <= height; i++) { + for (uint16_t i = 0; i < height; i++) { self->data[2 * i] = 0; self->data[2 * i + 1] = width; } @@ -63,58 +63,52 @@ void common_hal_displayio_shape_construct(displayio_shape_t *self, uint32_t widt } void common_hal_displayio_shape_set_boundary(displayio_shape_t *self, uint16_t y, uint16_t start_x, uint16_t end_x) { - if (y < 0 || y >= self->height || (self->mirror_y && y > self->half_height)) { + if (y < 0 || y >= self->height || (self->mirror_y && y >= self->half_height)) { mp_raise_ValueError(translate("y value out of bounds")); } - if (start_x < 0 || start_x > self->width || end_x < 0 || end_x > self->width) { + if (start_x < 0 || start_x >= self->width || end_x < 0 || end_x >= self->width) { mp_raise_ValueError(translate("x value out of bounds")); } - uint16_t half_width = self->width / 2 - 1 + self->width % 2; - if (self->mirror_x && (start_x > half_width || end_x > half_width)) { - mp_raise_ValueError_varg(translate("Maximum x value when mirrored is %d"), half_width); + if (self->mirror_x && (start_x >= self->half_width || end_x >= self->half_width)) { + mp_raise_ValueError_varg(translate("Maximum x value when mirrored is %d"), self->half_width); } - uint16_t lower_x, upper_x; + uint16_t lower_x, upper_x, lower_y, upper_y; - // find x-boundaries for updating based on current data and start_x, end_x + // find x-boundaries for updating based on current data and start_x, end_x, and mirror_x lower_x = MIN(start_x, self->data[2 * y]); if (self->mirror_x) { - upper_x = self->width-lower_x; + upper_x = self->width - lower_x + 1; // dirty rectangles are treated with max value exclusive } else { - upper_x = 1 + MAX(end_x, self->data[2 * y + 1]); + upper_x = MAX(end_x, self->data[2 * y + 1]) + 1; // dirty rectangles are treated with max value exclusive } - self->data[2 * y] = start_x; + // find y-boundaries based on y and mirror_y + lower_y = y; + + if (self->mirror_y) { + upper_y = self->height - lower_y + 1; // dirty rectangles are treated with max value exclusive + } else { + upper_y = y + 1; // dirty rectangles are treated with max value exclusive + } + + self->data[2 * y] = start_x; // update the data array with the new boundaries self->data[2 * y + 1] = end_x; if (self->dirty_area.x1 == self->dirty_area.x2) { // Dirty region is empty - self->dirty_area.x1=lower_x; - self->dirty_area.x2=upper_x; - self->dirty_area.y1 = y; - if (self->mirror_y) { - self->dirty_area.y2 = self->height-y; - } else { - self->dirty_area.y2 = y+1; - } - } else { // Dirty region is not empty + self->dirty_area.x1 = lower_x; + self->dirty_area.x2 = upper_x; + self->dirty_area.y1 = lower_y; + self->dirty_area.y2 = upper_y; + } else { // Dirty region is not empty self->dirty_area.x1 = MIN(lower_x, self->dirty_area.x1); self->dirty_area.x2 = MAX(upper_x, self->dirty_area.x2); - if (y < self->dirty_area.y1) { - self->dirty_area.y1=y; - if (self->mirror_y) { // if y is mirrored and the lower y was updated, the upper y must be updated too - self->dirty_area.y2=self->height-y; - } - } - else { - if ( !self->mirror_y && (y >= self->dirty_area.y2) ) { // y is not mirrored - self->dirty_area.y2=y+1; - } - } + self->dirty_area.y1 = MIN(lower_y, self->dirty_area.y1); + self->dirty_area.y2 = MAX(upper_y, self->dirty_area.y2); } - } uint32_t common_hal_displayio_shape_get_pixel(void *obj, int16_t x, int16_t y) { @@ -122,10 +116,10 @@ uint32_t common_hal_displayio_shape_get_pixel(void *obj, int16_t x, int16_t y) { if (x >= self->width || x < 0 || y >= self->height || y < 0) { return 0; } - if (self->mirror_x && x > self->half_width) { - x = self->width - 1 - x; + if (self->mirror_x && x >= self->half_width) { + x = self->width - x - 1; } - if (self->mirror_y && y > self->half_height) { + if (self->mirror_y && y >= self->half_height) { y = self->height - y - 1; } uint16_t start_x = self->data[2 * y]; -- cgit v1.2.3 From 870326b2218e24a20f40c8ee72f3ec27d0f3813b Mon Sep 17 00:00:00 2001 From: root Date: Fri, 11 Sep 2020 10:54:46 -0500 Subject: Moved SPI unlock code --- shared-module/board/__init__.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index ae0659791..7d99f2d4e 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -166,9 +166,9 @@ void reset_board_busses(void) { #endif } #endif + // make sure SPI lock is not held over a soft reset + common_hal_busio_spi_unlock(&spi_obj); if (!display_using_spi) { - // make sure lock is not held over a soft reset - common_hal_busio_spi_unlock(&spi_obj); spi_singleton = NULL; } #endif -- cgit v1.2.3