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 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 f95ad7b27c040e54daeb4c71d6bb6c35844be66e Mon Sep 17 00:00:00 2001 From: Lucian Copeland Date: Thu, 10 Sep 2020 15:37:43 -0400 Subject: Fix reset pin null reference, construct error null reference --- shared-module/displayio/FourWire.c | 4 +++- shared-module/displayio/I2CDisplay.c | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c index 17e8cfa1d..726116208 100644 --- a/shared-module/displayio/FourWire.c +++ b/shared-module/displayio/FourWire.c @@ -76,7 +76,9 @@ void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self) { common_hal_reset_pin(self->command.pin); common_hal_reset_pin(self->chip_select.pin); - common_hal_reset_pin(self->reset.pin); + if (self->reset.pin) { + common_hal_reset_pin(self->reset.pin); + } } bool common_hal_displayio_fourwire_reset(mp_obj_t obj) { diff --git a/shared-module/displayio/I2CDisplay.c b/shared-module/displayio/I2CDisplay.c index 0c8f2e69a..9e9e17881 100644 --- a/shared-module/displayio/I2CDisplay.c +++ b/shared-module/displayio/I2CDisplay.c @@ -53,6 +53,7 @@ void common_hal_displayio_i2cdisplay_construct(displayio_i2cdisplay_obj_t* self, // Probe the bus to see if a device acknowledges the given address. if (!common_hal_busio_i2c_probe(i2c, device_address)) { + self->base.type = &mp_type_NoneType; mp_raise_ValueError_varg(translate("Unable to find I2C Display at %x"), device_address); } @@ -71,7 +72,9 @@ void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self) { common_hal_busio_i2c_deinit(self->bus); } - common_hal_reset_pin(self->reset.pin); + if (self->reset.pin) { + common_hal_reset_pin(self->reset.pin); + } } bool common_hal_displayio_i2cdisplay_reset(mp_obj_t obj) { -- 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 From e114b5ab54e3c7f4a36a03dae2913cb76804efa3 Mon Sep 17 00:00:00 2001 From: FoamyGuy Date: Fri, 11 Sep 2020 21:37:00 -0500 Subject: fixes showing OnDiskBitmap with adafruit_sdcard --- shared-module/displayio/Display.c | 5 ++--- shared-module/displayio/display_core.c | 12 +++++++++++- shared-module/displayio/display_core.h | 3 ++- 3 files changed, 15 insertions(+), 5 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 021159c0d..70ed8f2c2 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -317,11 +317,10 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* } STATIC void _refresh_display(displayio_display_obj_t* self) { - if (!displayio_display_core_bus_free(&self->core)) { - // Can't acquire display bus; skip updating this display. Try next display. + if (!displayio_display_core_start_refresh(&self->core)) { + // A refresh on this bus is already in progress. Try next display. return; } - displayio_display_core_start_refresh(&self->core); const displayio_area_t* current_area = _get_refresh_areas(self); while (current_area != NULL) { _refresh_area(self, current_area); diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 43f2d1937..68572c44f 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -295,8 +295,17 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, } } -void displayio_display_core_start_refresh(displayio_display_core_t* self) { +bool displayio_display_core_start_refresh(displayio_display_core_t* self) { + if (!displayio_display_core_bus_free(self)) { + // Can't acquire display bus; skip updating this display. Try next display. + return false; + } + if (self->refresh_in_progress) { + return false; + } + self->refresh_in_progress = true; self->last_refresh = supervisor_ticks_ms64(); + return true; } void displayio_display_core_finish_refresh(displayio_display_core_t* self) { @@ -305,6 +314,7 @@ void displayio_display_core_finish_refresh(displayio_display_core_t* self) { displayio_group_finish_refresh(self->current_group); } self->full_refresh = false; + self->refresh_in_progress = false; self->last_refresh = supervisor_ticks_ms64(); } diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index e4fd62d4a..c72111f7d 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -54,6 +54,7 @@ typedef struct { int16_t colstart; int16_t rowstart; bool full_refresh; // New group means we need to refresh the whole display. + bool refresh_in_progress; } displayio_display_core_t; void displayio_display_core_construct(displayio_display_core_t* self, @@ -78,7 +79,7 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, void release_display_core(displayio_display_core_t* self); -void displayio_display_core_start_refresh(displayio_display_core_t* self); +bool displayio_display_core_start_refresh(displayio_display_core_t* self); void displayio_display_core_finish_refresh(displayio_display_core_t* self); void displayio_display_core_collect_ptrs(displayio_display_core_t* self); -- cgit v1.2.3 From e504438fd223c9bb0b9d6950a699f1283ece137c Mon Sep 17 00:00:00 2001 From: Lucian Copeland Date: Mon, 14 Sep 2020 11:58:13 -0400 Subject: Remove unlicensed file, fix reset pin type check --- ports/esp32s2/boards/esp32s2-saola-1.cfg | 41 -------------------------------- shared-module/displayio/I2CDisplay.c | 4 ++-- 2 files changed, 2 insertions(+), 43 deletions(-) delete mode 100644 ports/esp32s2/boards/esp32s2-saola-1.cfg (limited to 'shared-module') diff --git a/ports/esp32s2/boards/esp32s2-saola-1.cfg b/ports/esp32s2/boards/esp32s2-saola-1.cfg deleted file mode 100644 index 677290757..000000000 --- a/ports/esp32s2/boards/esp32s2-saola-1.cfg +++ /dev/null @@ -1,41 +0,0 @@ -# The ESP32-S2 only supports JTAG. -transport select jtag -adapter_khz 1000 - -# Source the ESP common configuration file -source [find target/esp_common.cfg] - -if { [info exists CHIPNAME] } { - set _CHIPNAME $CHIPNAME -} else { - set _CHIPNAME esp32s2 -} - -if { [info exists CPUTAPID] } { - set _CPUTAPID $CPUTAPID -} else { - set _CPUTAPID 0x120034e5 -} - -set _TARGETNAME $_CHIPNAME -set _CPUNAME cpu -set _TAPNAME $_CHIPNAME.$_CPUNAME - -jtag newtap $_CHIPNAME $_CPUNAME -irlen 5 -expected-id $_CPUTAPID - -if { $_RTOS == "none" } { - target create $_TARGETNAME esp32s2 -endian little -chain-position $_TAPNAME -} else { - target create $_TARGETNAME esp32s2 -endian little -chain-position $_TAPNAME -rtos $_RTOS -} - -configure_esp_workarea $_TARGETNAME 0x40030000 0x3400 0x3FFE0000 0x6000 -configure_esp_flash_bank $_TARGETNAME $_TARGETNAME $_FLASH_SIZE - -xtensa maskisr on -if { $_SEMIHOST_BASEDIR != "" } { - esp semihost_basedir $_SEMIHOST_BASEDIR -} -if { $_FLASH_SIZE == 0 } { - gdb_breakpoint_override hard -} diff --git a/shared-module/displayio/I2CDisplay.c b/shared-module/displayio/I2CDisplay.c index 9e9e17881..5bd03dcd6 100644 --- a/shared-module/displayio/I2CDisplay.c +++ b/shared-module/displayio/I2CDisplay.c @@ -72,8 +72,8 @@ void common_hal_displayio_i2cdisplay_deinit(displayio_i2cdisplay_obj_t* self) { common_hal_busio_i2c_deinit(self->bus); } - if (self->reset.pin) { - common_hal_reset_pin(self->reset.pin); + if (self->reset.base.type == &digitalio_digitalinout_type) { + common_hal_digitalio_digitalinout_deinit(&self->reset); } } -- cgit v1.2.3 From a2e1867f69ec2d703a9651e5c36a02b0e14dfd9c Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 20 Aug 2020 11:08:00 -0500 Subject: _canio: Minimal implementation for SAM E5x MCUs Tested & working: * Send standard packets * Receive standard packets (1 FIFO, no filter) Interoperation between SAM E54 Xplained running this tree and MicroPython running on STM32F405 Feather with an external transceiver was also tested. Many other aspects of a full implementation are not yet present, such as error detection and recovery. --- main.c | 8 + ports/atmel-samd/Makefile | 4 + .../asf4_conf/same54/peripheral_clk_config.h | 82 +++++ ports/atmel-samd/boards/common.template.ld | 7 +- .../boards/same54_xplained/mpconfigboard.mk | 1 + ports/atmel-samd/boards/same54_xplained/pins.c | 5 +- ports/atmel-samd/common-hal/_canio/CAN.c | 384 +++++++++++++++++++++ ports/atmel-samd/common-hal/_canio/CAN.h | 62 ++++ ports/atmel-samd/common-hal/_canio/Listener.c | 117 +++++++ ports/atmel-samd/common-hal/_canio/Listener.h | 53 +++ ports/atmel-samd/common-hal/_canio/__init__.c | 25 ++ ports/atmel-samd/common-hal/_canio/__init__.h | 62 ++++ ports/atmel-samd/tools/mkcandata.py | 31 ++ py/circuitpy_defns.mk | 9 + py/circuitpy_mpconfig.h | 8 + py/circuitpy_mpconfig.mk | 3 + shared-bindings/_canio/CAN.c | 338 ++++++++++++++++++ shared-bindings/_canio/CAN.h | 31 ++ shared-bindings/_canio/Listener.c | 197 +++++++++++ shared-bindings/_canio/Listener.h | 31 ++ shared-bindings/_canio/Match.c | 140 ++++++++ shared-bindings/_canio/Match.h | 33 ++ shared-bindings/_canio/Message.c | 213 ++++++++++++ shared-bindings/_canio/Message.h | 31 ++ shared-bindings/_canio/__init__.c | 73 ++++ shared-bindings/_canio/__init__.h | 29 ++ shared-module/_canio/Match.c | 43 +++ shared-module/_canio/Match.h | 41 +++ shared-module/_canio/Message.c | 85 +++++ shared-module/_canio/Message.h | 47 +++ 30 files changed, 2190 insertions(+), 3 deletions(-) create mode 100644 ports/atmel-samd/common-hal/_canio/CAN.c create mode 100644 ports/atmel-samd/common-hal/_canio/CAN.h create mode 100644 ports/atmel-samd/common-hal/_canio/Listener.c create mode 100644 ports/atmel-samd/common-hal/_canio/Listener.h create mode 100644 ports/atmel-samd/common-hal/_canio/__init__.c create mode 100644 ports/atmel-samd/common-hal/_canio/__init__.h create mode 100755 ports/atmel-samd/tools/mkcandata.py create mode 100644 shared-bindings/_canio/CAN.c create mode 100644 shared-bindings/_canio/CAN.h create mode 100644 shared-bindings/_canio/Listener.c create mode 100644 shared-bindings/_canio/Listener.h create mode 100644 shared-bindings/_canio/Match.c create mode 100644 shared-bindings/_canio/Match.h create mode 100644 shared-bindings/_canio/Message.c create mode 100644 shared-bindings/_canio/Message.h create mode 100644 shared-bindings/_canio/__init__.c create mode 100644 shared-bindings/_canio/__init__.h create mode 100644 shared-module/_canio/Match.c create mode 100644 shared-module/_canio/Match.h create mode 100644 shared-module/_canio/Message.c create mode 100644 shared-module/_canio/Message.h (limited to 'shared-module') diff --git a/main.c b/main.c index 5b719dc4b..f259fea3f 100755 --- a/main.c +++ b/main.c @@ -81,6 +81,10 @@ #include "supervisor/shared/bluetooth.h" #endif +#if CIRCUITPY_CANIO +#include "common-hal/_canio/CAN.h" +#endif + void do_str(const char *src, mp_parse_input_kind_t input_kind) { mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0); if (lex == NULL) { @@ -226,6 +230,10 @@ void cleanup_after_vm(supervisor_allocation* heap) { free_memory(heap); supervisor_move_memory(); + #ifdef CIRCUITPY_CANIO + common_hal_canio_reset(); + #endif + reset_port(); #if CIRCUITPY_BOARD reset_board_busses(); diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index aba630dbb..1ee21679d 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -393,6 +393,10 @@ SRC_QSTR += $(HEADER_BUILD)/sdiodata.h $(HEADER_BUILD)/sdiodata.h: tools/mksdiodata.py | $(HEADER_BUILD) $(Q)$(PYTHON3) $< > $@ +SRC_QSTR += $(HEADER_BUILD)/candata.h +$(HEADER_BUILD)/candata.h: tools/mkcandata.py | $(HEADER_BUILD) + $(Q)$(PYTHON3) $< > $@ + SRC_QSTR += $(SRC_C) $(SRC_SUPERVISOR) $(SRC_COMMON_HAL_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED) # Sources that only hold QSTRs after pre-processing. SRC_QSTR_PREPROCESSOR += peripherals/samd/$(PERIPHERALS_CHIP_FAMILY)/clocks.c diff --git a/ports/atmel-samd/asf4_conf/same54/peripheral_clk_config.h b/ports/atmel-samd/asf4_conf/same54/peripheral_clk_config.h index 59fe8730e..51173f6d3 100644 --- a/ports/atmel-samd/asf4_conf/same54/peripheral_clk_config.h +++ b/ports/atmel-samd/asf4_conf/same54/peripheral_clk_config.h @@ -1165,6 +1165,88 @@ #define CONF_SDHC1_SLOW_FREQUENCY 12000000 #endif +// CAN Clock Settings +// CAN Clock source + +// Generic clock generator 0 + +// Generic clock generator 1 + +// Generic clock generator 2 + +// Generic clock generator 3 + +// Generic clock generator 4 + +// Generic clock generator 5 + +// Generic clock generator 6 + +// Generic clock generator 7 + +// Generic clock generator 8 + +// Generic clock generator 9 + +// Generic clock generator 10 + +// Generic clock generator 11 + +// Select the clock source for CAN. +// sdhc_gclk_selection +#ifndef CONF_GCLK_CAN0_SRC +#define CONF_GCLK_CAN0_SRC GCLK_PCHCTRL_GEN_GCLK0_Val +#endif + +/** + * \def CAN FREQUENCY + * \brief CAN's Clock frequency + */ +#ifndef CONF_CAN0_FREQUENCY +#define CONF_CAN0_FREQUENCY 120000000 +#endif + +// CAN Clock Settings +// CAN Clock source + +// Generic clock generator 0 + +// Generic clock generator 1 + +// Generic clock generator 2 + +// Generic clock generator 3 + +// Generic clock generator 4 + +// Generic clock generator 5 + +// Generic clock generator 6 + +// Generic clock generator 7 + +// Generic clock generator 8 + +// Generic clock generator 9 + +// Generic clock generator 10 + +// Generic clock generator 11 + +// Select the clock source for CAN. +// sdhc_gclk_selection +#ifndef CONF_GCLK_CAN1_SRC +#define CONF_GCLK_CAN1_SRC GCLK_PCHCTRL_GEN_GCLK0_Val +#endif + +/** + * \def CAN FREQUENCY + * \brief CAN's Clock frequency + */ +#ifndef CONF_CAN1_FREQUENCY +#define CONF_CAN1_FREQUENCY 120000000 +#endif + // <<< end of configuration section >>> #endif // PERIPHERAL_CLK_CONFIG_H diff --git a/ports/atmel-samd/boards/common.template.ld b/ports/atmel-samd/boards/common.template.ld index 1054605c8..19e4753f8 100644 --- a/ports/atmel-samd/boards/common.template.ld +++ b/ports/atmel-samd/boards/common.template.ld @@ -51,6 +51,7 @@ SECTIONS { . = ALIGN(4); _srelocate = .; /* create a global symbol at data start; used by startup code in order to initialize the .data section in RAM */ + . = ALIGN(4); *(.ramfunc) *(.ramfunc*) *(.data) /* .data sections */ @@ -61,11 +62,15 @@ SECTIONS } >RAM /* Uninitialized data section */ - .bss : + .bss (NOLOAD) : { . = ALIGN(4); _sbss = .; _szero = .; /* define a global symbol at bss start; used by startup code */ + /* Data accessed by the CAN peripheral must be in the first 64kB RAM */ + _scanram = .; + *(.canram) + _ecanram = .; *(.bss) *(.bss*) *(COMMON) diff --git a/ports/atmel-samd/boards/same54_xplained/mpconfigboard.mk b/ports/atmel-samd/boards/same54_xplained/mpconfigboard.mk index 7ac126514..e4472e05d 100644 --- a/ports/atmel-samd/boards/same54_xplained/mpconfigboard.mk +++ b/ports/atmel-samd/boards/same54_xplained/mpconfigboard.mk @@ -12,3 +12,4 @@ EXTERNAL_FLASH_DEVICES = "N25Q256A" LONGINT_IMPL = MPZ CIRCUITPY_SDIOIO = 1 +CIRCUITPY_CANIO = 1 diff --git a/ports/atmel-samd/boards/same54_xplained/pins.c b/ports/atmel-samd/boards/same54_xplained/pins.c index 8a864ab97..1ed431fba 100644 --- a/ports/atmel-samd/boards/same54_xplained/pins.c +++ b/ports/atmel-samd/boards/same54_xplained/pins.c @@ -48,8 +48,9 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_QT), MP_ROM_PTR(&pin_PA16) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CANRX), MP_ROM_PTR(&pin_PB12) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CANTX), MP_ROM_PTR(&pin_PB13) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_PB13) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_PB12) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_STANDBY), MP_ROM_PTR(&pin_PC13) }, // EXT1 header { MP_OBJ_NEW_QSTR(MP_QSTR_PB04), MP_ROM_PTR(&pin_PB04) }, diff --git a/ports/atmel-samd/common-hal/_canio/CAN.c b/ports/atmel-samd/common-hal/_canio/CAN.c new file mode 100644 index 000000000..dcd269495 --- /dev/null +++ b/ports/atmel-samd/common-hal/_canio/CAN.c @@ -0,0 +1,384 @@ +/* + * 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/runtime.h" +#include "py/mperrno.h" + +#include "peripheral_clk_config.h" + +#include "common-hal/_canio/CAN.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "supervisor/port.h" + +#include "component/can.h" + +#include "genhdr/candata.h" + +STATIC Can * const can_insts[] = CAN_INSTS; + +STATIC canio_can_obj_t *can_objs[MP_ARRAY_SIZE(can_insts)]; + +// This must be placed in the first 64kB of RAM +STATIC COMPILER_SECTION(".canram") canio_can_state_t can_state[MP_ARRAY_SIZE(can_insts)]; + +__attribute__((optimize("O0"), noinline)) +void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *rx, mcu_pin_obj_t *tx, int baudrate, bool loopback, bool silent) +{ + mcu_pin_function_t *tx_function = mcu_find_pin_function(can_tx, tx, -1, MP_QSTR_tx); + int instance = tx_function->instance; + + mcu_pin_function_t *rx_function = mcu_find_pin_function(can_rx, rx, instance, MP_QSTR_rx); + + const uint32_t can_frequency = CONF_CAN0_FREQUENCY; + +#define DIV_ROUND(a, b) (((a) + (b)/2) / (b)) +#define DIV_ROUND_UP(a, b) (((a) + (b) - 1) / (b)) + + uint32_t clocks_per_bit = DIV_ROUND(can_frequency, baudrate); + uint32_t clocks_to_sample = DIV_ROUND(clocks_per_bit * 7, 8); + uint32_t clocks_after_sample = clocks_per_bit - clocks_to_sample; + uint32_t divisor = MAX(DIV_ROUND_UP(clocks_to_sample, 256), DIV_ROUND_UP(clocks_after_sample, 128)); + if (divisor > 32) { + mp_raise_OSError(MP_EINVAL); // baudrate cannot be attained (16kHz or something is lower bound, should never happen) + } + + gpio_set_pin_direction(tx_function->pin, GPIO_DIRECTION_OUT); + gpio_set_pin_function(tx_function->pin, tx_function->function); + common_hal_never_reset_pin(tx_function->obj); + + if (rx_function) { + gpio_set_pin_direction(rx_function->pin, GPIO_DIRECTION_IN); + gpio_set_pin_function(rx_function->pin, rx_function->function); + common_hal_never_reset_pin(rx_function->obj); + } + + self->tx_pin_number = common_hal_mcu_pin_number(tx); + self->rx_pin_number = rx ? common_hal_mcu_pin_number(rx) : COMMON_HAL_MCU_NO_PIN; + self->hw = can_insts[instance]; + self->state = &can_state[instance]; + + self->loopback = loopback; + + // Allow configuration change + hri_can_set_CCCR_INIT_bit(self->hw); + while (hri_can_get_CCCR_INIT_bit(self->hw) == 0) { + } + hri_can_set_CCCR_CCE_bit(self->hw); + + if(instance == 0) { + hri_mclk_set_AHBMASK_CAN0_bit(MCLK); + hri_gclk_write_PCHCTRL_reg(GCLK, CAN0_GCLK_ID, CONF_GCLK_CAN0_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos)); + + NVIC_DisableIRQ(CAN0_IRQn); + NVIC_ClearPendingIRQ(CAN0_IRQn); + NVIC_EnableIRQ(CAN0_IRQn); + hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); +#ifdef CAN1_GCLK_ID + } else if(instance == 1) { + hri_mclk_set_AHBMASK_CAN1_bit(MCLK); + hri_gclk_write_PCHCTRL_reg(GCLK, CAN1_GCLK_ID, CONF_GCLK_CAN1_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos)); + + NVIC_DisableIRQ(CAN1_IRQn); + NVIC_ClearPendingIRQ(CAN1_IRQn); + NVIC_EnableIRQ(CAN1_IRQn); + hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); +#endif + } + + self->hw->CCCR.bit.FDOE = 0; // neither FD nor Bit Rate Switch enabled + self->hw->CCCR.bit.BRSE = 0; + + hri_can_write_MRCFG_reg(self->hw, CAN_MRCFG_QOS(CAN_MRCFG_QOS_DISABLE_Val)); // QoS disabled (no sensitive operation) + + // A "nominal bit" is a header bit. With dual rate CAN FD, this is a slower rate + { + CAN_NBTP_Type btp = { + // 0 means "1 tq", but 2 is subtracted from NTSEG1 for the + // fixed 1 "SYNC" tq + .bit.NTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 2, + .bit.NTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1, + .bit.NBRP = divisor - 1, + .bit.NSJW = DIV_ROUND(clocks_after_sample, divisor * 4), + }; + hri_can_write_NBTP_reg(self->hw, btp.reg); + } + + // we don't do the high bit rate yet, so do we need to set this register? + // hri_can_write_DBTP_reg(self->hw, ???); + // A "data bit" is a data bit :) with dul rate CAN FD, this is a higher + // rate. However, CAN FD is not implemented in CircuitPython, and this is the same rate as + // the "nominal rate". + { + CAN_DBTP_Type btp = { + .bit.DTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 1, + .bit.DTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1, + .bit.DBRP = divisor - 1, + .bit.DSJW = DIV_ROUND(clocks_after_sample, divisor * 4), + }; + hri_can_write_DBTP_reg(self->hw, btp.reg); + } + + { + CAN_RXF0C_Type rxf = { + .bit.F0SA = (uint32_t)self->state->rx0_fifo, + .bit.F0S = COMMON_HAL_CANIO_RX_FIFO_SIZE, + }; + hri_can_write_RXF0C_reg(self->hw, rxf.reg); + } + + { + CAN_RXF1C_Type rxf = { + .bit.F1SA = (uint32_t)self->state->rx1_fifo, + .bit.F1S = COMMON_HAL_CANIO_RX_FIFO_SIZE, + }; + hri_can_write_RXF1C_reg(self->hw, rxf.reg); + } + + // All RX data has an 8 byte payload (max) + { + CAN_RXESC_Type esc = { + .bit.F0DS = CAN_RXESC_F0DS_DATA8_Val, + .bit.F1DS = CAN_RXESC_F1DS_DATA8_Val, + .bit.RBDS = CAN_RXESC_RBDS_DATA8_Val, + }; + hri_can_write_RXESC_reg(self->hw, esc.reg); + } + + // All TX data has an 8 byte payload (max) + { + CAN_TXESC_Type esc = { + .bit.TBDS = CAN_TXESC_TBDS_DATA8_Val, + }; + hri_can_write_TXESC_reg(self->hw, esc.reg); + } + + { + CAN_TXBC_Type bc = { + .bit.TBSA = (uint32_t)self->state->tx_fifo, + .bit.NDTB = COMMON_HAL_CANIO_TX_FIFO_SIZE, + .bit.TFQM = 0, // Messages are transmitted in the order submitted + }; + hri_can_write_TXBC_reg(self->hw, bc.reg); + } + + { + CAN_TXEFC_Type efc = { + .bit.EFS = 0, + }; + hri_can_write_TXEFC_reg(self->hw, efc.reg); + } + + { + CAN_GFC_Type gfc = { + .bit.RRFE = 1, + .bit.ANFS = CAN_GFC_ANFS_RXF0_Val, + .bit.ANFE = CAN_GFC_ANFE_REJECT_Val, + }; + hri_can_write_GFC_reg(self->hw, gfc.reg); + } + + { + CAN_SIDFC_Type dfc = { + .bit.LSS = COMMON_HAL_CANIO_RX_FILTER_SIZE, + .bit.FLSSA = (uint32_t)self->state->rx_filter + }; + hri_can_write_SIDFC_reg(self->hw, dfc.reg); + } + + { + CAN_XIDFC_Type dfc = { + .bit.LSE = 0, + }; + hri_can_write_XIDFC_reg(self->hw, dfc.reg); + } + + hri_can_write_XIDAM_reg(self->hw, CAN_XIDAM_RESETVALUE); + +// silent: The CAN is set in Bus Monitoring Mode by programming CCCR.MON to '1'. (tx pin unused) +// external loopback: The CAN can be set in External Loop Back Mode by programming TEST.LBCK and CCCR.MON to '1'. (rx pin unused) +// internal loopback (silent loopback): Internal Loop Back Mode is entered by programming bits TEST.LBCK and CCCR.MON to '1'. (tx, rx unused) + self->hw->CCCR.bit.MON = silent; + self->hw->CCCR.bit.TEST = loopback; + self->hw->TEST.bit.LBCK = loopback; + + if(instance == 0) { + NVIC_DisableIRQ(CAN0_IRQn); + NVIC_ClearPendingIRQ(CAN0_IRQn); + NVIC_EnableIRQ(CAN0_IRQn); +#ifdef CAN1_GCLK_ID + } else if(instance == 1) { + NVIC_DisableIRQ(CAN1_IRQn); + NVIC_ClearPendingIRQ(CAN1_IRQn); + NVIC_EnableIRQ(CAN1_IRQn); +#endif + } + + hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); + // Prevent configuration change + hri_can_clear_CCCR_CCE_bit(self->hw); + hri_can_clear_CCCR_INIT_bit(self->hw); + while (hri_can_get_CCCR_INIT_bit(self->hw)) { + } + + can_objs[instance] = self; +} + +int common_hal_canio_can_loopback_get(canio_can_obj_t *self) +{ + return self->loopback; +} + +int common_hal_canio_can_baudrate_get(canio_can_obj_t *self) +{ + return self->baudrate; +} + +int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self) +{ + return -1; +} + +int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self) +{ + return -1; +} + +int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self) +{ + return -1; +} + +int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self) +{ + return -1; +} + +int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self) +{ + return -1; +} + +int common_hal_canio_can_state_get(canio_can_obj_t *self) { + return -1; +} + +void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message) +{ + // We have just one dedicated TX buffer, use it! + canio_can_fifo_t *ent = &self->state->tx_fifo[0]; + ent->txb0.bit.ESI = false; + ent->txb0.bit.XTD = false; + ent->txb0.bit.RTR = message->rtr; + ent->txb0.bit.ID = message->id << 18; // short addresses are left-justified + + ent->txb1.bit.MM = 0; // "message marker" + ent->txb1.bit.EFC = 0; // don't store fifo events to event queue + ent->txb1.bit.FDF = 0; // Classic CAN format + ent->txb1.bit.BRS = 0; // No bit rate switching + ent->txb1.bit.DLC = message->size; + + if (!message->rtr) { + memcpy(ent->data, message->data, message->size); + } + + // TX buffer add request + self->hw->TXBAR.reg = 1; + + // wait 8ms (hard coded for now) for TX to occur + uint64_t deadline = port_get_raw_ticks(NULL) + 8; + while (port_get_raw_ticks(NULL) < deadline && !(self->hw->TXBTO.reg & 1)) { + RUN_BACKGROUND_TASKS; + } +} + +bool common_hal_canio_can_deinited(canio_can_obj_t *self) { + return !self->hw; +} + +void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self) { + if(common_hal_canio_can_deinited(self)) { + raise_deinited_error(); + } +} + +void common_hal_canio_can_deinit(canio_can_obj_t *self) +{ + if (self->hw) { + hri_can_set_CCCR_INIT_bit(self->hw); + self->hw = 0; + } + if (self->rx_pin_number != COMMON_HAL_MCU_NO_PIN) { + reset_pin_number(self->rx_pin_number); + self->rx_pin_number = COMMON_HAL_MCU_NO_PIN; + } + if (self->tx_pin_number != COMMON_HAL_MCU_NO_PIN) { + reset_pin_number(self->tx_pin_number); + self->tx_pin_number = COMMON_HAL_MCU_NO_PIN; + } +} + +void common_hal_canio_reset(void) { + memset(can_state, 0, sizeof(can_state)); + + for (size_t i=0; i +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "common-hal/_canio/__init__.h" +#include "common-hal/_canio/Listener.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/tick.h" + +void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout) { + if (nmatch) { + mp_raise_NotImplementedError(NULL); + } + + if (!can->fifo0_in_use) { + self->fifo_idx = 0; + self->fifo = can->state->rx0_fifo; + self->hw = (canio_rxfifo_reg_t*)&can->hw->RXF0C; + can->hw->IR.reg = CAN_IR_RF0N | CAN_IR_RF0W | CAN_IR_RF0F | CAN_IR_RF0L; + can->fifo0_in_use = true; + } else if (!can->fifo1_in_use) { + self->fifo_idx = 1; + self->fifo = can->state->rx1_fifo; + self->hw = (canio_rxfifo_reg_t*)&can->hw->RXF1C; + can->fifo1_in_use = true; + can->hw->IR.reg = CAN_IR_RF1N | CAN_IR_RF1W | CAN_IR_RF1F | CAN_IR_RF1L; + } else { + mp_raise_ValueError(translate("All RX FIFOs in use")); + } + + self->can = can; + common_hal_canio_listener_set_timeout(self, timeout); +} + +void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout) { + self->timeout_ms = (int)MICROPY_FLOAT_C_FUN(ceil)(timeout * 1000); +} + +float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self) { + return self->timeout_ms / 1000.0f; +} + +void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self) { + if(!self->can) { + raise_deinited_error(); + } + common_hal_canio_can_check_for_deinit(self->can); +} + +int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self) { + return self->hw->RXFS.bit.F0FL; +} + +bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_message_obj_t *message) { + if (!common_hal_canio_listener_in_waiting(self)) { + uint64_t deadline = supervisor_ticks_ms64() + self->timeout_ms; + do { + if(supervisor_ticks_ms64() > deadline) { + return false; + } + } while (!common_hal_canio_listener_in_waiting(self)); + } + int index = self->hw->RXFS.bit.F0GI; + canio_can_fifo_t *hw_message = &self->fifo[index]; + message->id = hw_message->rxb0.bit.ID >> 18; // short addresses are left-justified + message->rtr = hw_message->rxb0.bit.RTR; + message->size = hw_message->rxb1.bit.DLC; + if(!message->rtr) { + memcpy(message->data, hw_message->data, message->size); + } + self->hw->RXFA.bit.F0AI = index; + return true; +} + +void common_hal_canio_listener_deinit(canio_listener_obj_t *self) { + // free our FIFO, clear our matches, SOMETHING + if(self->can) { + if(self->fifo_idx == 0) { + self->can->fifo0_in_use = false; + } + if(self->fifo_idx == 1) { + self->can->fifo1_in_use = false; + } + } + self->fifo_idx = -1; + self->fifo = NULL; + self->can = NULL; + self->hw = NULL; +} diff --git a/ports/atmel-samd/common-hal/_canio/Listener.h b/ports/atmel-samd/common-hal/_canio/Listener.h new file mode 100644 index 000000000..cc6770e6e --- /dev/null +++ b/ports/atmel-samd/common-hal/_canio/Listener.h @@ -0,0 +1,53 @@ +/* + * 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 "common-hal/_canio/CAN.h" +#include "shared-module/_canio/Match.h" + +typedef struct { + __IO CAN_RXF0C_Type RXFC; /**< \brief (R/W 32) Rx FIFO n Configuration */ + __I CAN_RXF0S_Type RXFS; /**< \brief (R/ 32) Rx FIFO n Status */ + __IO CAN_RXF0A_Type RXFA; /**< \brief (R/W 32) Rx FIFO n Acknowledge */ +} canio_rxfifo_reg_t; + +typedef struct { + mp_obj_base_t base; + canio_can_obj_t *can; + canio_can_fifo_t *fifo; + canio_rxfifo_reg_t *hw; + uint32_t timeout_ms; + uint8_t fifo_idx; +} canio_listener_obj_t; + +void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout); +void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self); +void common_hal_canio_listener_deinit(canio_listener_obj_t *self); +bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_message_obj_t *message); +int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self); +float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self); +void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout); diff --git a/ports/atmel-samd/common-hal/_canio/__init__.c b/ports/atmel-samd/common-hal/_canio/__init__.c new file mode 100644 index 000000000..7932bfc2d --- /dev/null +++ b/ports/atmel-samd/common-hal/_canio/__init__.c @@ -0,0 +1,25 @@ +/* + * 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. + */ diff --git a/ports/atmel-samd/common-hal/_canio/__init__.h b/ports/atmel-samd/common-hal/_canio/__init__.h new file mode 100644 index 000000000..429369e18 --- /dev/null +++ b/ports/atmel-samd/common-hal/_canio/__init__.h @@ -0,0 +1,62 @@ +/* + * 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 "hal/utils/include/utils.h" +#include "component/can.h" + +#define COMMON_HAL_CANIO_MAX_MESSAGE_LENGTH (8) +#define COMMON_HAL_CANIO_RX_FIFO_SIZE (3) +#define COMMON_HAL_CANIO_RX_FILTER_SIZE (4) +#define COMMON_HAL_CANIO_TX_FIFO_SIZE (1) + +typedef struct canio_listener canio_listener_t; +typedef struct canio_can canio_can_t; + +typedef struct { + union { + CAN_RXBE_0_Type rxb0; + CAN_TXBE_0_Type txb0; + CAN_RXF0E_0_Type rxf0; + }; + union { + CAN_RXBE_1_Type rxb1; + CAN_TXBE_1_Type txb1; + CAN_RXF0E_1_Type rxf1; + }; + COMPILER_ALIGNED(4) + uint8_t data[COMMON_HAL_CANIO_MAX_MESSAGE_LENGTH]; +} canio_can_fifo_t; + +typedef uint32_t canio_can_filter_t; + +typedef struct { + canio_can_fifo_t tx_fifo[COMMON_HAL_CANIO_TX_FIFO_SIZE]; + canio_can_fifo_t rx0_fifo[COMMON_HAL_CANIO_RX_FIFO_SIZE]; + canio_can_fifo_t rx1_fifo[COMMON_HAL_CANIO_RX_FIFO_SIZE]; + canio_can_filter_t rx_filter[COMMON_HAL_CANIO_RX_FILTER_SIZE]; +} canio_can_state_t; diff --git a/ports/atmel-samd/tools/mkcandata.py b/ports/atmel-samd/tools/mkcandata.py new file mode 100755 index 000000000..9668d2208 --- /dev/null +++ b/ports/atmel-samd/tools/mkcandata.py @@ -0,0 +1,31 @@ +#!/usr/bin/python3 + +def defines(name, suffix): + print(f'mcu_pin_function_t {name} [] = {{') + for instance in (0, 1): + for function in 'HI': + for port in 'ABCD': + for idx in range(32): + pin = f'P{port}{idx:02d}' + pinmux = f'PINMUX_{pin}{function}_CAN{instance}_{suffix}' + print(f'''\ +#if defined({pinmux}) && ! defined(IGNORE_PIN_{pin}) + {{&pin_{pin}, {instance}, PIN_{pin}, {pinmux} & 0xffff}}, +#endif''') + print(f'{{NULL, 0, 0}}') + print(f'}};') + print() + +print('''\ +#include +#include "py/obj.h" +#include "sam.h" +#include "samd/pins.h" +#include "mpconfigport.h" +#include "atmel_start_pins.h" +#include "hal/include/hal_gpio.h" +#include "common-hal/microcontroller/Pin.h" +''') + +defines('can_rx', 'RX') +defines('can_tx', 'TX') diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 6e98af868..2614dc011 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -142,6 +142,9 @@ endif ifeq ($(CIRCUITPY_CAMERA),1) SRC_PATTERNS += camera/% endif +ifeq ($(CIRCUITPY_CANIO),1) +SRC_PATTERNS += _canio/% +endif ifeq ($(CIRCUITPY_COUNTIO),1) SRC_PATTERNS += countio/% endif @@ -315,6 +318,9 @@ SRC_COMMON_HAL_ALL = \ busio/__init__.c \ camera/__init__.c \ camera/Camera.c \ + _canio/CAN.c \ + _canio/Listener.c \ + _canio/__init__.c \ countio/Counter.c \ countio/__init__.c \ digitalio/DigitalInOut.c \ @@ -384,6 +390,7 @@ $(filter $(SRC_PATTERNS), \ _bleio/Address.c \ _bleio/Attribute.c \ _bleio/ScanEntry.c \ + _canio/Match.c \ _eve/__init__.c \ camera/ImageFormat.c \ digitalio/Direction.c \ @@ -402,6 +409,8 @@ SRC_SHARED_MODULE_ALL = \ _bleio/Attribute.c \ _bleio/ScanEntry.c \ _bleio/ScanResults.c \ + _canio/Match.c \ + _canio/Message.c \ _eve/__init__.c \ _pixelbuf/PixelBuf.c \ _pixelbuf/__init__.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 4272de2ec..d1b12f354 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -336,6 +336,13 @@ extern const struct _mp_obj_module_t camera_module; #define CAMERA_MODULE #endif +#if CIRCUITPY_CANIO +extern const struct _mp_obj_module_t canio_module; +#define CANIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__canio), (mp_obj_t)&canio_module }, +#else +#define CANIO_MODULE +#endif + #if CIRCUITPY_COUNTIO extern const struct _mp_obj_module_t countio_module; #define COUNTIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_countio), (mp_obj_t)&countio_module }, @@ -766,6 +773,7 @@ extern const struct _mp_obj_module_t wifi_module; BOARD_MODULE \ BUSIO_MODULE \ CAMERA_MODULE \ + CANIO_MODULE \ COUNTIO_MODULE \ DIGITALIO_MODULE \ DISPLAYIO_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 54bdefc6d..9b9bd83b4 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -93,6 +93,9 @@ CFLAGS += -DCIRCUITPY_BUSIO=$(CIRCUITPY_BUSIO) CIRCUITPY_CAMERA ?= 0 CFLAGS += -DCIRCUITPY_CAMERA=$(CIRCUITPY_CAMERA) +CIRCUITPY_CANIO ?= 0 +CFLAGS += -DCIRCUITPY_CANIO=$(CIRCUITPY_CANIO) + CIRCUITPY_DIGITALIO ?= 1 CFLAGS += -DCIRCUITPY_DIGITALIO=$(CIRCUITPY_DIGITALIO) diff --git a/shared-bindings/_canio/CAN.c b/shared-bindings/_canio/CAN.c new file mode 100644 index 000000000..4c7ae3650 --- /dev/null +++ b/shared-bindings/_canio/CAN.c @@ -0,0 +1,338 @@ +/* + * 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 "common-hal/_canio/CAN.h" +#include "common-hal/_canio/Listener.h" +#include "shared-bindings/_canio/CAN.h" +#include "shared-bindings/_canio/Listener.h" +#include "shared-bindings/_canio/Match.h" +#include "shared-bindings/_canio/Message.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "py/objproperty.h" +#include "py/runtime.h" + +//| +//| class CAN: +//| """CAN bus protocol""" +//| +//| def __init__(self, +//| rx: microcontroller.Pin, +//| tx: Optional[microcontroller.Pin]=None, +//| *, +//| baudrate: int = 250000, +//| loopback: bool = False, +//| ): +//| """A common shared-bus protocol. The rx and tx pins are generally +//| connected to a transceiver which controls the H and L pins on a shared +//| bus. +//| +//| :param ~microcontrller.Pin rx: the pin to receive with. +//| :param ~microcontrller.Pin tx: the pin to transmit with, or None if the peripheral should operate in "silent" mode. +//| :param int baudrate: The bit rate of the bus in Hz. All devices on the bus must agree on this value. +//| :param bool loopback: True if the peripheral will be operated in loopback mode. +//| """ +//| ... +//| +//## auto_restart: bool = False, # Whether to restart communications after entering bus-off state +//## sample_point: float = .875, # When to sample within bit time (0.0-1.0) +STATIC mp_obj_t canio_can_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_rx, ARG_tx, ARG_baudrate, ARG_loopback, ARG_silent, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_rx, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = 0} }, + { MP_QSTR_tx, MP_ARG_OBJ, {.u_obj = 0} }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 250000} }, + { MP_QSTR_loopback, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_silent, MP_ARG_BOOL, {.u_bool = false} }, + }; + 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); + +mp_printf(&mp_plat_print, "ARG_rx=%d args[ARG_rx].u_obj=%p\n", ARG_rx, args[ARG_rx].u_obj); +mp_printf(&mp_plat_print, "ARG_tx=%d args[ARG_tx].u_obj=%p\n", ARG_tx, args[ARG_tx].u_obj); + + mcu_pin_obj_t *rx_pin = validate_obj_is_free_pin(args[ARG_rx].u_obj); +mp_printf(&mp_plat_print, "rx_pin=%p\n", rx_pin); + mcu_pin_obj_t *tx_pin = validate_obj_is_free_pin_or_none(args[ARG_tx].u_obj); +mp_printf(&mp_plat_print, "tx_pin=%p\n", tx_pin); + + canio_can_obj_t *self = m_new_obj(canio_can_obj_t); + self->base.type = &canio_can_type; + common_hal_canio_can_construct(self, rx_pin, tx_pin, args[ARG_baudrate].u_int, args[ARG_loopback].u_bool, args[ARG_silent].u_bool); + + return MP_OBJ_FROM_PTR(self); +} + + +//| baudrate: int +//| """The baud rate(read-only)""" +//| +STATIC mp_obj_t canio_can_baudrate_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_baudrate_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_baudrate_get_obj, canio_can_baudrate_get); + +STATIC const mp_obj_property_t canio_can_baudrate_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_baudrate_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| state: State +//| """The status of the hardware (read-only)""" +//| +STATIC mp_obj_t canio_can_state_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_state_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_state_get_obj, canio_can_state_get); + +STATIC const mp_obj_property_t canio_can_state_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_state_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| transmit_error_count: int +//| """The number of transmit errors (read-only). Increased for a detected transmission error, decreased for successful transmission. Limited to the range from 0 to 255 inclusive. Also called TEC.""" +//| +STATIC mp_obj_t canio_can_transmit_error_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_transmit_error_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_transmit_error_count_get_obj, canio_can_transmit_error_count_get); + +STATIC const mp_obj_property_t canio_can_transmit_error_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_transmit_error_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| receive_error_count: int +//| """The number of receive errors (read-only). Increased for a detected reception error, decreased for successful reception. Limited to the range from 0 to 255 inclusive. Also called REC.""" +//| +STATIC mp_obj_t canio_can_receive_error_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_receive_error_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_receive_error_count_get_obj, canio_can_receive_error_count_get); + +STATIC const mp_obj_property_t canio_can_receive_error_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_receive_error_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| error_warning_state_count: int +//| """The number of times the controller enterted the Error Warning state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" +//| +STATIC mp_obj_t canio_can_error_warning_state_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_error_warning_state_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_error_warning_state_count_get_obj, canio_can_error_warning_state_count_get); + +STATIC const mp_obj_property_t canio_can_error_warning_state_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_error_warning_state_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| error_passive_state_count: int +//| """The number of times the controller enterted the Error Passive state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" +//| +STATIC mp_obj_t canio_can_error_passive_state_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_error_passive_state_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_error_passive_state_count_get_obj, canio_can_error_passive_state_count_get); + +STATIC const mp_obj_property_t canio_can_error_passive_state_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_error_passive_state_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| bus_off_state_count: int +//| """The number of times the controller enterted the Bus Off state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" +//| +STATIC mp_obj_t canio_can_bus_off_state_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_bus_off_state_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_bus_off_state_count_get_obj, canio_can_bus_off_state_count_get); + +STATIC const mp_obj_property_t canio_can_bus_off_state_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_bus_off_state_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +#if 0 +//| # pending_tx_count: int +//| # """The number of messages waiting to be transmitted. (read-only)""" +#endif + +//| def listen(filters: Optional[Sequence[Filter]]=None, *, timeout: float=10) -> Listener: +//| """Start receiving messages that match any one of the filters. +//| Creating a listener is an expensive operation and can interfere with reception of messages by other listeners. +//| There is an implementation-defined maximum number of listeners and limit to the complexity of the filters. +//| If the hardware cannot support all the requested filters, a ValueError is raised. Note that generally there are some number of hardware filters shared among all fifos. +//| A message can be received by at most one Listener. +//| An empty filter list causes all messages to be accepted. +//| Timeout dictates how long readinto, read and next() will block. +//| Readinto will return false(), read will return None, and next() will raise StopIteration.""" +//| ... +//| +STATIC mp_obj_t canio_can_listen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + common_hal_canio_can_check_for_deinit(self); + + enum { ARG_match, ARG_timeout, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_match, MP_ARG_OBJ, {.u_obj = 0} }, + { MP_QSTR_timeout, MP_ARG_OBJ, {.u_obj = 0} }, + }; + 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); + + size_t nmatch = 0; + mp_obj_t *match_objects = NULL; + + if (args[ARG_match].u_obj) { + mp_obj_get_array(args[ARG_match].u_obj, &nmatch, &match_objects); + } + + canio_match_obj_t *matches[nmatch]; + for (size_t i=0; iname); + } + matches[i] = MP_OBJ_TO_PTR(match_objects[i]); + } + + float timeout = args[ARG_timeout].u_obj ? mp_obj_get_float(args[ARG_timeout].u_obj) : 10.0f; + canio_listener_obj_t *listener = m_new_obj(canio_listener_obj_t); + listener->base.type = &canio_listener_type; + common_hal_canio_listener_construct(listener, self, nmatch, matches, timeout); + return listener; +} +MP_DEFINE_CONST_FUN_OBJ_KW(canio_can_listen_obj, 1, canio_can_listen); + +//| def send(message: Message) -> None: +//| """Send a message on the bus with the given data and id. +//| If the message could not be sent due to a full fifo or a bus error condition, RuntimeError is raised. +//| """ +//| ... +//| +STATIC mp_obj_t canio_can_send(mp_obj_t self_in, mp_obj_t message_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + mp_obj_type_t *message_type = mp_obj_get_type(message_in); + if (message_type != &canio_message_type) { + mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Message, message_type->name); + } + + canio_message_obj_t *message = message_in; + common_hal_canio_can_send(self, message); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_can_send_obj, canio_can_send); + +//| def deinit(self) -> None: +//| """Deinitialize this object, freeing its hardware resources""" +//| ... +//| +STATIC mp_obj_t canio_can_deinit(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_deinit_obj, canio_can_deinit); + +//| def __enter__(self) -> CAN: +//| """Returns self, to allow the object to be used in a `with` statement for resource control""" +//| ... +//| +STATIC mp_obj_t canio_can_enter(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_enter_obj, canio_can_enter); + +//| def __exit__(self, unused1, unused2, unused3) -> None: +//| """Calls deinit()""" +//| ... +STATIC mp_obj_t canio_can_exit(size_t num_args, const mp_obj_t args[]) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(args[0]); + common_hal_canio_can_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_can_exit_obj, 4, 4, canio_can_exit); + +STATIC const mp_rom_map_elem_t canio_can_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_can_enter_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_can_exit_obj) }, + { MP_ROM_QSTR(MP_QSTR_bus_off_state_count), MP_ROM_PTR(&canio_can_bus_off_state_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_can_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_error_passive_state_count), MP_ROM_PTR(&canio_can_error_passive_state_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_error_warning_state_count), MP_ROM_PTR(&canio_can_error_warning_state_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&canio_can_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_receive_error_count), MP_ROM_PTR(&canio_can_receive_error_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&canio_can_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&canio_can_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&canio_can_baudrate_obj) }, + { MP_ROM_QSTR(MP_QSTR_transmit_error_count), MP_ROM_PTR(&canio_can_transmit_error_count_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_can_locals_dict, canio_can_locals_dict_table); + +const mp_obj_type_t canio_can_type = { + { &mp_type_type }, + .name = MP_QSTR_CAN, + .make_new = canio_can_make_new, + .locals_dict = (mp_obj_t)&canio_can_locals_dict, +}; diff --git a/shared-bindings/_canio/CAN.h b/shared-bindings/_canio/CAN.h new file mode 100644 index 000000000..81040cf23 --- /dev/null +++ b/shared-bindings/_canio/CAN.h @@ -0,0 +1,31 @@ +/* + * 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" + +extern const mp_obj_type_t canio_can_type; diff --git a/shared-bindings/_canio/Listener.c b/shared-bindings/_canio/Listener.c new file mode 100644 index 000000000..7f83c735f --- /dev/null +++ b/shared-bindings/_canio/Listener.c @@ -0,0 +1,197 @@ +/* + * 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 "shared-bindings/_canio/Listener.h" +#include "shared-bindings/_canio/Message.h" +#include "common-hal/_canio/Listener.h" + +#include "py/runtime.h" +#include "py/objproperty.h" + +//| class Listener: +//| """Listens for CAN message +//| +//| _canio.Listener is not constructed directly, but instead by calling the +//| Listen method of a _canio.CAN object.""" +//| + +//| def read(self) -> Optional[Message]: +//| """Returns a message, after waiting up to self.timeout seconds +//| +//| If no message is received in time, None is returned. Otherwise, +//| a Message is returned.""" +//| ... +//| +STATIC mp_obj_t canio_listener_read(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + + canio_message_obj_t *message = m_new_obj(canio_message_obj_t); + self->base.type = &canio_message_type; + + if (common_hal_canio_listener_readinto(self, message)) { + return message; + } else { + m_free(message); // message did not escape into vm + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_read_obj, canio_listener_read); + +//| def readinto(self, message: Message) -> bool: +//| """Returns a message, after waiting up to self.timeout seconds +//| +//| Returns True (and modifies message) if a message was received, +//| False otherwise.""" +//| ... +//| +STATIC mp_obj_t canio_listener_readinto(mp_obj_t self_in, mp_obj_t message) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_type_t *type = mp_obj_get_type(message); + if (type != &canio_message_type) { + mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Message, type->name); + } + common_hal_canio_listener_check_for_deinit(self); + return mp_obj_new_bool(common_hal_canio_listener_readinto(self, message)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(canio_listener_readinto_obj, canio_listener_readinto); + +//| def in_waiting(self) -> int: +//| """Returns the number of messages waiting""" +//| ... +//| +STATIC mp_obj_t canio_listener_in_waiting(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_listener_in_waiting(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_in_waiting_obj, canio_listener_in_waiting); + +//| def __iter__(self): +//| """Returns self, unless the object is deinitialized""" +//| ... +//| +STATIC mp_obj_t canio_listener_iter(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return self; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_iter_obj, canio_listener_iter); + +//| def __next__(self): +//| """Returns the next waiting message, if one is available +//| +//| If the object is deinitialized, raises ValueError. +//| +//| If no message is waiting raises StopIteration""" +//| ... +//| +STATIC mp_obj_t canio_listener_next(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + if(common_hal_canio_listener_in_waiting(self)) { + return canio_listener_read(self_in); + } + return self; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_next_obj, canio_listener_next); + +//| def deinit(self) -> None: +//| """Deinitialize this object, freeing its hardware resources""" +//| ... +//| +STATIC mp_obj_t canio_listener_deinit(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_deinit_obj, canio_listener_deinit); + +//| def __enter__(self) -> CAN: +//| """Returns self, to allow the object to be used in a `with` statement for resource control""" +//| ... +//| +STATIC mp_obj_t canio_listener_enter(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_enter_obj, canio_listener_enter); + +//| def __exit__(self, unused1, unused2, unused3) -> None: +//| """Calls deinit()""" +//| ... +STATIC mp_obj_t canio_listener_exit(size_t num_args, const mp_obj_t args[]) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(args[0]); + common_hal_canio_listener_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_listener_exit_obj, 4, 4, canio_listener_exit); + + +//| timeout : float +STATIC mp_obj_t canio_listener_timeout_get(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return mp_obj_new_float(common_hal_canio_listener_get_timeout(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_timeout_get_obj, canio_listener_timeout_get); + +STATIC mp_obj_t canio_listener_timeout_set(mp_obj_t self_in, mp_obj_t timeout_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + common_hal_canio_listener_set_timeout(self, mp_obj_get_float(timeout_in)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(canio_listener_timeout_set_obj, canio_listener_timeout_set); + +STATIC const mp_obj_property_t canio_listener_timeout_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_listener_timeout_get_obj, + (mp_obj_t)&canio_listener_timeout_set_obj, + (mp_obj_t)mp_const_none}, +}; + + + +STATIC const mp_rom_map_elem_t canio_listener_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_listener_enter_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_listener_exit_obj) }, + { MP_ROM_QSTR(MP_QSTR___iter__), MP_ROM_PTR(&canio_listener_iter_obj) }, + { MP_ROM_QSTR(MP_QSTR___next__), MP_ROM_PTR(&canio_listener_next_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_listener_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&canio_listener_in_waiting_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&canio_listener_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&canio_listener_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&canio_listener_timeout_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_listener_locals_dict, canio_listener_locals_dict_table); + +const mp_obj_type_t canio_listener_type = { + { &mp_type_type }, + .name = MP_QSTR_Listener, + .locals_dict = (mp_obj_dict_t*)&canio_listener_locals_dict, +}; diff --git a/shared-bindings/_canio/Listener.h b/shared-bindings/_canio/Listener.h new file mode 100644 index 000000000..eaa3490df --- /dev/null +++ b/shared-bindings/_canio/Listener.h @@ -0,0 +1,31 @@ +/* + * 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" + +extern const mp_obj_type_t canio_listener_type; diff --git a/shared-bindings/_canio/Match.c b/shared-bindings/_canio/Match.c new file mode 100644 index 000000000..6c32aa539 --- /dev/null +++ b/shared-bindings/_canio/Match.c @@ -0,0 +1,140 @@ +/* + * 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 "shared-bindings/_canio/Match.h" +#include "shared-module/_canio/Match.h" + +#include "py/objproperty.h" +#include "py/runtime.h" + +//| class Match: +//| """Describe CAN bus messages to match""" +//| +//| +//| def __init__(self, address: int, *, mask: int = 0, extended: bool = False): +//| """Construct a Match with the given properties. +//| +//| If mask is nonzero, then the filter is for any sender which matches all +//| the nonzero bits in mask. Otherwise, it matches exactly the given address. +//| If extended is true then only extended addresses are matched, otherwise +//| only standard addresses are matched.""" +//| + +STATIC mp_obj_t canio_match_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, ARG_mask, ARG_extended, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} }, + { MP_QSTR_mask, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, + }; + 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); + + int address_bits = args[ARG_extended].u_bool ? 0x1fffffff : 0x7ff; + int address = args[ARG_address].u_int; + int mask = args[ARG_mask].u_int; + + if(address & ~address_bits) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_address); + } + + if(mask & ~address_bits) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_mask); + } + + canio_match_obj_t *self = m_new_obj(canio_match_obj_t); + self->base.type = &canio_match_type; + common_hal_canio_match_construct(self, args[ARG_address].u_int, args[ARG_mask].u_int, args[ARG_extended].u_bool); + return self; +} + +//| address: int +//| """The address to match""" +//| + +STATIC mp_obj_t canio_match_address_get(mp_obj_t self_in) { + canio_match_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_address_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_match_address_get_obj, canio_match_address_get); + +const mp_obj_property_t canio_match_address_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_match_address_get_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| +//| mask: int +//| """The optional mask of addresses to match""" +//| + +STATIC mp_obj_t canio_match_mask_get(mp_obj_t self_in) { + canio_match_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_mask_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_match_mask_get_obj, canio_match_mask_get); + +const mp_obj_property_t canio_match_mask_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_match_mask_get_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| extended: bool +//| """True to match extended addresses, False to match standard addresses""" +//| + +STATIC mp_obj_t canio_match_extended_get(mp_obj_t self_in) { + canio_match_obj_t *self = self_in; + return mp_obj_new_bool(common_hal_canio_match_extended_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_match_extended_get_obj, canio_match_extended_get); + +const mp_obj_property_t canio_match_extended_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_match_extended_get_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t canio_match_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&canio_match_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_mask), MP_ROM_PTR(&canio_match_mask_obj) }, + { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_match_extended_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_match_locals_dict, canio_match_locals_dict_table); + +const mp_obj_type_t canio_match_type = { + { &mp_type_type }, + .name = MP_QSTR_Match, + .make_new = canio_match_make_new, + .locals_dict = (mp_obj_dict_t*)&canio_match_locals_dict, +}; diff --git a/shared-bindings/_canio/Match.h b/shared-bindings/_canio/Match.h new file mode 100644 index 000000000..adf98eb86 --- /dev/null +++ b/shared-bindings/_canio/Match.h @@ -0,0 +1,33 @@ +/* + * 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" + +extern const mp_obj_type_t canio_match_type; + +// Nothing now. diff --git a/shared-bindings/_canio/Message.c b/shared-bindings/_canio/Message.c new file mode 100644 index 000000000..a8e588354 --- /dev/null +++ b/shared-bindings/_canio/Message.c @@ -0,0 +1,213 @@ +/* + * 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 "shared-bindings/_canio/Message.h" +#include "shared-module/_canio/Message.h" + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +//| class Message: +//| def __init__(self, id: int=0, data: Optional[bytes] = None, *, size: Optional[int] = None, rtr: bool = False): +//| """Construct a Message to send on a CAN bus +//| +//| :param int id: The numeric ID of the message +//| :param bytes data: The content of the message +//| :param int size: The amount of data requested, for an rtr +//| :param bool rtr: True if the message represents an rtr (Remote Transmission Request) +//| +//| In CAN, messages can have a size from 0 to 8 bytes. +//| +//| For a non-rtr message, specify `data`. For an rtr-message, specify either `data` (a dummy buffer of the requested size) or `size`. +//| """ +//| ... +//| +STATIC mp_obj_t canio_message_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_id, ARG_data, ARG_size, ARG_rtr, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_obj = 0} }, + { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = 0} }, + { MP_QSTR_size, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_rtr, MP_ARG_BOOL, {.u_bool = false} }, + }; + 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); + + bool rtr = args[ARG_rtr].u_bool; + size_t size = (size_t)args[ARG_size].u_int; + bool specified_size = (size != (size_t)-1); + bool specified_data = (args[ARG_data].u_obj != NULL); + + if(specified_size && specified_data) { + mp_raise_TypeError(translate("specify size or data, but not both")); + } + + mp_buffer_info_t data; + if (specified_data) { + mp_get_buffer_raise(args[ARG_data].u_obj, &data, MP_BUFFER_READ); + } else if (specified_size) { + data.buf = 0; + data.len = size; + } else { + data.buf = 0; + data.len = 0; + } + + if(data.len > 8) { + mp_raise_ValueError(translate("Messages limited to 8 bytes")); + } + + canio_message_obj_t *self = m_new_obj(canio_message_obj_t); + self->base.type = &canio_message_type; + common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, rtr); + return self; +} + +//| id: int +//| """The numeric ID of the message""" +//| +STATIC mp_obj_t canio_message_id_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_id_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_id_get_obj, canio_message_id_get); + +STATIC mp_obj_t canio_message_id_set(const mp_obj_t self_in, const mp_obj_t id) { + canio_message_obj_t *self = self_in; + common_hal_canio_message_id_set(self, mp_obj_get_int(id)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_id_set_obj, canio_message_id_set); + +STATIC const mp_obj_property_t canio_message_id_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_id_get_obj, + (mp_obj_t)&canio_message_id_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| data: bytes +//| """The content of the message, or dummy content in the case of an rtr. +//| +//| Assigning to data sets the bytes to zero""" +//| +STATIC mp_obj_t canio_message_data_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return mp_obj_new_bytes((const byte*)common_hal_canio_message_data_get(self), common_hal_canio_message_size_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_data_get_obj, canio_message_data_get); + +STATIC mp_obj_t canio_message_data_set(const mp_obj_t self_in, const mp_obj_t data_in) { + canio_message_obj_t *self = self_in; + mp_buffer_info_t data; + mp_get_buffer_raise(data_in, &data, MP_BUFFER_READ); + if(data.len > 8) { + mp_raise_ValueError(translate("Messages limited to 8 bytes")); + } + common_hal_canio_message_data_set(self, data.buf, data.len); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_data_set_obj, canio_message_data_set); + + +STATIC const mp_obj_property_t canio_message_data_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_data_get_obj, + (mp_obj_t)&canio_message_data_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +//| size: int +//| """The length of the message, or the length of the requested data in the case of an rtr""" +//| +STATIC mp_obj_t canio_message_size_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_size_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_size_get_obj, canio_message_size_get); + +STATIC mp_obj_t canio_message_size_set(const mp_obj_t self_in, const mp_obj_t size_in) { + canio_message_obj_t *self = self_in; + int size = mp_obj_get_int(size_in); + if(size > 8) { + mp_raise_ValueError(translate("Messages limited to 8 bytes")); + } + common_hal_canio_message_size_set(self, size); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_size_set_obj, canio_message_size_set); + + +STATIC const mp_obj_property_t canio_message_size_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_size_get_obj, + (mp_obj_t)&canio_message_size_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| rtr: bool +//| """True if the message represents a remote transmission request (RTR)""" +//| +STATIC mp_obj_t canio_message_rtr_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return mp_obj_new_bool(common_hal_canio_message_rtr_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_rtr_get_obj, canio_message_rtr_get); + +STATIC mp_obj_t canio_message_rtr_set(const mp_obj_t self_in, const mp_obj_t rtr) { + canio_message_obj_t *self = self_in; + common_hal_canio_message_size_set(self, mp_obj_is_true(rtr)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_rtr_set_obj, canio_message_rtr_set); + + +STATIC const mp_obj_property_t canio_message_rtr_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_rtr_get_obj, + (mp_obj_t)&canio_message_rtr_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +STATIC const mp_rom_map_elem_t canio_message_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&canio_message_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&canio_message_size_obj) }, + { MP_ROM_QSTR(MP_QSTR_rtr), MP_ROM_PTR(&canio_message_rtr_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_message_locals_dict, canio_message_locals_dict_table); + +const mp_obj_type_t canio_message_type = { + { &mp_type_type }, + .name = MP_QSTR_Message, + .make_new = canio_message_make_new, + .locals_dict = (mp_obj_t)&canio_message_locals_dict, +}; diff --git a/shared-bindings/_canio/Message.h b/shared-bindings/_canio/Message.h new file mode 100644 index 000000000..32d6801bc --- /dev/null +++ b/shared-bindings/_canio/Message.h @@ -0,0 +1,31 @@ +/* + * 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" + +extern const mp_obj_type_t canio_message_type; diff --git a/shared-bindings/_canio/__init__.c b/shared-bindings/_canio/__init__.c new file mode 100644 index 000000000..4da008ff2 --- /dev/null +++ b/shared-bindings/_canio/__init__.c @@ -0,0 +1,73 @@ +/* + * 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. + */ + +//| """CAN bus access +//| +//| The `_canio` module contains low level classes to support the CAN bus +//| protocol. +//| +//| 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 _canio +//| from board import * +//| +//| can = _canio.BUS(board.CANRX, board.CANTX) +//| can.write(408, b"adafruit") +//| can.deinit() +//| +//| This example will write the data 'adafruit' onto the CAN bus to any +//| device listening for message id 408.""" +//| + +#include "py/obj.h" + +#include "shared-bindings/_canio/__init__.h" +#include "shared-bindings/_canio/CAN.h" +#include "shared-bindings/_canio/Match.h" +#include "shared-bindings/_canio/Message.h" + +STATIC const mp_rom_map_elem_t canio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__canio) }, + { MP_ROM_QSTR(MP_QSTR_CAN), MP_ROM_PTR(&canio_can_type) }, + { MP_ROM_QSTR(MP_QSTR_Match), MP_ROM_PTR(&canio_match_type) }, + { MP_ROM_QSTR(MP_QSTR_Message), MP_ROM_PTR(&canio_message_type) }, +#if 0 + { MP_ROM_QSTR(MP_QSTR_Listener), MP_ROM_PTR(&canio_listener_type) }, +#endif +}; + + +STATIC MP_DEFINE_CONST_DICT(canio_module_globals, canio_module_globals_table); + +const mp_obj_module_t canio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&canio_module_globals, +}; diff --git a/shared-bindings/_canio/__init__.h b/shared-bindings/_canio/__init__.h new file mode 100644 index 000000000..45e76369c --- /dev/null +++ b/shared-bindings/_canio/__init__.h @@ -0,0 +1,29 @@ +/* + * 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 + +// Nothing now. diff --git a/shared-module/_canio/Match.c b/shared-module/_canio/Match.c new file mode 100644 index 000000000..2b696addb --- /dev/null +++ b/shared-module/_canio/Match.c @@ -0,0 +1,43 @@ +/* + * 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 "shared-module/_canio/Match.h" + +void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended) { + self->address = address; + self->mask = mask; + self->extended = extended; +} + +int common_hal_canio_match_address_get(const canio_match_obj_t *self) { + return self->address; +} +int common_hal_canio_match_mask_get(const canio_match_obj_t *self) { + return self->mask; +} +bool common_hal_canio_match_extended_get(const canio_match_obj_t *self) { + return self->extended; +} diff --git a/shared-module/_canio/Match.h b/shared-module/_canio/Match.h new file mode 100644 index 000000000..099df976d --- /dev/null +++ b/shared-module/_canio/Match.h @@ -0,0 +1,41 @@ +/* + * 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" + +typedef struct { + mp_obj_base_t base; + int address; + int mask; + bool extended; +} canio_match_obj_t; + +void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended); +int common_hal_canio_match_address_get(const canio_match_obj_t *self); +int common_hal_canio_match_mask_get(const canio_match_obj_t *self); +bool common_hal_canio_match_extended_get(const canio_match_obj_t *self); diff --git a/shared-module/_canio/Message.c b/shared-module/_canio/Message.c new file mode 100644 index 000000000..df6a40a0a --- /dev/null +++ b/shared-module/_canio/Message.c @@ -0,0 +1,85 @@ +/* + * 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 "shared-module/_canio/Message.h" + +#include + +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr) +{ + self->id = id; + self->size = size; + self->rtr = rtr; + if (data) { + memcpy(self->data, data, size); + } else { + memset(self->data, 0, size); + } +} + +int common_hal_canio_message_id_get(const canio_message_obj_t *self) +{ + return self->id; +} + +void common_hal_canio_message_id_set(canio_message_obj_t *self, int id) +{ + self->id = id; +} + + +const void *common_hal_canio_message_data_get(const canio_message_obj_t *self) +{ + return self->data; +} + +const void common_hal_canio_message_data_set(canio_message_obj_t *self, const void *data, size_t size) +{ + memcpy(self->data, data, size); +} + + +size_t common_hal_canio_message_size_get(const canio_message_obj_t *self) +{ + return self->size; +} + +void common_hal_canio_message_size_set(canio_message_obj_t *self, size_t size) +{ + memset(self->data, 0, size); + self->size = size; +} + + +bool common_hal_canio_message_rtr_get(const canio_message_obj_t *self) +{ + return self->rtr; +} + +void common_hal_canio_message_rtr_set(canio_message_obj_t *self, bool rtr) +{ + self->rtr = rtr; +} diff --git a/shared-module/_canio/Message.h b/shared-module/_canio/Message.h new file mode 100644 index 000000000..e846f1095 --- /dev/null +++ b/shared-module/_canio/Message.h @@ -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. + */ + +#pragma once + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + int id; + size_t size; + uint8_t data[8]; + bool rtr; +} canio_message_obj_t; + +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr); +bool common_hal_canio_message_rtr_get(const canio_message_obj_t *self); +int common_hal_canio_message_id_get(const canio_message_obj_t *self); +const void *common_hal_canio_message_data_get(const canio_message_obj_t *self); +size_t common_hal_canio_message_size_get(const canio_message_obj_t *self); +void common_hal_canio_message_rtr_set(canio_message_obj_t *self, bool rtr); +void common_hal_canio_message_id_set(canio_message_obj_t *self, int id); +void common_hal_canio_message_data_set(canio_message_obj_t *self, const void *data, size_t size); +void common_hal_canio_message_size_set(canio_message_obj_t *self, size_t size); -- cgit v1.2.3 From 65ca1c7bbc84cd88d3aae69d89d2ff2c287ef884 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 16 Sep 2020 11:57:24 -0500 Subject: _canio: Message: Setting data should set the size to match --- shared-module/_canio/Message.c | 1 + 1 file changed, 1 insertion(+) (limited to 'shared-module') diff --git a/shared-module/_canio/Message.c b/shared-module/_canio/Message.c index df6a40a0a..1ac5b8178 100644 --- a/shared-module/_canio/Message.c +++ b/shared-module/_canio/Message.c @@ -58,6 +58,7 @@ const void *common_hal_canio_message_data_get(const canio_message_obj_t *self) const void common_hal_canio_message_data_set(canio_message_obj_t *self, const void *data, size_t size) { + self->size = size; memcpy(self->data, data, size); } -- cgit v1.2.3 From 2cb4707f92ffc65b2f160a7d1ea7d6b28892b548 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 17 Sep 2020 10:57:16 -0500 Subject: Message: add extended address flag --- shared-bindings/_canio/Message.c | 35 ++++++++++++++++++++++++++++++++--- shared-module/_canio/Message.c | 13 ++++++++++++- shared-module/_canio/Message.h | 9 ++++++--- 3 files changed, 50 insertions(+), 7 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/_canio/Message.c b/shared-bindings/_canio/Message.c index f1cd11d8e..3fa018a83 100644 --- a/shared-bindings/_canio/Message.c +++ b/shared-bindings/_canio/Message.c @@ -32,13 +32,14 @@ #include "py/runtime.h" //| class Message: -//| def __init__(self, id: int=0, data: Optional[bytes] = None, *, size: Optional[int] = None, rtr: bool = False): +//| def __init__(self, id: int=0, data: Optional[bytes] = None, *, size: Optional[int] = None, rtr: bool = False, extended: bool = False): //| """Construct a Message to send on a CAN bus //| //| :param int id: The numeric ID of the message //| :param bytes data: The content of the message //| :param int size: The amount of data requested, for an rtr //| :param bool rtr: True if the message represents an rtr (Remote Transmission Request) +//| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier //| //| In CAN, messages can have a size from 0 to 8 bytes. //| @@ -47,12 +48,13 @@ //| ... //| STATIC mp_obj_t canio_message_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_id, ARG_data, ARG_size, ARG_rtr, NUM_ARGS }; + enum { ARG_id, ARG_data, ARG_size, ARG_rtr, ARG_extended, NUM_ARGS }; static const mp_arg_t allowed_args[] = { { MP_QSTR_id, MP_ARG_INT, {.u_obj = 0} }, { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = 0} }, { MP_QSTR_size, MP_ARG_INT, {.u_int = -1} }, { MP_QSTR_rtr, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS ); @@ -60,6 +62,7 @@ STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); bool rtr = args[ARG_rtr].u_bool; + bool extended = args[ARG_extended].u_bool; size_t size = (size_t)args[ARG_size].u_int; bool specified_size = (size != (size_t)-1); bool specified_data = (args[ARG_data].u_obj != NULL); @@ -85,7 +88,7 @@ STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, canio_message_obj_t *self = m_new_obj(canio_message_obj_t); self->base.type = &canio_message_type; - common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, rtr); + common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, rtr, extended); return self; } @@ -174,6 +177,31 @@ STATIC const mp_obj_property_t canio_message_size_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| extended: bool +//| """True if the message represents a remote transmission request (RTR)""" +//| +STATIC mp_obj_t canio_message_extended_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return mp_obj_new_bool(common_hal_canio_message_extended_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_extended_get_obj, canio_message_extended_get); + +STATIC mp_obj_t canio_message_extended_set(const mp_obj_t self_in, const mp_obj_t extended) { + canio_message_obj_t *self = self_in; + common_hal_canio_message_size_set(self, mp_obj_is_true(extended)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_extended_set_obj, canio_message_extended_set); + + +STATIC const mp_obj_property_t canio_message_extended_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_extended_get_obj, + (mp_obj_t)&canio_message_extended_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + //| rtr: bool //| """True if the message represents a remote transmission request (RTR)""" //| @@ -204,6 +232,7 @@ STATIC const mp_rom_map_elem_t canio_message_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&canio_message_data_obj) }, { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&canio_message_size_obj) }, { MP_ROM_QSTR(MP_QSTR_rtr), MP_ROM_PTR(&canio_message_rtr_obj) }, + { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_message_extended_obj) }, }; STATIC MP_DEFINE_CONST_DICT(canio_message_locals_dict, canio_message_locals_dict_table); diff --git a/shared-module/_canio/Message.c b/shared-module/_canio/Message.c index 1ac5b8178..c0403b519 100644 --- a/shared-module/_canio/Message.c +++ b/shared-module/_canio/Message.c @@ -28,11 +28,12 @@ #include -void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr) +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended) { self->id = id; self->size = size; self->rtr = rtr; + self->extended = extended; if (data) { memcpy(self->data, data, size); } else { @@ -84,3 +85,13 @@ void common_hal_canio_message_rtr_set(canio_message_obj_t *self, bool rtr) { self->rtr = rtr; } + +bool common_hal_canio_message_extended_get(const canio_message_obj_t *self) +{ + return self->extended; +} + +void common_hal_canio_message_extended_set(canio_message_obj_t *self, bool extended) +{ + self->extended = extended; +} diff --git a/shared-module/_canio/Message.h b/shared-module/_canio/Message.h index e846f1095..b9fd8eaf2 100644 --- a/shared-module/_canio/Message.h +++ b/shared-module/_canio/Message.h @@ -31,17 +31,20 @@ typedef struct { mp_obj_base_t base; int id; - size_t size; uint8_t data[8]; - bool rtr; + size_t size:4; + bool rtr:1; + bool extended:1; } canio_message_obj_t; -void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr); +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended); bool common_hal_canio_message_rtr_get(const canio_message_obj_t *self); +bool common_hal_canio_message_extended_get(const canio_message_obj_t *self); int common_hal_canio_message_id_get(const canio_message_obj_t *self); const void *common_hal_canio_message_data_get(const canio_message_obj_t *self); size_t common_hal_canio_message_size_get(const canio_message_obj_t *self); void common_hal_canio_message_rtr_set(canio_message_obj_t *self, bool rtr); +void common_hal_canio_message_extended_set(canio_message_obj_t *self, bool extended); void common_hal_canio_message_id_set(canio_message_obj_t *self, int id); void common_hal_canio_message_data_set(canio_message_obj_t *self, const void *data, size_t size); void common_hal_canio_message_size_set(canio_message_obj_t *self, size_t size); -- cgit v1.2.3 From 44c5b2bbb1a00cf07e1725c76d1920e8c73977ed Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 17 Sep 2020 12:44:40 -0500 Subject: Respond to review comments Thanks @tannewt! --- ports/atmel-samd/common-hal/_canio/Listener.c | 1 - shared-bindings/_canio/CAN.c | 17 +++-------------- shared-bindings/_canio/Listener.c | 10 ++++------ shared-bindings/_canio/Match.c | 9 ++++----- shared-bindings/_canio/Match.h | 6 +++++- shared-bindings/_canio/Message.c | 23 +++++++++++------------ shared-bindings/_canio/Message.h | 13 +++++++++++++ shared-module/_canio/Match.c | 6 +++--- shared-module/_canio/Match.h | 5 ----- shared-module/_canio/Message.c | 20 ++++++++++---------- shared-module/_canio/Message.h | 12 ------------ 11 files changed, 53 insertions(+), 69 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/common-hal/_canio/Listener.c b/ports/atmel-samd/common-hal/_canio/Listener.c index 4d54e9f73..0a5f629f8 100644 --- a/ports/atmel-samd/common-hal/_canio/Listener.c +++ b/ports/atmel-samd/common-hal/_canio/Listener.c @@ -375,7 +375,6 @@ bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_messag } void common_hal_canio_listener_deinit(canio_listener_obj_t *self) { - // free our FIFO, clear our matches, SOMETHING if (self->can) { clear_filters(self); if (self->fifo_idx == 0) { diff --git a/shared-bindings/_canio/CAN.c b/shared-bindings/_canio/CAN.c index 53045c35a..537aa5580 100644 --- a/shared-bindings/_canio/CAN.c +++ b/shared-bindings/_canio/CAN.c @@ -53,8 +53,8 @@ //| connected to a transceiver which controls the H and L pins on a shared //| bus. //| -//| :param ~microcontrller.Pin rx: the pin to receive with. -//| :param ~microcontrller.Pin tx: the pin to transmit with, or None if the peripheral should operate in "silent" mode. +//| :param ~microcontroller.Pin rx: the pin to receive with. +//| :param ~microcontroller.Pin tx: the pin to transmit with, or None if the peripheral should operate in "silent" mode. //| :param int baudrate: The bit rate of the bus in Hz. All devices on the bus must agree on this value. //| :param bool loopback: True if the peripheral will be operated in loopback mode. //| :param bool auto_restart: If True, will restart communications after entering bus-off state @@ -76,13 +76,8 @@ STATIC mp_obj_t canio_can_make_new(const mp_obj_type_t *type, size_t n_args, con mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); -mp_printf(&mp_plat_print, "ARG_rx=%d args[ARG_rx].u_obj=%p\n", ARG_rx, args[ARG_rx].u_obj); -mp_printf(&mp_plat_print, "ARG_tx=%d args[ARG_tx].u_obj=%p\n", ARG_tx, args[ARG_tx].u_obj); - mcu_pin_obj_t *rx_pin = validate_obj_is_free_pin(args[ARG_rx].u_obj); -mp_printf(&mp_plat_print, "rx_pin=%p\n", rx_pin); mcu_pin_obj_t *tx_pin = validate_obj_is_free_pin_or_none(args[ARG_tx].u_obj); -mp_printf(&mp_plat_print, "tx_pin=%p\n", tx_pin); canio_can_obj_t *self = m_new_obj(canio_can_obj_t); self->base.type = &canio_can_type; @@ -94,7 +89,7 @@ mp_printf(&mp_plat_print, "tx_pin=%p\n", tx_pin); } -//| auto_restart: int +//| auto_restart: bool //| """If True, will restart communications after entering bus-off state""" //| STATIC mp_obj_t canio_can_auto_restart_get(mp_obj_t self_in) { @@ -240,12 +235,6 @@ STATIC const mp_obj_property_t canio_can_state_obj = { }; -#if 0 -//| # pending_tx_count: int -//| # """The number of messages waiting to be transmitted. (read-only)""" -//| -#endif - //| def restart(self) -> None: //| """If the device is in the bus off state, restart it.""" //| ... diff --git a/shared-bindings/_canio/Listener.c b/shared-bindings/_canio/Listener.c index a3890f8dd..84b2aacb9 100644 --- a/shared-bindings/_canio/Listener.c +++ b/shared-bindings/_canio/Listener.c @@ -39,7 +39,7 @@ //| //| def read(self) -> Optional[Message]: -//| """Returns a message, after waiting up to self.timeout seconds +//| """Reads a message, after waiting up to self.timeout seconds //| //| If no message is received in time, None is returned. Otherwise, //| a Message is returned.""" @@ -62,10 +62,8 @@ STATIC mp_obj_t canio_listener_read(mp_obj_t self_in) { STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_read_obj, canio_listener_read); //| def readinto(self, message: Message) -> bool: -//| """Returns a message, after waiting up to self.timeout seconds -//| -//| Returns True (and modifies message) if a message was received, -//| False otherwise.""" +//| """Returns True (and modifies message) if a message was received +//| before ``timeout`` seconds elapsed, False otherwise.""" //| ... //| STATIC mp_obj_t canio_listener_readinto(mp_obj_t self_in, mp_obj_t message) { @@ -115,7 +113,7 @@ STATIC mp_obj_t canio_listener_next(mp_obj_t self_in) { if (common_hal_canio_listener_in_waiting(self)) { return canio_listener_read(self_in); } - return self; + return MP_OBJ_STOP_ITERATION; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_next_obj, canio_listener_next); diff --git a/shared-bindings/_canio/Match.c b/shared-bindings/_canio/Match.c index b71529b73..4ff35906b 100644 --- a/shared-bindings/_canio/Match.c +++ b/shared-bindings/_canio/Match.c @@ -25,7 +25,6 @@ */ #include "shared-bindings/_canio/Match.h" -#include "shared-module/_canio/Match.h" #include "py/objproperty.h" #include "py/runtime.h" @@ -46,7 +45,7 @@ STATIC mp_obj_t canio_match_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, ARG_mask, ARG_extended, NUM_ARGS }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_address, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} }, + { MP_QSTR_address, MP_ARG_INT | MP_ARG_REQUIRED }, { MP_QSTR_mask, MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, }; @@ -79,7 +78,7 @@ STATIC mp_obj_t canio_match_make_new(const mp_obj_type_t *type, size_t n_args, c STATIC mp_obj_t canio_match_address_get(mp_obj_t self_in) { canio_match_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_address_get(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_address(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_match_address_get_obj, canio_match_address_get); @@ -97,7 +96,7 @@ const mp_obj_property_t canio_match_address_obj = { STATIC mp_obj_t canio_match_mask_get(mp_obj_t self_in) { canio_match_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_mask_get(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_mask(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_match_mask_get_obj, canio_match_mask_get); @@ -114,7 +113,7 @@ const mp_obj_property_t canio_match_mask_obj = { STATIC mp_obj_t canio_match_extended_get(mp_obj_t self_in) { canio_match_obj_t *self = self_in; - return mp_obj_new_bool(common_hal_canio_match_extended_get(self)); + return mp_obj_new_bool(common_hal_canio_match_get_extended(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_match_extended_get_obj, canio_match_extended_get); diff --git a/shared-bindings/_canio/Match.h b/shared-bindings/_canio/Match.h index adf98eb86..5522c2636 100644 --- a/shared-bindings/_canio/Match.h +++ b/shared-bindings/_canio/Match.h @@ -27,7 +27,11 @@ #pragma once #include "py/obj.h" +#include "shared-module/_canio/Match.h" extern const mp_obj_type_t canio_match_type; -// Nothing now. +void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended); +int common_hal_canio_match_get_address(const canio_match_obj_t *self); +int common_hal_canio_match_get_mask(const canio_match_obj_t *self); +bool common_hal_canio_match_get_extended(const canio_match_obj_t *self); diff --git a/shared-bindings/_canio/Message.c b/shared-bindings/_canio/Message.c index bfaaf52b2..85657e05e 100644 --- a/shared-bindings/_canio/Message.c +++ b/shared-bindings/_canio/Message.c @@ -25,7 +25,6 @@ */ #include "shared-bindings/_canio/Message.h" -#include "shared-module/_canio/Message.h" #include "py/obj.h" #include "py/objproperty.h" @@ -33,7 +32,7 @@ //| class Message: //| def __init__(self, id: int=0, data: Optional[bytes] = None, *, size: Optional[int] = None, rtr: bool = False, extended: bool = False): -//| """Construct a Message to send on a CAN bus +//| """Construct a Message to use with a CAN bus. Provide arguments to create a message to send. Otherwise, use Listener.readinto() to read a message. //| //| :param int id: The numeric ID of the message //| :param bytes data: The content of the message @@ -97,13 +96,13 @@ STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, //| STATIC mp_obj_t canio_message_id_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_id_get(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_get_id(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_message_id_get_obj, canio_message_id_get); STATIC mp_obj_t canio_message_id_set(const mp_obj_t self_in, const mp_obj_t id) { canio_message_obj_t *self = self_in; - common_hal_canio_message_id_set(self, mp_obj_get_int(id)); + common_hal_canio_message_set_id(self, mp_obj_get_int(id)); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(canio_message_id_set_obj, canio_message_id_set); @@ -122,7 +121,7 @@ STATIC const mp_obj_property_t canio_message_id_obj = { //| STATIC mp_obj_t canio_message_data_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; - return mp_obj_new_bytes((const byte*)common_hal_canio_message_data_get(self), common_hal_canio_message_size_get(self)); + return mp_obj_new_bytes((const byte*)common_hal_canio_message_get_data(self), common_hal_canio_message_get_size(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_message_data_get_obj, canio_message_data_get); @@ -133,7 +132,7 @@ STATIC mp_obj_t canio_message_data_set(const mp_obj_t self_in, const mp_obj_t da if (data.len > 8) { mp_raise_ValueError(translate("Messages limited to 8 bytes")); } - common_hal_canio_message_data_set(self, data.buf, data.len); + common_hal_canio_message_set_data(self, data.buf, data.len); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(canio_message_data_set_obj, canio_message_data_set); @@ -154,7 +153,7 @@ STATIC const mp_obj_property_t canio_message_data_obj = { //| STATIC mp_obj_t canio_message_size_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_size_get(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_get_size(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_message_size_get_obj, canio_message_size_get); @@ -164,7 +163,7 @@ STATIC mp_obj_t canio_message_size_set(const mp_obj_t self_in, const mp_obj_t si if (size > 8) { mp_raise_ValueError(translate("Messages limited to 8 bytes")); } - common_hal_canio_message_size_set(self, size); + common_hal_canio_message_set_size(self, size); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(canio_message_size_set_obj, canio_message_size_set); @@ -182,13 +181,13 @@ STATIC const mp_obj_property_t canio_message_size_obj = { //| STATIC mp_obj_t canio_message_extended_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; - return mp_obj_new_bool(common_hal_canio_message_extended_get(self)); + return mp_obj_new_bool(common_hal_canio_message_get_extended(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_message_extended_get_obj, canio_message_extended_get); STATIC mp_obj_t canio_message_extended_set(const mp_obj_t self_in, const mp_obj_t extended) { canio_message_obj_t *self = self_in; - common_hal_canio_message_size_set(self, mp_obj_is_true(extended)); + common_hal_canio_message_set_extended(self, mp_obj_is_true(extended)); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(canio_message_extended_set_obj, canio_message_extended_set); @@ -207,13 +206,13 @@ STATIC const mp_obj_property_t canio_message_extended_obj = { //| STATIC mp_obj_t canio_message_rtr_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; - return mp_obj_new_bool(common_hal_canio_message_rtr_get(self)); + return mp_obj_new_bool(common_hal_canio_message_get_rtr(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_message_rtr_get_obj, canio_message_rtr_get); STATIC mp_obj_t canio_message_rtr_set(const mp_obj_t self_in, const mp_obj_t rtr) { canio_message_obj_t *self = self_in; - common_hal_canio_message_size_set(self, mp_obj_is_true(rtr)); + common_hal_canio_message_set_rtr(self, mp_obj_is_true(rtr)); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(canio_message_rtr_set_obj, canio_message_rtr_set); diff --git a/shared-bindings/_canio/Message.h b/shared-bindings/_canio/Message.h index 32d6801bc..ed739af0d 100644 --- a/shared-bindings/_canio/Message.h +++ b/shared-bindings/_canio/Message.h @@ -27,5 +27,18 @@ #pragma once #include "py/obj.h" +#include "shared-module/_canio/Message.h" extern const mp_obj_type_t canio_message_type; + +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended); +const void *common_hal_canio_message_get_data(const canio_message_obj_t *self); +void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size); +bool common_hal_canio_message_get_extended(const canio_message_obj_t *self); +void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended); +int common_hal_canio_message_get_id(const canio_message_obj_t *self); +void common_hal_canio_message_set_id(canio_message_obj_t *self, int id); +bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self); +void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr); +size_t common_hal_canio_message_get_size(const canio_message_obj_t *self); +void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size); diff --git a/shared-module/_canio/Match.c b/shared-module/_canio/Match.c index 2b696addb..3dcde18a7 100644 --- a/shared-module/_canio/Match.c +++ b/shared-module/_canio/Match.c @@ -32,12 +32,12 @@ void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int self->extended = extended; } -int common_hal_canio_match_address_get(const canio_match_obj_t *self) { +int common_hal_canio_match_get_address(const canio_match_obj_t *self) { return self->address; } -int common_hal_canio_match_mask_get(const canio_match_obj_t *self) { +int common_hal_canio_match_get_mask(const canio_match_obj_t *self) { return self->mask; } -bool common_hal_canio_match_extended_get(const canio_match_obj_t *self) { +bool common_hal_canio_match_get_extended(const canio_match_obj_t *self) { return self->extended; } diff --git a/shared-module/_canio/Match.h b/shared-module/_canio/Match.h index 099df976d..25f047f37 100644 --- a/shared-module/_canio/Match.h +++ b/shared-module/_canio/Match.h @@ -34,8 +34,3 @@ typedef struct { int mask; bool extended; } canio_match_obj_t; - -void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended); -int common_hal_canio_match_address_get(const canio_match_obj_t *self); -int common_hal_canio_match_mask_get(const canio_match_obj_t *self); -bool common_hal_canio_match_extended_get(const canio_match_obj_t *self); diff --git a/shared-module/_canio/Message.c b/shared-module/_canio/Message.c index c0403b519..0caca58f0 100644 --- a/shared-module/_canio/Message.c +++ b/shared-module/_canio/Message.c @@ -41,57 +41,57 @@ void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void } } -int common_hal_canio_message_id_get(const canio_message_obj_t *self) +int common_hal_canio_message_get_id(const canio_message_obj_t *self) { return self->id; } -void common_hal_canio_message_id_set(canio_message_obj_t *self, int id) +void common_hal_canio_message_set_id(canio_message_obj_t *self, int id) { self->id = id; } -const void *common_hal_canio_message_data_get(const canio_message_obj_t *self) +const void *common_hal_canio_message_get_data(const canio_message_obj_t *self) { return self->data; } -const void common_hal_canio_message_data_set(canio_message_obj_t *self, const void *data, size_t size) +const void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size) { self->size = size; memcpy(self->data, data, size); } -size_t common_hal_canio_message_size_get(const canio_message_obj_t *self) +size_t common_hal_canio_message_get_size(const canio_message_obj_t *self) { return self->size; } -void common_hal_canio_message_size_set(canio_message_obj_t *self, size_t size) +void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size) { memset(self->data, 0, size); self->size = size; } -bool common_hal_canio_message_rtr_get(const canio_message_obj_t *self) +bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self) { return self->rtr; } -void common_hal_canio_message_rtr_set(canio_message_obj_t *self, bool rtr) +void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr) { self->rtr = rtr; } -bool common_hal_canio_message_extended_get(const canio_message_obj_t *self) +bool common_hal_canio_message_get_extended(const canio_message_obj_t *self) { return self->extended; } -void common_hal_canio_message_extended_set(canio_message_obj_t *self, bool extended) +void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended) { self->extended = extended; } diff --git a/shared-module/_canio/Message.h b/shared-module/_canio/Message.h index b9fd8eaf2..b99c5c48e 100644 --- a/shared-module/_canio/Message.h +++ b/shared-module/_canio/Message.h @@ -36,15 +36,3 @@ typedef struct { bool rtr:1; bool extended:1; } canio_message_obj_t; - -void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended); -bool common_hal_canio_message_rtr_get(const canio_message_obj_t *self); -bool common_hal_canio_message_extended_get(const canio_message_obj_t *self); -int common_hal_canio_message_id_get(const canio_message_obj_t *self); -const void *common_hal_canio_message_data_get(const canio_message_obj_t *self); -size_t common_hal_canio_message_size_get(const canio_message_obj_t *self); -void common_hal_canio_message_rtr_set(canio_message_obj_t *self, bool rtr); -void common_hal_canio_message_extended_set(canio_message_obj_t *self, bool extended); -void common_hal_canio_message_id_set(canio_message_obj_t *self, int id); -void common_hal_canio_message_data_set(canio_message_obj_t *self, const void *data, size_t size); -void common_hal_canio_message_size_set(canio_message_obj_t *self, size_t size); -- cgit v1.2.3 From c39ec1581e3fbc59de7f882adf2e6fbb574fb42e Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 18 Sep 2020 11:14:59 -0500 Subject: _canio: Message: setting data clears rtr, and vice versa --- shared-bindings/_canio/Message.c | 4 ++-- shared-module/_canio/Message.c | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/_canio/Message.c b/shared-bindings/_canio/Message.c index 85657e05e..c7ef5d458 100644 --- a/shared-bindings/_canio/Message.c +++ b/shared-bindings/_canio/Message.c @@ -117,7 +117,7 @@ STATIC const mp_obj_property_t canio_message_id_obj = { //| data: bytes //| """The content of the message, or dummy content in the case of an rtr. //| -//| Assigning to data also sets the length.""" +//| Assigning to data also sets the length and clears the rtr flag.""" //| STATIC mp_obj_t canio_message_data_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; @@ -202,7 +202,7 @@ STATIC const mp_obj_property_t canio_message_extended_obj = { //| rtr: bool -//| """True if the message represents a remote transmission request (RTR)""" +//| """True if the message represents a remote transmission request (RTR). Setting rtr to true zeros out data""" //| STATIC mp_obj_t canio_message_rtr_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; diff --git a/shared-module/_canio/Message.c b/shared-module/_canio/Message.c index 0caca58f0..a02bd0127 100644 --- a/shared-module/_canio/Message.c +++ b/shared-module/_canio/Message.c @@ -59,6 +59,7 @@ const void *common_hal_canio_message_get_data(const canio_message_obj_t *self) const void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size) { + self->rtr = false; self->size = size; memcpy(self->data, data, size); } @@ -84,6 +85,9 @@ bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self) void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr) { self->rtr = rtr; + if (rtr) { + memset(self->data, 0, self->size); + } } bool common_hal_canio_message_get_extended(const canio_message_obj_t *self) -- cgit v1.2.3 From 4869dbdc670bfa8a5f2e0a639495d03984ea0a6a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 21 Sep 2020 16:42:12 -0500 Subject: canio: rename from _canio This reflects our belief that the API is stable enough to avoid incompatible changes during 6.x. --- main.c | 2 +- ports/atmel-samd/common-hal/_canio/CAN.c | 445 -------------------------- ports/atmel-samd/common-hal/_canio/CAN.h | 55 ---- ports/atmel-samd/common-hal/_canio/Listener.c | 391 ---------------------- ports/atmel-samd/common-hal/_canio/Listener.h | 53 --- ports/atmel-samd/common-hal/_canio/__init__.c | 25 -- ports/atmel-samd/common-hal/_canio/__init__.h | 67 ---- ports/atmel-samd/common-hal/canio/CAN.c | 445 ++++++++++++++++++++++++++ ports/atmel-samd/common-hal/canio/CAN.h | 55 ++++ ports/atmel-samd/common-hal/canio/Listener.c | 391 ++++++++++++++++++++++ ports/atmel-samd/common-hal/canio/Listener.h | 53 +++ ports/atmel-samd/common-hal/canio/__init__.c | 25 ++ ports/atmel-samd/common-hal/canio/__init__.h | 67 ++++ py/circuitpy_defns.mk | 14 +- py/circuitpy_mpconfig.h | 2 +- shared-bindings/_canio/CAN.c | 422 ------------------------ shared-bindings/_canio/CAN.h | 54 ---- shared-bindings/_canio/Listener.c | 193 ----------- shared-bindings/_canio/Listener.h | 31 -- shared-bindings/_canio/Match.c | 139 -------- shared-bindings/_canio/Match.h | 37 --- shared-bindings/_canio/Message.c | 212 ------------ shared-bindings/_canio/Message.h | 44 --- shared-bindings/_canio/__init__.c | 124 ------- shared-bindings/_canio/__init__.h | 33 -- shared-bindings/canio/CAN.c | 422 ++++++++++++++++++++++++ shared-bindings/canio/CAN.h | 54 ++++ shared-bindings/canio/Listener.c | 193 +++++++++++ shared-bindings/canio/Listener.h | 31 ++ shared-bindings/canio/Match.c | 139 ++++++++ shared-bindings/canio/Match.h | 37 +++ shared-bindings/canio/Message.c | 212 ++++++++++++ shared-bindings/canio/Message.h | 44 +++ shared-bindings/canio/__init__.c | 124 +++++++ shared-bindings/canio/__init__.h | 33 ++ shared-module/_canio/Match.c | 43 --- shared-module/_canio/Match.h | 36 --- shared-module/_canio/Message.c | 101 ------ shared-module/_canio/Message.h | 38 --- shared-module/canio/Match.c | 43 +++ shared-module/canio/Match.h | 36 +++ shared-module/canio/Message.c | 101 ++++++ shared-module/canio/Message.h | 38 +++ 43 files changed, 2552 insertions(+), 2552 deletions(-) delete mode 100644 ports/atmel-samd/common-hal/_canio/CAN.c delete mode 100644 ports/atmel-samd/common-hal/_canio/CAN.h delete mode 100644 ports/atmel-samd/common-hal/_canio/Listener.c delete mode 100644 ports/atmel-samd/common-hal/_canio/Listener.h delete mode 100644 ports/atmel-samd/common-hal/_canio/__init__.c delete mode 100644 ports/atmel-samd/common-hal/_canio/__init__.h create mode 100644 ports/atmel-samd/common-hal/canio/CAN.c create mode 100644 ports/atmel-samd/common-hal/canio/CAN.h create mode 100644 ports/atmel-samd/common-hal/canio/Listener.c create mode 100644 ports/atmel-samd/common-hal/canio/Listener.h create mode 100644 ports/atmel-samd/common-hal/canio/__init__.c create mode 100644 ports/atmel-samd/common-hal/canio/__init__.h delete mode 100644 shared-bindings/_canio/CAN.c delete mode 100644 shared-bindings/_canio/CAN.h delete mode 100644 shared-bindings/_canio/Listener.c delete mode 100644 shared-bindings/_canio/Listener.h delete mode 100644 shared-bindings/_canio/Match.c delete mode 100644 shared-bindings/_canio/Match.h delete mode 100644 shared-bindings/_canio/Message.c delete mode 100644 shared-bindings/_canio/Message.h delete mode 100644 shared-bindings/_canio/__init__.c delete mode 100644 shared-bindings/_canio/__init__.h create mode 100644 shared-bindings/canio/CAN.c create mode 100644 shared-bindings/canio/CAN.h create mode 100644 shared-bindings/canio/Listener.c create mode 100644 shared-bindings/canio/Listener.h create mode 100644 shared-bindings/canio/Match.c create mode 100644 shared-bindings/canio/Match.h create mode 100644 shared-bindings/canio/Message.c create mode 100644 shared-bindings/canio/Message.h create mode 100644 shared-bindings/canio/__init__.c create mode 100644 shared-bindings/canio/__init__.h delete mode 100644 shared-module/_canio/Match.c delete mode 100644 shared-module/_canio/Match.h delete mode 100644 shared-module/_canio/Message.c delete mode 100644 shared-module/_canio/Message.h create mode 100644 shared-module/canio/Match.c create mode 100644 shared-module/canio/Match.h create mode 100644 shared-module/canio/Message.c create mode 100644 shared-module/canio/Message.h (limited to 'shared-module') diff --git a/main.c b/main.c index 4d34e451d..dbd367a59 100755 --- a/main.c +++ b/main.c @@ -82,7 +82,7 @@ #endif #if CIRCUITPY_CANIO -#include "common-hal/_canio/CAN.h" +#include "common-hal/canio/CAN.h" #endif void do_str(const char *src, mp_parse_input_kind_t input_kind) { diff --git a/ports/atmel-samd/common-hal/_canio/CAN.c b/ports/atmel-samd/common-hal/_canio/CAN.c deleted file mode 100644 index 0d967d7ca..000000000 --- a/ports/atmel-samd/common-hal/_canio/CAN.c +++ /dev/null @@ -1,445 +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/runtime.h" -#include "py/mperrno.h" - -#include "peripheral_clk_config.h" - -#include "common-hal/_canio/CAN.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/util.h" -#include "supervisor/port.h" - -#include "component/can.h" - -#include "genhdr/candata.h" - -STATIC Can * const can_insts[] = CAN_INSTS; - -STATIC canio_can_obj_t *can_objs[MP_ARRAY_SIZE(can_insts)]; - -// This must be placed in the first 64kB of RAM -STATIC COMPILER_SECTION(".canram") canio_can_state_t can_state[MP_ARRAY_SIZE(can_insts)]; - -void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent) -{ - mcu_pin_function_t *tx_function = mcu_find_pin_function(can_tx, tx, -1, MP_QSTR_tx); - int instance = tx_function->instance; - - mcu_pin_function_t *rx_function = mcu_find_pin_function(can_rx, rx, instance, MP_QSTR_rx); - - const uint32_t can_frequency = CONF_CAN0_FREQUENCY; - -#define DIV_ROUND(a, b) (((a) + (b)/2) / (b)) -#define DIV_ROUND_UP(a, b) (((a) + (b) - 1) / (b)) - - uint32_t clocks_per_bit = DIV_ROUND(can_frequency, baudrate); - uint32_t clocks_to_sample = DIV_ROUND(clocks_per_bit * 7, 8); - uint32_t clocks_after_sample = clocks_per_bit - clocks_to_sample; - uint32_t divisor = MAX(DIV_ROUND_UP(clocks_to_sample, 256), DIV_ROUND_UP(clocks_after_sample, 128)); - if (divisor > 32) { - mp_raise_OSError(MP_EINVAL); // baudrate cannot be attained (16kHz or something is lower bound, should never happen) - } - - gpio_set_pin_direction(tx_function->pin, GPIO_DIRECTION_OUT); - gpio_set_pin_function(tx_function->pin, tx_function->function); - common_hal_never_reset_pin(tx_function->obj); - - gpio_set_pin_direction(rx_function->pin, GPIO_DIRECTION_IN); - gpio_set_pin_function(rx_function->pin, rx_function->function); - common_hal_never_reset_pin(rx_function->obj); - - self->tx_pin_number = tx ? common_hal_mcu_pin_number(tx) : COMMON_HAL_MCU_NO_PIN; - self->rx_pin_number = rx ? common_hal_mcu_pin_number(rx) : COMMON_HAL_MCU_NO_PIN; - self->hw = can_insts[instance]; - self->state = &can_state[instance]; - - self->loopback = loopback; - self->silent = silent; - - // Allow configuration change - hri_can_set_CCCR_INIT_bit(self->hw); - while (hri_can_get_CCCR_INIT_bit(self->hw) == 0) { - } - hri_can_set_CCCR_CCE_bit(self->hw); - - if (instance == 0) { - hri_mclk_set_AHBMASK_CAN0_bit(MCLK); - hri_gclk_write_PCHCTRL_reg(GCLK, CAN0_GCLK_ID, CONF_GCLK_CAN0_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos)); - - NVIC_DisableIRQ(CAN0_IRQn); - NVIC_ClearPendingIRQ(CAN0_IRQn); - NVIC_EnableIRQ(CAN0_IRQn); - hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); -#ifdef CAN1_GCLK_ID - } else if (instance == 1) { - hri_mclk_set_AHBMASK_CAN1_bit(MCLK); - hri_gclk_write_PCHCTRL_reg(GCLK, CAN1_GCLK_ID, CONF_GCLK_CAN1_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos)); - - NVIC_DisableIRQ(CAN1_IRQn); - NVIC_ClearPendingIRQ(CAN1_IRQn); - NVIC_EnableIRQ(CAN1_IRQn); - hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); -#endif - } - - self->hw->CCCR.bit.FDOE = 0; // neither FD nor Bit Rate Switch enabled - self->hw->CCCR.bit.BRSE = 0; - - hri_can_write_MRCFG_reg(self->hw, CAN_MRCFG_QOS(CAN_MRCFG_QOS_DISABLE_Val)); // QoS disabled (no sensitive operation) - - // A "nominal bit" is a header bit. With dual rate CAN FD, this is a slower rate - { - CAN_NBTP_Type btp = { - // 0 means "1 tq", but 2 is subtracted from NTSEG1 for the - // fixed 1 "SYNC" tq - .bit.NTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 2, - .bit.NTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1, - .bit.NBRP = divisor - 1, - .bit.NSJW = DIV_ROUND(clocks_after_sample, divisor * 4), - }; - hri_can_write_NBTP_reg(self->hw, btp.reg); - } - - // A "data bit" is a data bit :) with dula rate CAN FD, this is a higher - // rate. However, CAN FD is not implemented in CircuitPython, and this is - // the same rate as the "nominal rate". - { - CAN_DBTP_Type btp = { - .bit.DTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 1, - .bit.DTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1, - .bit.DBRP = divisor - 1, - .bit.DSJW = DIV_ROUND(clocks_after_sample, divisor * 4), - }; - hri_can_write_DBTP_reg(self->hw, btp.reg); - } - - { - CAN_RXF0C_Type rxf = { - .bit.F0SA = (uint32_t)self->state->rx0_fifo, - .bit.F0S = COMMON_HAL_CANIO_RX_FIFO_SIZE, - }; - hri_can_write_RXF0C_reg(self->hw, rxf.reg); - } - - { - CAN_RXF1C_Type rxf = { - .bit.F1SA = (uint32_t)self->state->rx1_fifo, - .bit.F1S = COMMON_HAL_CANIO_RX_FIFO_SIZE, - }; - hri_can_write_RXF1C_reg(self->hw, rxf.reg); - } - - // All RX data has an 8 byte payload (max) - { - CAN_RXESC_Type esc = { - .bit.F0DS = CAN_RXESC_F0DS_DATA8_Val, - .bit.F1DS = CAN_RXESC_F1DS_DATA8_Val, - .bit.RBDS = CAN_RXESC_RBDS_DATA8_Val, - }; - hri_can_write_RXESC_reg(self->hw, esc.reg); - } - - // All TX data has an 8 byte payload (max) - { - CAN_TXESC_Type esc = { - .bit.TBDS = CAN_TXESC_TBDS_DATA8_Val, - }; - hri_can_write_TXESC_reg(self->hw, esc.reg); - } - - { - CAN_TXBC_Type bc = { - .bit.TBSA = (uint32_t)self->state->tx_fifo, - .bit.NDTB = COMMON_HAL_CANIO_TX_FIFO_SIZE, - .bit.TFQM = 0, // Messages are transmitted in the order submitted - }; - hri_can_write_TXBC_reg(self->hw, bc.reg); - } - - { - CAN_TXEFC_Type efc = { - .bit.EFS = 0, - }; - hri_can_write_TXEFC_reg(self->hw, efc.reg); - } - - { - CAN_GFC_Type gfc = { - .bit.RRFE = 1, - .bit.ANFS = CAN_GFC_ANFS_REJECT_Val, - .bit.ANFE = CAN_GFC_ANFE_REJECT_Val, - }; - hri_can_write_GFC_reg(self->hw, gfc.reg); - } - - { - CAN_SIDFC_Type dfc = { - .bit.LSS = COMMON_HAL_CANIO_RX_FILTER_SIZE, - .bit.FLSSA = (uint32_t)self->state->standard_rx_filter - }; - hri_can_write_SIDFC_reg(self->hw, dfc.reg); - } - - { - CAN_XIDFC_Type dfc = { - .bit.LSE = COMMON_HAL_CANIO_RX_FILTER_SIZE, - .bit.FLESA = (uint32_t)self->state->extended_rx_filter - }; - hri_can_write_XIDFC_reg(self->hw, dfc.reg); - } - - { - CAN_IE_Type ie = { - .bit.EWE = 1, - .bit.EPE = 1, - .bit.BOE = 1, - }; - hri_can_write_IE_reg(self->hw, ie.reg); - } - - hri_can_write_XIDAM_reg(self->hw, CAN_XIDAM_RESETVALUE); - -// silent: The CAN is set in Bus Monitoring Mode by programming CCCR.MON to '1'. (tx pin unused) -// external loopback: The CAN can be set in External Loop Back Mode by programming TEST.LBCK and CCCR.MON to '1'. (rx pin unused) -// internal loopback (silent loopback): Internal Loop Back Mode is entered by programming bits TEST.LBCK and CCCR.MON to '1'. (tx, rx unused) - self->hw->CCCR.bit.MON = silent; - self->hw->CCCR.bit.TEST = loopback; - self->hw->TEST.bit.LBCK = loopback; - - if (instance == 0) { - NVIC_DisableIRQ(CAN0_IRQn); - NVIC_ClearPendingIRQ(CAN0_IRQn); - NVIC_EnableIRQ(CAN0_IRQn); -#ifdef CAN1_GCLK_ID - } else if (instance == 1) { - NVIC_DisableIRQ(CAN1_IRQn); - NVIC_ClearPendingIRQ(CAN1_IRQn); - NVIC_EnableIRQ(CAN1_IRQn); -#endif - } - - hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); - // Prevent configuration change - hri_can_clear_CCCR_CCE_bit(self->hw); - hri_can_clear_CCCR_INIT_bit(self->hw); - while (hri_can_get_CCCR_INIT_bit(self->hw)) { - } - - can_objs[instance] = self; -} - -bool common_hal_canio_can_loopback_get(canio_can_obj_t *self) -{ - return self->loopback; -} - -int common_hal_canio_can_baudrate_get(canio_can_obj_t *self) -{ - return self->baudrate; -} - -int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self) -{ - return self->hw->ECR.bit.TEC; -} - -int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self) -{ - return self->hw->ECR.bit.REC; -} - -int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self) -{ - return self->error_warning_state_count; -} - -int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self) -{ - return self->error_passive_state_count; -} - -int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self) -{ - return self->bus_off_state_count; -} - -canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self) { - CAN_PSR_Type psr = self->hw->PSR; - if (psr.bit.BO) { - return BUS_STATE_OFF; - } - if (psr.bit.EP) { - return BUS_STATE_ERROR_PASSIVE; - } - if (psr.bit.EW) { - return BUS_STATE_ERROR_WARNING; - } - return BUS_STATE_ERROR_ACTIVE; -} - -void common_hal_canio_can_restart(canio_can_obj_t *self) { - if (!self->hw->PSR.bit.BO) { - return; - } - - hri_can_clear_CCCR_INIT_bit(self->hw); - while (hri_can_get_CCCR_INIT_bit(self->hw)) { - } -} - -bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self) { - return self->auto_restart; -} - -void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool value) { - self->auto_restart = value; -} - -static void maybe_auto_restart(canio_can_obj_t *self) { - if (self->auto_restart) { - common_hal_canio_can_restart(self); - } -} - -void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message) -{ - maybe_auto_restart(self); - - // We have just one dedicated TX buffer, use it! - canio_can_fifo_t *ent = &self->state->tx_fifo[0]; - - ent->txb0.bit.ESI = false; - ent->txb0.bit.XTD = message->extended; - ent->txb0.bit.RTR = message->rtr; - if (message->extended) { - ent->txb0.bit.ID = message->id << 18; - } else { - ent->txb0.bit.ID = message->id << 18; // short addresses are left-justified - } - - ent->txb1.bit.MM = 0; // "message marker" - ent->txb1.bit.EFC = 0; // don't store fifo events to event queue - ent->txb1.bit.FDF = 0; // Classic CAN format - ent->txb1.bit.BRS = 0; // No bit rate switching - ent->txb1.bit.DLC = message->size; - - if (!message->rtr) { - memcpy(ent->data, message->data, message->size); - } - - // TX buffer add request - self->hw->TXBAR.reg = 1; - - // wait 8ms (hard coded for now) for TX to occur - uint64_t deadline = port_get_raw_ticks(NULL) + 8; - while (port_get_raw_ticks(NULL) < deadline && !(self->hw->TXBTO.reg & 1)) { - RUN_BACKGROUND_TASKS; - } -} - -bool common_hal_canio_can_silent_get(canio_can_obj_t *self) { - return self->silent; -} - -bool common_hal_canio_can_deinited(canio_can_obj_t *self) { - return !self->hw; -} - -void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self) { - if (common_hal_canio_can_deinited(self)) { - raise_deinited_error(); - } -} - -void common_hal_canio_can_deinit(canio_can_obj_t *self) -{ - if (self->hw) { - hri_can_set_CCCR_INIT_bit(self->hw); - self->hw = 0; - } - if (self->rx_pin_number != COMMON_HAL_MCU_NO_PIN) { - reset_pin_number(self->rx_pin_number); - self->rx_pin_number = COMMON_HAL_MCU_NO_PIN; - } - if (self->tx_pin_number != COMMON_HAL_MCU_NO_PIN) { - reset_pin_number(self->tx_pin_number); - self->tx_pin_number = COMMON_HAL_MCU_NO_PIN; - } -} - -void common_hal_canio_reset(void) { - memset(can_state, 0, sizeof(can_state)); - - for (size_t i=0; ierror_warning_state_count += 1; - } - if (ir & CAN_IE_EPE) { - self->error_passive_state_count += 1; - } - if (ir & CAN_IE_BOE) { - self->bus_off_state_count += 1; - } - - /* Acknowledge interrupt */ - hri_can_write_IR_reg(hw, ir); -} - -__attribute__((used)) -void CAN0_Handler(void) { - can_handler(0); -} - -#ifdef CAN1_GCLK_ID -__attribute__((used)) -void CAN1_Handler(void) { - can_handler(1); -} -#endif diff --git a/ports/atmel-samd/common-hal/_canio/CAN.h b/ports/atmel-samd/common-hal/_canio/CAN.h deleted file mode 100644 index 1cc34e3ac..000000000 --- a/ports/atmel-samd/common-hal/_canio/CAN.h +++ /dev/null @@ -1,55 +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. - */ - -#pragma once - -#include "py/obj.h" -#include "shared-bindings/_canio/__init__.h" -#include "shared-bindings/_canio/CAN.h" -#include "component/can.h" -#include "common-hal/microcontroller/Pin.h" -#include "common-hal/_canio/__init__.h" -#include "shared-module/_canio/Message.h" - -#define COMMON_HAL_CAN_RX_FIFO_LEN (2) -#define COMMON_HAL_CAN_TX_FIFO_LEN (2) - -typedef struct canio_can_obj { - mp_obj_base_t base; - Can *hw; - canio_can_state_t *state; - volatile uint32_t error_warning_state_count; - volatile uint32_t error_passive_state_count; - volatile uint32_t bus_off_state_count; - int baudrate; - uint8_t rx_pin_number:8; - uint8_t tx_pin_number:8; - bool loopback:1; - bool silent:1; - bool auto_restart:1; - bool fifo0_in_use:1; - bool fifo1_in_use:1; -} canio_can_obj_t; diff --git a/ports/atmel-samd/common-hal/_canio/Listener.c b/ports/atmel-samd/common-hal/_canio/Listener.c deleted file mode 100644 index 0a5f629f8..000000000 --- a/ports/atmel-samd/common-hal/_canio/Listener.c +++ /dev/null @@ -1,391 +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 - -#include "py/obj.h" -#include "py/runtime.h" - -#include "common-hal/_canio/__init__.h" -#include "common-hal/_canio/Listener.h" -#include "shared-bindings/util.h" -#include "supervisor/shared/tick.h" -#include "component/can.h" - -STATIC void allow_config_change(canio_can_obj_t *can) { - can->hw->CCCR.bit.INIT = 1; - while (!can->hw->CCCR.bit.INIT) { - } - can->hw->CCCR.bit.CCE = 1; -} - -STATIC void prevent_config_change(canio_can_obj_t *can) { - can->hw->CCCR.bit.CCE = 0; - can->hw->CCCR.bit.INIT = 0; - while (can->hw->CCCR.bit.INIT) { - } -} - -__attribute__((unused)) -STATIC void static_assertions(void) { - MP_STATIC_ASSERT(CAN_GFC_ANFE_RXF0_Val + 1 == CAN_GFC_ANFE_RXF1_Val); - MP_STATIC_ASSERT(CAN_GFC_ANFS_RXF0_Val + 1 == CAN_GFC_ANFS_RXF1_Val); - MP_STATIC_ASSERT(CAN_SIDFE_0_SFEC_STF0M_Val + 1 == CAN_SIDFE_0_SFEC_STF1M_Val); - MP_STATIC_ASSERT(CAN_XIDFE_0_EFEC_STF0M_Val + 1 == CAN_XIDFE_0_EFEC_STF1M_Val); -} - -STATIC bool single_address_filter(canio_match_obj_t *match) { - return match->mask == 0 || match->mask == match->address; -} - -STATIC bool standard_filter_in_use(CanMramSidfe *filter) { - return filter->SIDFE_0.bit.SFEC != CAN_SIDFE_0_SFEC_DISABLE_Val; -} - -STATIC bool extended_filter_in_use(CanMramXidfe *filter) { - return filter->XIDFE_0.bit.EFEC != CAN_XIDFE_0_EFEC_DISABLE_Val; -} - -STATIC size_t num_filters_needed(size_t nmatch, canio_match_obj_t **matches, bool extended) { - size_t num_half_filters_needed = 1; - for(size_t i=0; iextended) { - continue; - } - if (single_address_filter(matches[i])) { - num_half_filters_needed += 1; - } else { - num_half_filters_needed += 2; - } - } - return num_half_filters_needed / 2; -} - -STATIC size_t num_filters_available(canio_can_obj_t *can, bool extended) { - size_t available = 0; - if (extended) { - for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->extended_rx_filter); i++) { - if (!extended_filter_in_use(&can->state->extended_rx_filter[i])) { - available++; - } - } - } else { - for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->standard_rx_filter); i++) { - if (!standard_filter_in_use(&can->state->standard_rx_filter[i])) { - available++; - } - } - } - return available; -} - -STATIC void clear_filters(canio_listener_obj_t *self) { - canio_can_obj_t *can = self->can; - int fifo = self->fifo_idx; - - // If it was a global accept, clear it - allow_config_change(can); - if (can->hw->GFC.bit.ANFS == CAN_GFC_ANFS_RXF0 + fifo) { - can->hw->GFC.bit.ANFS = CAN_GFC_ANFS_REJECT_Val; - } - if (can->hw->GFC.bit.ANFE == CAN_GFC_ANFE_RXF0 + fifo) { - can->hw->GFC.bit.ANFE = CAN_GFC_ANFE_REJECT_Val; - } - prevent_config_change(can); - - // For each filter entry, if it pointed at this FIFO set it to DISABLE - for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->extended_rx_filter); i++) { - int val = CAN_XIDFE_0_EFEC_STF0M_Val + fifo; - if (can->state->extended_rx_filter[i].XIDFE_0.bit.EFEC == val) { - can->state->extended_rx_filter[i].XIDFE_0.bit.EFEC = CAN_XIDFE_0_EFEC_DISABLE_Val; - } - } - for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->standard_rx_filter); i++) { - int val = CAN_SIDFE_0_SFEC_STF1M_Val + fifo; - if (can->state->standard_rx_filter[i].SIDFE_0.bit.SFEC == val) { - can->state->standard_rx_filter[i].SIDFE_0.bit.SFEC = CAN_SIDFE_0_SFEC_DISABLE_Val; - } - } -} - -STATIC CanMramXidfe *next_extended_filter(canio_listener_obj_t *self, CanMramXidfe *start) { - CanMramXidfe *end = &self->can->state->extended_rx_filter[MP_ARRAY_SIZE(self->can->state->extended_rx_filter)]; - if (start == NULL) { - start = self->can->state->extended_rx_filter; - } else { - start = start + 1; - } - while (extended_filter_in_use(start)) { - if (start == end) { - return NULL; - } - start = start + 1; - } - return start; -} - -STATIC CanMramSidfe *next_standard_filter(canio_listener_obj_t *self, CanMramSidfe *start) { - CanMramSidfe *end = &self->can->state->standard_rx_filter[MP_ARRAY_SIZE(self->can->state->standard_rx_filter)]; - if (start == NULL) { - start = self->can->state->standard_rx_filter; - } else { - start = start + 1; - } - while (standard_filter_in_use(start)) { - if (start == end) { - return NULL; - } - start = start + 1; - } - return start; -} - -STATIC void install_standard_filter(CanMramSidfe *standard, int id1, int id2, int sfec, int sft) { - assert(standard); - CAN_SIDFE_0_Type val = { - .bit.SFID1 = id1, - .bit.SFID2 = id2, - .bit.SFEC = sfec, - .bit.SFT = sft, - }; - standard->SIDFE_0 = val; -} - -STATIC void install_extended_filter(CanMramXidfe *extended, int id1, int id2, int efec, int eft) { - assert(extended); - CAN_XIDFE_0_Type val0 = { - .bit.EFID1 = id1, - .bit.EFEC = efec, - }; - CAN_XIDFE_1_Type val1 = { - .bit.EFID2 = id2, - .bit.EFT = eft, - }; - // Set entry 0 second, because it has the enable bits (XIDFE_0_EFEC) - extended->XIDFE_1 = val1; - extended->XIDFE_0 = val0; -} - - -#define NO_ADDRESS (-1) -void set_filters(canio_listener_obj_t *self, size_t nmatch, canio_match_obj_t **matches) { - int fifo = self->fifo_idx; - - if (!nmatch) { - allow_config_change(self->can); - self->can->hw->GFC.bit.ANFS = CAN_GFC_ANFS_RXF0_Val + fifo; - self->can->hw->GFC.bit.ANFE = CAN_GFC_ANFE_RXF0_Val + fifo; - self->can->hw->CCCR.bit.CCE = 0; - prevent_config_change(self->can); - return; - } - - CanMramSidfe *standard = next_standard_filter(self, NULL); - CanMramXidfe *extended = next_extended_filter(self, NULL); - - int first_address = NO_ADDRESS; - - // step 1: single address standard matches - // we have to gather up pairs and stuff them in a single filter entry - for(size_t i = 0; iextended) { - continue; - } - if (!single_address_filter(match)) { - continue; - } - if (first_address != NO_ADDRESS) { - install_standard_filter(standard, first_address, match->address, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); - first_address = NO_ADDRESS; - standard = next_standard_filter(self, standard); - } else { - first_address = match->address; - } - } - // step 1.5. odd single address standard match - if (first_address != NO_ADDRESS) { - install_standard_filter(standard, first_address, first_address, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); - standard = next_standard_filter(self, standard); - first_address = NO_ADDRESS; - } - - // step 2: standard mask filter - for(size_t i = 0; iextended) { - continue; - } - if (single_address_filter(match)) { - continue; - } - install_standard_filter(standard, match->address, match->mask, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_CLASSIC_Val); - standard = next_standard_filter(self, standard); - } - - // step 3: single address extended matches - // we have to gather up pairs and stuff them in a single filter entry - for(size_t i = 0; iextended) { - continue; - } - if (!single_address_filter(match)) { - continue; - } - if (first_address != NO_ADDRESS) { - install_extended_filter(extended, first_address, match->address, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); - first_address = NO_ADDRESS; - extended = next_extended_filter(self, extended); - } else { - first_address = match->address; - } - } - // step 3.5. odd single address standard match - if (first_address != NO_ADDRESS) { - install_extended_filter(extended, first_address, first_address, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); - extended = next_extended_filter(self, extended); - first_address = NO_ADDRESS; - } - - // step 4: extended mask filters - for(size_t i = 0; iextended) { - continue; - } - if (single_address_filter(match)) { - continue; - } - install_extended_filter(extended, match->address, match->mask, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_CLASSIC_Val); - extended = next_extended_filter(self, extended); - } - - // phew, easy(!) -} - - -void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout) { - if (!can->fifo0_in_use) { - self->fifo_idx = 0; - self->fifo = can->state->rx0_fifo; - self->hw = (canio_rxfifo_reg_t*)&can->hw->RXF0C; - can->hw->IR.reg = CAN_IR_RF0N | CAN_IR_RF0W | CAN_IR_RF0F | CAN_IR_RF0L; - can->fifo0_in_use = true; - } else if (!can->fifo1_in_use) { - self->fifo_idx = 1; - self->fifo = can->state->rx1_fifo; - self->hw = (canio_rxfifo_reg_t*)&can->hw->RXF1C; - can->fifo1_in_use = true; - can->hw->IR.reg = CAN_IR_RF1N | CAN_IR_RF1W | CAN_IR_RF1F | CAN_IR_RF1L; - } else { - mp_raise_ValueError(translate("All RX FIFOs in use")); - } - - if (!nmatch) { - if (can->hw->GFC.bit.ANFS == CAN_GFC_ANFS_RXF1_Val - self->fifo_idx) { - mp_raise_ValueError(translate("Already have all-matches listener")); - } - if (can->hw->GFC.bit.ANFE == CAN_GFC_ANFE_RXF1_Val - self->fifo_idx) { - mp_raise_ValueError(translate("Already have all-matches listener")); - } - } - - if (num_filters_needed(nmatch, matches, false) > num_filters_available(can, false)) { - mp_raise_ValueError(translate("Filters too complex")); - } - - if (num_filters_needed(nmatch, matches, true) > num_filters_available(can, true)) { - mp_raise_ValueError(translate("Filters too complex")); - } - - // Nothing can fail now so it's safe to assign self->can - self->can = can; - set_filters(self, nmatch, matches); - common_hal_canio_listener_set_timeout(self, timeout); -} - -void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout) { - self->timeout_ms = (int)MICROPY_FLOAT_C_FUN(ceil)(timeout * 1000); -} - -float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self) { - return self->timeout_ms / 1000.0f; -} - -void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self) { - if (!self->can) { - raise_deinited_error(); - } - common_hal_canio_can_check_for_deinit(self->can); -} - -int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self) { - return self->hw->RXFS.bit.F0FL; -} - -bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_message_obj_t *message) { - if (!common_hal_canio_listener_in_waiting(self)) { - uint64_t deadline = supervisor_ticks_ms64() + self->timeout_ms; - do { - if (supervisor_ticks_ms64() > deadline) { - return false; - } - } while (!common_hal_canio_listener_in_waiting(self)); - } - int index = self->hw->RXFS.bit.F0GI; - canio_can_fifo_t *hw_message = &self->fifo[index]; - message->extended = hw_message->rxb0.bit.XTD; - if (message->extended) { - message->id = hw_message->rxb0.bit.ID; - } else { - message->id = hw_message->rxb0.bit.ID >> 18; // short addresses are left-justified - } - message->rtr = hw_message->rxb0.bit.RTR; - message->size = hw_message->rxb1.bit.DLC; - if (!message->rtr) { - memcpy(message->data, hw_message->data, message->size); - } - self->hw->RXFA.bit.F0AI = index; - return true; -} - -void common_hal_canio_listener_deinit(canio_listener_obj_t *self) { - if (self->can) { - clear_filters(self); - if (self->fifo_idx == 0) { - self->can->fifo0_in_use = false; - } - if (self->fifo_idx == 1) { - self->can->fifo1_in_use = false; - } - } - self->fifo_idx = -1; - self->fifo = NULL; - self->can = NULL; - self->hw = NULL; -} diff --git a/ports/atmel-samd/common-hal/_canio/Listener.h b/ports/atmel-samd/common-hal/_canio/Listener.h deleted file mode 100644 index cc6770e6e..000000000 --- a/ports/atmel-samd/common-hal/_canio/Listener.h +++ /dev/null @@ -1,53 +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. - */ - -#pragma once - -#include "common-hal/_canio/CAN.h" -#include "shared-module/_canio/Match.h" - -typedef struct { - __IO CAN_RXF0C_Type RXFC; /**< \brief (R/W 32) Rx FIFO n Configuration */ - __I CAN_RXF0S_Type RXFS; /**< \brief (R/ 32) Rx FIFO n Status */ - __IO CAN_RXF0A_Type RXFA; /**< \brief (R/W 32) Rx FIFO n Acknowledge */ -} canio_rxfifo_reg_t; - -typedef struct { - mp_obj_base_t base; - canio_can_obj_t *can; - canio_can_fifo_t *fifo; - canio_rxfifo_reg_t *hw; - uint32_t timeout_ms; - uint8_t fifo_idx; -} canio_listener_obj_t; - -void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout); -void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self); -void common_hal_canio_listener_deinit(canio_listener_obj_t *self); -bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_message_obj_t *message); -int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self); -float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self); -void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout); diff --git a/ports/atmel-samd/common-hal/_canio/__init__.c b/ports/atmel-samd/common-hal/_canio/__init__.c deleted file mode 100644 index 7932bfc2d..000000000 --- a/ports/atmel-samd/common-hal/_canio/__init__.c +++ /dev/null @@ -1,25 +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. - */ diff --git a/ports/atmel-samd/common-hal/_canio/__init__.h b/ports/atmel-samd/common-hal/_canio/__init__.h deleted file mode 100644 index cb491ab9e..000000000 --- a/ports/atmel-samd/common-hal/_canio/__init__.h +++ /dev/null @@ -1,67 +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. - */ - -#pragma once - -#include "hal/utils/include/utils.h" -#include "component/can.h" - -#define COMMON_HAL_CANIO_MAX_MESSAGE_LENGTH (8) -#define COMMON_HAL_CANIO_RX_FIFO_SIZE (3) -#define COMMON_HAL_CANIO_RX_FILTER_SIZE (4) -#define COMMON_HAL_CANIO_TX_FIFO_SIZE (1) - -// This appears to be a typo (transposition error) in the ASF4 headers -// It's called the "Extended ID Filter Entry" -typedef CanMramXifde CanMramXidfe; - -typedef struct canio_listener canio_listener_t; -typedef struct canio_can canio_can_t; - -typedef struct { - union { - CAN_RXBE_0_Type rxb0; - CAN_TXBE_0_Type txb0; - CAN_RXF0E_0_Type rxf0; - }; - union { - CAN_RXBE_1_Type rxb1; - CAN_TXBE_1_Type txb1; - CAN_RXF0E_1_Type rxf1; - }; - COMPILER_ALIGNED(4) - uint8_t data[COMMON_HAL_CANIO_MAX_MESSAGE_LENGTH]; -} canio_can_fifo_t; - -typedef uint32_t canio_can_filter_t; - -typedef struct { - canio_can_fifo_t tx_fifo[COMMON_HAL_CANIO_TX_FIFO_SIZE]; - canio_can_fifo_t rx0_fifo[COMMON_HAL_CANIO_RX_FIFO_SIZE]; - canio_can_fifo_t rx1_fifo[COMMON_HAL_CANIO_RX_FIFO_SIZE]; - CanMramSidfe standard_rx_filter[COMMON_HAL_CANIO_RX_FILTER_SIZE]; - CanMramXifde extended_rx_filter[COMMON_HAL_CANIO_RX_FILTER_SIZE]; -} canio_can_state_t; diff --git a/ports/atmel-samd/common-hal/canio/CAN.c b/ports/atmel-samd/common-hal/canio/CAN.c new file mode 100644 index 000000000..01cc03dea --- /dev/null +++ b/ports/atmel-samd/common-hal/canio/CAN.c @@ -0,0 +1,445 @@ +/* + * 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/runtime.h" +#include "py/mperrno.h" + +#include "peripheral_clk_config.h" + +#include "common-hal/canio/CAN.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "supervisor/port.h" + +#include "component/can.h" + +#include "genhdr/candata.h" + +STATIC Can * const can_insts[] = CAN_INSTS; + +STATIC canio_can_obj_t *can_objs[MP_ARRAY_SIZE(can_insts)]; + +// This must be placed in the first 64kB of RAM +STATIC COMPILER_SECTION(".canram") canio_can_state_t can_state[MP_ARRAY_SIZE(can_insts)]; + +void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent) +{ + mcu_pin_function_t *tx_function = mcu_find_pin_function(can_tx, tx, -1, MP_QSTR_tx); + int instance = tx_function->instance; + + mcu_pin_function_t *rx_function = mcu_find_pin_function(can_rx, rx, instance, MP_QSTR_rx); + + const uint32_t can_frequency = CONF_CAN0_FREQUENCY; + +#define DIV_ROUND(a, b) (((a) + (b)/2) / (b)) +#define DIV_ROUND_UP(a, b) (((a) + (b) - 1) / (b)) + + uint32_t clocks_per_bit = DIV_ROUND(can_frequency, baudrate); + uint32_t clocks_to_sample = DIV_ROUND(clocks_per_bit * 7, 8); + uint32_t clocks_after_sample = clocks_per_bit - clocks_to_sample; + uint32_t divisor = MAX(DIV_ROUND_UP(clocks_to_sample, 256), DIV_ROUND_UP(clocks_after_sample, 128)); + if (divisor > 32) { + mp_raise_OSError(MP_EINVAL); // baudrate cannot be attained (16kHz or something is lower bound, should never happen) + } + + gpio_set_pin_direction(tx_function->pin, GPIO_DIRECTION_OUT); + gpio_set_pin_function(tx_function->pin, tx_function->function); + common_hal_never_reset_pin(tx_function->obj); + + gpio_set_pin_direction(rx_function->pin, GPIO_DIRECTION_IN); + gpio_set_pin_function(rx_function->pin, rx_function->function); + common_hal_never_reset_pin(rx_function->obj); + + self->tx_pin_number = tx ? common_hal_mcu_pin_number(tx) : COMMON_HAL_MCU_NO_PIN; + self->rx_pin_number = rx ? common_hal_mcu_pin_number(rx) : COMMON_HAL_MCU_NO_PIN; + self->hw = can_insts[instance]; + self->state = &can_state[instance]; + + self->loopback = loopback; + self->silent = silent; + + // Allow configuration change + hri_can_set_CCCR_INIT_bit(self->hw); + while (hri_can_get_CCCR_INIT_bit(self->hw) == 0) { + } + hri_can_set_CCCR_CCE_bit(self->hw); + + if (instance == 0) { + hri_mclk_set_AHBMASK_CAN0_bit(MCLK); + hri_gclk_write_PCHCTRL_reg(GCLK, CAN0_GCLK_ID, CONF_GCLK_CAN0_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos)); + + NVIC_DisableIRQ(CAN0_IRQn); + NVIC_ClearPendingIRQ(CAN0_IRQn); + NVIC_EnableIRQ(CAN0_IRQn); + hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); +#ifdef CAN1_GCLK_ID + } else if (instance == 1) { + hri_mclk_set_AHBMASK_CAN1_bit(MCLK); + hri_gclk_write_PCHCTRL_reg(GCLK, CAN1_GCLK_ID, CONF_GCLK_CAN1_SRC | (1 << GCLK_PCHCTRL_CHEN_Pos)); + + NVIC_DisableIRQ(CAN1_IRQn); + NVIC_ClearPendingIRQ(CAN1_IRQn); + NVIC_EnableIRQ(CAN1_IRQn); + hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); +#endif + } + + self->hw->CCCR.bit.FDOE = 0; // neither FD nor Bit Rate Switch enabled + self->hw->CCCR.bit.BRSE = 0; + + hri_can_write_MRCFG_reg(self->hw, CAN_MRCFG_QOS(CAN_MRCFG_QOS_DISABLE_Val)); // QoS disabled (no sensitive operation) + + // A "nominal bit" is a header bit. With dual rate CAN FD, this is a slower rate + { + CAN_NBTP_Type btp = { + // 0 means "1 tq", but 2 is subtracted from NTSEG1 for the + // fixed 1 "SYNC" tq + .bit.NTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 2, + .bit.NTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1, + .bit.NBRP = divisor - 1, + .bit.NSJW = DIV_ROUND(clocks_after_sample, divisor * 4), + }; + hri_can_write_NBTP_reg(self->hw, btp.reg); + } + + // A "data bit" is a data bit :) with dula rate CAN FD, this is a higher + // rate. However, CAN FD is not implemented in CircuitPython, and this is + // the same rate as the "nominal rate". + { + CAN_DBTP_Type btp = { + .bit.DTSEG1 = DIV_ROUND(clocks_to_sample, divisor) - 1, + .bit.DTSEG2 = DIV_ROUND(clocks_after_sample, divisor) - 1, + .bit.DBRP = divisor - 1, + .bit.DSJW = DIV_ROUND(clocks_after_sample, divisor * 4), + }; + hri_can_write_DBTP_reg(self->hw, btp.reg); + } + + { + CAN_RXF0C_Type rxf = { + .bit.F0SA = (uint32_t)self->state->rx0_fifo, + .bit.F0S = COMMON_HAL_CANIO_RX_FIFO_SIZE, + }; + hri_can_write_RXF0C_reg(self->hw, rxf.reg); + } + + { + CAN_RXF1C_Type rxf = { + .bit.F1SA = (uint32_t)self->state->rx1_fifo, + .bit.F1S = COMMON_HAL_CANIO_RX_FIFO_SIZE, + }; + hri_can_write_RXF1C_reg(self->hw, rxf.reg); + } + + // All RX data has an 8 byte payload (max) + { + CAN_RXESC_Type esc = { + .bit.F0DS = CAN_RXESC_F0DS_DATA8_Val, + .bit.F1DS = CAN_RXESC_F1DS_DATA8_Val, + .bit.RBDS = CAN_RXESC_RBDS_DATA8_Val, + }; + hri_can_write_RXESC_reg(self->hw, esc.reg); + } + + // All TX data has an 8 byte payload (max) + { + CAN_TXESC_Type esc = { + .bit.TBDS = CAN_TXESC_TBDS_DATA8_Val, + }; + hri_can_write_TXESC_reg(self->hw, esc.reg); + } + + { + CAN_TXBC_Type bc = { + .bit.TBSA = (uint32_t)self->state->tx_fifo, + .bit.NDTB = COMMON_HAL_CANIO_TX_FIFO_SIZE, + .bit.TFQM = 0, // Messages are transmitted in the order submitted + }; + hri_can_write_TXBC_reg(self->hw, bc.reg); + } + + { + CAN_TXEFC_Type efc = { + .bit.EFS = 0, + }; + hri_can_write_TXEFC_reg(self->hw, efc.reg); + } + + { + CAN_GFC_Type gfc = { + .bit.RRFE = 1, + .bit.ANFS = CAN_GFC_ANFS_REJECT_Val, + .bit.ANFE = CAN_GFC_ANFE_REJECT_Val, + }; + hri_can_write_GFC_reg(self->hw, gfc.reg); + } + + { + CAN_SIDFC_Type dfc = { + .bit.LSS = COMMON_HAL_CANIO_RX_FILTER_SIZE, + .bit.FLSSA = (uint32_t)self->state->standard_rx_filter + }; + hri_can_write_SIDFC_reg(self->hw, dfc.reg); + } + + { + CAN_XIDFC_Type dfc = { + .bit.LSE = COMMON_HAL_CANIO_RX_FILTER_SIZE, + .bit.FLESA = (uint32_t)self->state->extended_rx_filter + }; + hri_can_write_XIDFC_reg(self->hw, dfc.reg); + } + + { + CAN_IE_Type ie = { + .bit.EWE = 1, + .bit.EPE = 1, + .bit.BOE = 1, + }; + hri_can_write_IE_reg(self->hw, ie.reg); + } + + hri_can_write_XIDAM_reg(self->hw, CAN_XIDAM_RESETVALUE); + +// silent: The CAN is set in Bus Monitoring Mode by programming CCCR.MON to '1'. (tx pin unused) +// external loopback: The CAN can be set in External Loop Back Mode by programming TEST.LBCK and CCCR.MON to '1'. (rx pin unused) +// internal loopback (silent loopback): Internal Loop Back Mode is entered by programming bits TEST.LBCK and CCCR.MON to '1'. (tx, rx unused) + self->hw->CCCR.bit.MON = silent; + self->hw->CCCR.bit.TEST = loopback; + self->hw->TEST.bit.LBCK = loopback; + + if (instance == 0) { + NVIC_DisableIRQ(CAN0_IRQn); + NVIC_ClearPendingIRQ(CAN0_IRQn); + NVIC_EnableIRQ(CAN0_IRQn); +#ifdef CAN1_GCLK_ID + } else if (instance == 1) { + NVIC_DisableIRQ(CAN1_IRQn); + NVIC_ClearPendingIRQ(CAN1_IRQn); + NVIC_EnableIRQ(CAN1_IRQn); +#endif + } + + hri_can_write_ILE_reg(self->hw, CAN_ILE_EINT0); + // Prevent configuration change + hri_can_clear_CCCR_CCE_bit(self->hw); + hri_can_clear_CCCR_INIT_bit(self->hw); + while (hri_can_get_CCCR_INIT_bit(self->hw)) { + } + + can_objs[instance] = self; +} + +bool common_hal_canio_can_loopback_get(canio_can_obj_t *self) +{ + return self->loopback; +} + +int common_hal_canio_can_baudrate_get(canio_can_obj_t *self) +{ + return self->baudrate; +} + +int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self) +{ + return self->hw->ECR.bit.TEC; +} + +int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self) +{ + return self->hw->ECR.bit.REC; +} + +int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self) +{ + return self->error_warning_state_count; +} + +int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self) +{ + return self->error_passive_state_count; +} + +int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self) +{ + return self->bus_off_state_count; +} + +canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self) { + CAN_PSR_Type psr = self->hw->PSR; + if (psr.bit.BO) { + return BUS_STATE_OFF; + } + if (psr.bit.EP) { + return BUS_STATE_ERROR_PASSIVE; + } + if (psr.bit.EW) { + return BUS_STATE_ERROR_WARNING; + } + return BUS_STATE_ERROR_ACTIVE; +} + +void common_hal_canio_can_restart(canio_can_obj_t *self) { + if (!self->hw->PSR.bit.BO) { + return; + } + + hri_can_clear_CCCR_INIT_bit(self->hw); + while (hri_can_get_CCCR_INIT_bit(self->hw)) { + } +} + +bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self) { + return self->auto_restart; +} + +void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool value) { + self->auto_restart = value; +} + +static void maybe_auto_restart(canio_can_obj_t *self) { + if (self->auto_restart) { + common_hal_canio_can_restart(self); + } +} + +void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message) +{ + maybe_auto_restart(self); + + // We have just one dedicated TX buffer, use it! + canio_can_fifo_t *ent = &self->state->tx_fifo[0]; + + ent->txb0.bit.ESI = false; + ent->txb0.bit.XTD = message->extended; + ent->txb0.bit.RTR = message->rtr; + if (message->extended) { + ent->txb0.bit.ID = message->id << 18; + } else { + ent->txb0.bit.ID = message->id << 18; // short addresses are left-justified + } + + ent->txb1.bit.MM = 0; // "message marker" + ent->txb1.bit.EFC = 0; // don't store fifo events to event queue + ent->txb1.bit.FDF = 0; // Classic CAN format + ent->txb1.bit.BRS = 0; // No bit rate switching + ent->txb1.bit.DLC = message->size; + + if (!message->rtr) { + memcpy(ent->data, message->data, message->size); + } + + // TX buffer add request + self->hw->TXBAR.reg = 1; + + // wait 8ms (hard coded for now) for TX to occur + uint64_t deadline = port_get_raw_ticks(NULL) + 8; + while (port_get_raw_ticks(NULL) < deadline && !(self->hw->TXBTO.reg & 1)) { + RUN_BACKGROUND_TASKS; + } +} + +bool common_hal_canio_can_silent_get(canio_can_obj_t *self) { + return self->silent; +} + +bool common_hal_canio_can_deinited(canio_can_obj_t *self) { + return !self->hw; +} + +void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self) { + if (common_hal_canio_can_deinited(self)) { + raise_deinited_error(); + } +} + +void common_hal_canio_can_deinit(canio_can_obj_t *self) +{ + if (self->hw) { + hri_can_set_CCCR_INIT_bit(self->hw); + self->hw = 0; + } + if (self->rx_pin_number != COMMON_HAL_MCU_NO_PIN) { + reset_pin_number(self->rx_pin_number); + self->rx_pin_number = COMMON_HAL_MCU_NO_PIN; + } + if (self->tx_pin_number != COMMON_HAL_MCU_NO_PIN) { + reset_pin_number(self->tx_pin_number); + self->tx_pin_number = COMMON_HAL_MCU_NO_PIN; + } +} + +void common_hal_canio_reset(void) { + memset(can_state, 0, sizeof(can_state)); + + for (size_t i=0; ierror_warning_state_count += 1; + } + if (ir & CAN_IE_EPE) { + self->error_passive_state_count += 1; + } + if (ir & CAN_IE_BOE) { + self->bus_off_state_count += 1; + } + + /* Acknowledge interrupt */ + hri_can_write_IR_reg(hw, ir); +} + +__attribute__((used)) +void CAN0_Handler(void) { + can_handler(0); +} + +#ifdef CAN1_GCLK_ID +__attribute__((used)) +void CAN1_Handler(void) { + can_handler(1); +} +#endif diff --git a/ports/atmel-samd/common-hal/canio/CAN.h b/ports/atmel-samd/common-hal/canio/CAN.h new file mode 100644 index 000000000..cdea60e7d --- /dev/null +++ b/ports/atmel-samd/common-hal/canio/CAN.h @@ -0,0 +1,55 @@ +/* + * 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/canio/__init__.h" +#include "shared-bindings/canio/CAN.h" +#include "component/can.h" +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/canio/__init__.h" +#include "shared-module/canio/Message.h" + +#define COMMON_HAL_CAN_RX_FIFO_LEN (2) +#define COMMON_HAL_CAN_TX_FIFO_LEN (2) + +typedef struct canio_can_obj { + mp_obj_base_t base; + Can *hw; + canio_can_state_t *state; + volatile uint32_t error_warning_state_count; + volatile uint32_t error_passive_state_count; + volatile uint32_t bus_off_state_count; + int baudrate; + uint8_t rx_pin_number:8; + uint8_t tx_pin_number:8; + bool loopback:1; + bool silent:1; + bool auto_restart:1; + bool fifo0_in_use:1; + bool fifo1_in_use:1; +} canio_can_obj_t; diff --git a/ports/atmel-samd/common-hal/canio/Listener.c b/ports/atmel-samd/common-hal/canio/Listener.c new file mode 100644 index 000000000..bf8b3288d --- /dev/null +++ b/ports/atmel-samd/common-hal/canio/Listener.c @@ -0,0 +1,391 @@ +/* + * 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 + +#include "py/obj.h" +#include "py/runtime.h" + +#include "common-hal/canio/__init__.h" +#include "common-hal/canio/Listener.h" +#include "shared-bindings/util.h" +#include "supervisor/shared/tick.h" +#include "component/can.h" + +STATIC void allow_config_change(canio_can_obj_t *can) { + can->hw->CCCR.bit.INIT = 1; + while (!can->hw->CCCR.bit.INIT) { + } + can->hw->CCCR.bit.CCE = 1; +} + +STATIC void prevent_config_change(canio_can_obj_t *can) { + can->hw->CCCR.bit.CCE = 0; + can->hw->CCCR.bit.INIT = 0; + while (can->hw->CCCR.bit.INIT) { + } +} + +__attribute__((unused)) +STATIC void static_assertions(void) { + MP_STATIC_ASSERT(CAN_GFC_ANFE_RXF0_Val + 1 == CAN_GFC_ANFE_RXF1_Val); + MP_STATIC_ASSERT(CAN_GFC_ANFS_RXF0_Val + 1 == CAN_GFC_ANFS_RXF1_Val); + MP_STATIC_ASSERT(CAN_SIDFE_0_SFEC_STF0M_Val + 1 == CAN_SIDFE_0_SFEC_STF1M_Val); + MP_STATIC_ASSERT(CAN_XIDFE_0_EFEC_STF0M_Val + 1 == CAN_XIDFE_0_EFEC_STF1M_Val); +} + +STATIC bool single_address_filter(canio_match_obj_t *match) { + return match->mask == 0 || match->mask == match->address; +} + +STATIC bool standard_filter_in_use(CanMramSidfe *filter) { + return filter->SIDFE_0.bit.SFEC != CAN_SIDFE_0_SFEC_DISABLE_Val; +} + +STATIC bool extended_filter_in_use(CanMramXidfe *filter) { + return filter->XIDFE_0.bit.EFEC != CAN_XIDFE_0_EFEC_DISABLE_Val; +} + +STATIC size_t num_filters_needed(size_t nmatch, canio_match_obj_t **matches, bool extended) { + size_t num_half_filters_needed = 1; + for(size_t i=0; iextended) { + continue; + } + if (single_address_filter(matches[i])) { + num_half_filters_needed += 1; + } else { + num_half_filters_needed += 2; + } + } + return num_half_filters_needed / 2; +} + +STATIC size_t num_filters_available(canio_can_obj_t *can, bool extended) { + size_t available = 0; + if (extended) { + for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->extended_rx_filter); i++) { + if (!extended_filter_in_use(&can->state->extended_rx_filter[i])) { + available++; + } + } + } else { + for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->standard_rx_filter); i++) { + if (!standard_filter_in_use(&can->state->standard_rx_filter[i])) { + available++; + } + } + } + return available; +} + +STATIC void clear_filters(canio_listener_obj_t *self) { + canio_can_obj_t *can = self->can; + int fifo = self->fifo_idx; + + // If it was a global accept, clear it + allow_config_change(can); + if (can->hw->GFC.bit.ANFS == CAN_GFC_ANFS_RXF0 + fifo) { + can->hw->GFC.bit.ANFS = CAN_GFC_ANFS_REJECT_Val; + } + if (can->hw->GFC.bit.ANFE == CAN_GFC_ANFE_RXF0 + fifo) { + can->hw->GFC.bit.ANFE = CAN_GFC_ANFE_REJECT_Val; + } + prevent_config_change(can); + + // For each filter entry, if it pointed at this FIFO set it to DISABLE + for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->extended_rx_filter); i++) { + int val = CAN_XIDFE_0_EFEC_STF0M_Val + fifo; + if (can->state->extended_rx_filter[i].XIDFE_0.bit.EFEC == val) { + can->state->extended_rx_filter[i].XIDFE_0.bit.EFEC = CAN_XIDFE_0_EFEC_DISABLE_Val; + } + } + for(size_t i = 0; i < MP_ARRAY_SIZE(can->state->standard_rx_filter); i++) { + int val = CAN_SIDFE_0_SFEC_STF1M_Val + fifo; + if (can->state->standard_rx_filter[i].SIDFE_0.bit.SFEC == val) { + can->state->standard_rx_filter[i].SIDFE_0.bit.SFEC = CAN_SIDFE_0_SFEC_DISABLE_Val; + } + } +} + +STATIC CanMramXidfe *next_extended_filter(canio_listener_obj_t *self, CanMramXidfe *start) { + CanMramXidfe *end = &self->can->state->extended_rx_filter[MP_ARRAY_SIZE(self->can->state->extended_rx_filter)]; + if (start == NULL) { + start = self->can->state->extended_rx_filter; + } else { + start = start + 1; + } + while (extended_filter_in_use(start)) { + if (start == end) { + return NULL; + } + start = start + 1; + } + return start; +} + +STATIC CanMramSidfe *next_standard_filter(canio_listener_obj_t *self, CanMramSidfe *start) { + CanMramSidfe *end = &self->can->state->standard_rx_filter[MP_ARRAY_SIZE(self->can->state->standard_rx_filter)]; + if (start == NULL) { + start = self->can->state->standard_rx_filter; + } else { + start = start + 1; + } + while (standard_filter_in_use(start)) { + if (start == end) { + return NULL; + } + start = start + 1; + } + return start; +} + +STATIC void install_standard_filter(CanMramSidfe *standard, int id1, int id2, int sfec, int sft) { + assert(standard); + CAN_SIDFE_0_Type val = { + .bit.SFID1 = id1, + .bit.SFID2 = id2, + .bit.SFEC = sfec, + .bit.SFT = sft, + }; + standard->SIDFE_0 = val; +} + +STATIC void install_extended_filter(CanMramXidfe *extended, int id1, int id2, int efec, int eft) { + assert(extended); + CAN_XIDFE_0_Type val0 = { + .bit.EFID1 = id1, + .bit.EFEC = efec, + }; + CAN_XIDFE_1_Type val1 = { + .bit.EFID2 = id2, + .bit.EFT = eft, + }; + // Set entry 0 second, because it has the enable bits (XIDFE_0_EFEC) + extended->XIDFE_1 = val1; + extended->XIDFE_0 = val0; +} + + +#define NO_ADDRESS (-1) +void set_filters(canio_listener_obj_t *self, size_t nmatch, canio_match_obj_t **matches) { + int fifo = self->fifo_idx; + + if (!nmatch) { + allow_config_change(self->can); + self->can->hw->GFC.bit.ANFS = CAN_GFC_ANFS_RXF0_Val + fifo; + self->can->hw->GFC.bit.ANFE = CAN_GFC_ANFE_RXF0_Val + fifo; + self->can->hw->CCCR.bit.CCE = 0; + prevent_config_change(self->can); + return; + } + + CanMramSidfe *standard = next_standard_filter(self, NULL); + CanMramXidfe *extended = next_extended_filter(self, NULL); + + int first_address = NO_ADDRESS; + + // step 1: single address standard matches + // we have to gather up pairs and stuff them in a single filter entry + for(size_t i = 0; iextended) { + continue; + } + if (!single_address_filter(match)) { + continue; + } + if (first_address != NO_ADDRESS) { + install_standard_filter(standard, first_address, match->address, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); + first_address = NO_ADDRESS; + standard = next_standard_filter(self, standard); + } else { + first_address = match->address; + } + } + // step 1.5. odd single address standard match + if (first_address != NO_ADDRESS) { + install_standard_filter(standard, first_address, first_address, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); + standard = next_standard_filter(self, standard); + first_address = NO_ADDRESS; + } + + // step 2: standard mask filter + for(size_t i = 0; iextended) { + continue; + } + if (single_address_filter(match)) { + continue; + } + install_standard_filter(standard, match->address, match->mask, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_CLASSIC_Val); + standard = next_standard_filter(self, standard); + } + + // step 3: single address extended matches + // we have to gather up pairs and stuff them in a single filter entry + for(size_t i = 0; iextended) { + continue; + } + if (!single_address_filter(match)) { + continue; + } + if (first_address != NO_ADDRESS) { + install_extended_filter(extended, first_address, match->address, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); + first_address = NO_ADDRESS; + extended = next_extended_filter(self, extended); + } else { + first_address = match->address; + } + } + // step 3.5. odd single address standard match + if (first_address != NO_ADDRESS) { + install_extended_filter(extended, first_address, first_address, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); + extended = next_extended_filter(self, extended); + first_address = NO_ADDRESS; + } + + // step 4: extended mask filters + for(size_t i = 0; iextended) { + continue; + } + if (single_address_filter(match)) { + continue; + } + install_extended_filter(extended, match->address, match->mask, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_CLASSIC_Val); + extended = next_extended_filter(self, extended); + } + + // phew, easy(!) +} + + +void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout) { + if (!can->fifo0_in_use) { + self->fifo_idx = 0; + self->fifo = can->state->rx0_fifo; + self->hw = (canio_rxfifo_reg_t*)&can->hw->RXF0C; + can->hw->IR.reg = CAN_IR_RF0N | CAN_IR_RF0W | CAN_IR_RF0F | CAN_IR_RF0L; + can->fifo0_in_use = true; + } else if (!can->fifo1_in_use) { + self->fifo_idx = 1; + self->fifo = can->state->rx1_fifo; + self->hw = (canio_rxfifo_reg_t*)&can->hw->RXF1C; + can->fifo1_in_use = true; + can->hw->IR.reg = CAN_IR_RF1N | CAN_IR_RF1W | CAN_IR_RF1F | CAN_IR_RF1L; + } else { + mp_raise_ValueError(translate("All RX FIFOs in use")); + } + + if (!nmatch) { + if (can->hw->GFC.bit.ANFS == CAN_GFC_ANFS_RXF1_Val - self->fifo_idx) { + mp_raise_ValueError(translate("Already have all-matches listener")); + } + if (can->hw->GFC.bit.ANFE == CAN_GFC_ANFE_RXF1_Val - self->fifo_idx) { + mp_raise_ValueError(translate("Already have all-matches listener")); + } + } + + if (num_filters_needed(nmatch, matches, false) > num_filters_available(can, false)) { + mp_raise_ValueError(translate("Filters too complex")); + } + + if (num_filters_needed(nmatch, matches, true) > num_filters_available(can, true)) { + mp_raise_ValueError(translate("Filters too complex")); + } + + // Nothing can fail now so it's safe to assign self->can + self->can = can; + set_filters(self, nmatch, matches); + common_hal_canio_listener_set_timeout(self, timeout); +} + +void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout) { + self->timeout_ms = (int)MICROPY_FLOAT_C_FUN(ceil)(timeout * 1000); +} + +float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self) { + return self->timeout_ms / 1000.0f; +} + +void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self) { + if (!self->can) { + raise_deinited_error(); + } + common_hal_canio_can_check_for_deinit(self->can); +} + +int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self) { + return self->hw->RXFS.bit.F0FL; +} + +bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_message_obj_t *message) { + if (!common_hal_canio_listener_in_waiting(self)) { + uint64_t deadline = supervisor_ticks_ms64() + self->timeout_ms; + do { + if (supervisor_ticks_ms64() > deadline) { + return false; + } + } while (!common_hal_canio_listener_in_waiting(self)); + } + int index = self->hw->RXFS.bit.F0GI; + canio_can_fifo_t *hw_message = &self->fifo[index]; + message->extended = hw_message->rxb0.bit.XTD; + if (message->extended) { + message->id = hw_message->rxb0.bit.ID; + } else { + message->id = hw_message->rxb0.bit.ID >> 18; // short addresses are left-justified + } + message->rtr = hw_message->rxb0.bit.RTR; + message->size = hw_message->rxb1.bit.DLC; + if (!message->rtr) { + memcpy(message->data, hw_message->data, message->size); + } + self->hw->RXFA.bit.F0AI = index; + return true; +} + +void common_hal_canio_listener_deinit(canio_listener_obj_t *self) { + if (self->can) { + clear_filters(self); + if (self->fifo_idx == 0) { + self->can->fifo0_in_use = false; + } + if (self->fifo_idx == 1) { + self->can->fifo1_in_use = false; + } + } + self->fifo_idx = -1; + self->fifo = NULL; + self->can = NULL; + self->hw = NULL; +} diff --git a/ports/atmel-samd/common-hal/canio/Listener.h b/ports/atmel-samd/common-hal/canio/Listener.h new file mode 100644 index 000000000..a51a9fc37 --- /dev/null +++ b/ports/atmel-samd/common-hal/canio/Listener.h @@ -0,0 +1,53 @@ +/* + * 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 "common-hal/canio/CAN.h" +#include "shared-module/canio/Match.h" + +typedef struct { + __IO CAN_RXF0C_Type RXFC; /**< \brief (R/W 32) Rx FIFO n Configuration */ + __I CAN_RXF0S_Type RXFS; /**< \brief (R/ 32) Rx FIFO n Status */ + __IO CAN_RXF0A_Type RXFA; /**< \brief (R/W 32) Rx FIFO n Acknowledge */ +} canio_rxfifo_reg_t; + +typedef struct { + mp_obj_base_t base; + canio_can_obj_t *can; + canio_can_fifo_t *fifo; + canio_rxfifo_reg_t *hw; + uint32_t timeout_ms; + uint8_t fifo_idx; +} canio_listener_obj_t; + +void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout); +void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self); +void common_hal_canio_listener_deinit(canio_listener_obj_t *self); +bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_message_obj_t *message); +int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self); +float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self); +void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout); diff --git a/ports/atmel-samd/common-hal/canio/__init__.c b/ports/atmel-samd/common-hal/canio/__init__.c new file mode 100644 index 000000000..7932bfc2d --- /dev/null +++ b/ports/atmel-samd/common-hal/canio/__init__.c @@ -0,0 +1,25 @@ +/* + * 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. + */ diff --git a/ports/atmel-samd/common-hal/canio/__init__.h b/ports/atmel-samd/common-hal/canio/__init__.h new file mode 100644 index 000000000..cb491ab9e --- /dev/null +++ b/ports/atmel-samd/common-hal/canio/__init__.h @@ -0,0 +1,67 @@ +/* + * 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 "hal/utils/include/utils.h" +#include "component/can.h" + +#define COMMON_HAL_CANIO_MAX_MESSAGE_LENGTH (8) +#define COMMON_HAL_CANIO_RX_FIFO_SIZE (3) +#define COMMON_HAL_CANIO_RX_FILTER_SIZE (4) +#define COMMON_HAL_CANIO_TX_FIFO_SIZE (1) + +// This appears to be a typo (transposition error) in the ASF4 headers +// It's called the "Extended ID Filter Entry" +typedef CanMramXifde CanMramXidfe; + +typedef struct canio_listener canio_listener_t; +typedef struct canio_can canio_can_t; + +typedef struct { + union { + CAN_RXBE_0_Type rxb0; + CAN_TXBE_0_Type txb0; + CAN_RXF0E_0_Type rxf0; + }; + union { + CAN_RXBE_1_Type rxb1; + CAN_TXBE_1_Type txb1; + CAN_RXF0E_1_Type rxf1; + }; + COMPILER_ALIGNED(4) + uint8_t data[COMMON_HAL_CANIO_MAX_MESSAGE_LENGTH]; +} canio_can_fifo_t; + +typedef uint32_t canio_can_filter_t; + +typedef struct { + canio_can_fifo_t tx_fifo[COMMON_HAL_CANIO_TX_FIFO_SIZE]; + canio_can_fifo_t rx0_fifo[COMMON_HAL_CANIO_RX_FIFO_SIZE]; + canio_can_fifo_t rx1_fifo[COMMON_HAL_CANIO_RX_FIFO_SIZE]; + CanMramSidfe standard_rx_filter[COMMON_HAL_CANIO_RX_FILTER_SIZE]; + CanMramXifde extended_rx_filter[COMMON_HAL_CANIO_RX_FILTER_SIZE]; +} canio_can_state_t; diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 2614dc011..98fa7a5f2 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -143,7 +143,7 @@ ifeq ($(CIRCUITPY_CAMERA),1) SRC_PATTERNS += camera/% endif ifeq ($(CIRCUITPY_CANIO),1) -SRC_PATTERNS += _canio/% +SRC_PATTERNS += canio/% endif ifeq ($(CIRCUITPY_COUNTIO),1) SRC_PATTERNS += countio/% @@ -318,9 +318,9 @@ SRC_COMMON_HAL_ALL = \ busio/__init__.c \ camera/__init__.c \ camera/Camera.c \ - _canio/CAN.c \ - _canio/Listener.c \ - _canio/__init__.c \ + canio/CAN.c \ + canio/Listener.c \ + canio/__init__.c \ countio/Counter.c \ countio/__init__.c \ digitalio/DigitalInOut.c \ @@ -390,7 +390,7 @@ $(filter $(SRC_PATTERNS), \ _bleio/Address.c \ _bleio/Attribute.c \ _bleio/ScanEntry.c \ - _canio/Match.c \ + canio/Match.c \ _eve/__init__.c \ camera/ImageFormat.c \ digitalio/Direction.c \ @@ -409,8 +409,8 @@ SRC_SHARED_MODULE_ALL = \ _bleio/Attribute.c \ _bleio/ScanEntry.c \ _bleio/ScanResults.c \ - _canio/Match.c \ - _canio/Message.c \ + canio/Match.c \ + canio/Message.c \ _eve/__init__.c \ _pixelbuf/PixelBuf.c \ _pixelbuf/__init__.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index d1b12f354..0583ae1c9 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -338,7 +338,7 @@ extern const struct _mp_obj_module_t camera_module; #if CIRCUITPY_CANIO extern const struct _mp_obj_module_t canio_module; -#define CANIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR__canio), (mp_obj_t)&canio_module }, +#define CANIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_canio), (mp_obj_t)&canio_module }, #else #define CANIO_MODULE #endif diff --git a/shared-bindings/_canio/CAN.c b/shared-bindings/_canio/CAN.c deleted file mode 100644 index 38aed85d3..000000000 --- a/shared-bindings/_canio/CAN.c +++ /dev/null @@ -1,422 +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 "py/enum.h" -#include "common-hal/_canio/CAN.h" -#include "common-hal/_canio/Listener.h" -#include "shared-bindings/_canio/__init__.h" -#include "shared-bindings/_canio/CAN.h" -#include "shared-bindings/_canio/Listener.h" -#include "shared-bindings/_canio/Match.h" -#include "shared-bindings/_canio/Message.h" -#include "shared-bindings/microcontroller/Pin.h" - -#include "py/objproperty.h" -#include "py/runtime.h" - -//| -//| class CAN: -//| """CAN bus protocol""" -//| -//| def __init__(self, -//| tx: microcontroller.Pin, -//| rx: microcontroller.Pin, -//| *, -//| baudrate: int = 250000, -//| loopback: bool = False, -//| silent: bool = False, -//| auto_restart: bool = False, -//| ): -//| """A common shared-bus protocol. The rx and tx pins are generally -//| connected to a transceiver which controls the H and L pins on a -//| shared bus. -//| -//| :param ~microcontroller.Pin rx: the pin to receive with -//| :param ~microcontroller.Pin tx: the pin to transmit with -//| :param int baudrate: The bit rate of the bus in Hz. All devices on the bus must agree on this value. -//| :param bool loopback: When True the ``rx`` pin's value is ignored, and the device receives the packets it sends. -//| :param bool silent: When True the ``tx`` pin is always driven to the high logic level. This mode can be used to "sniff" a CAN bus without interfering. -//| :param bool auto_restart: If True, will restart communications after entering bus-off state -//| """ -//| ... -//| -STATIC mp_obj_t canio_can_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_rx, ARG_tx, ARG_baudrate, ARG_loopback, ARG_silent, ARG_auto_restart, NUM_ARGS }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_tx, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_rx, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 250000} }, - { MP_QSTR_loopback, MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_silent, MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_auto_restart, MP_ARG_BOOL, {.u_bool = false} }, - }; - 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 *rx_pin = validate_obj_is_free_pin_or_none(args[ARG_rx].u_obj); - mcu_pin_obj_t *tx_pin = validate_obj_is_free_pin_or_none(args[ARG_tx].u_obj); - if (!rx_pin && !tx_pin) { - mp_raise_ValueError(translate("tx and rx cannot both be None")); - } - - canio_can_obj_t *self = m_new_obj(canio_can_obj_t); - self->base.type = &canio_can_type; - common_hal_canio_can_construct(self, tx_pin, rx_pin, args[ARG_baudrate].u_int, args[ARG_loopback].u_bool, args[ARG_silent].u_bool); - - common_hal_canio_can_auto_restart_set(self, args[ARG_auto_restart].u_bool); - - return MP_OBJ_FROM_PTR(self); -} - - -//| auto_restart: bool -//| """If True, will restart communications after entering bus-off state""" -//| -STATIC mp_obj_t canio_can_auto_restart_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return mp_obj_new_bool(common_hal_canio_can_auto_restart_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_auto_restart_get_obj, canio_can_auto_restart_get); - -STATIC mp_obj_t canio_can_auto_restart_set(mp_obj_t self_in, mp_obj_t flag_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - common_hal_canio_can_auto_restart_set(self, mp_obj_is_true(flag_in)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(canio_can_auto_restart_set_obj, canio_can_auto_restart_set); - -STATIC const mp_obj_property_t canio_can_auto_restart_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_auto_restart_get_obj, - (mp_obj_t)&canio_can_auto_restart_set_obj, - (mp_obj_t)mp_const_none}, -}; - - -//| baudrate: int -//| """The baud rate (read-only)""" -//| -STATIC mp_obj_t canio_can_baudrate_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_baudrate_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_baudrate_get_obj, canio_can_baudrate_get); - -STATIC const mp_obj_property_t canio_can_baudrate_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_baudrate_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - -//| transmit_error_count: int -//| """The number of transmit errors (read-only). Increased for a detected transmission error, decreased for successful transmission. Limited to the range from 0 to 255 inclusive. Also called TEC.""" -//| -STATIC mp_obj_t canio_can_transmit_error_count_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_transmit_error_count_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_transmit_error_count_get_obj, canio_can_transmit_error_count_get); - -STATIC const mp_obj_property_t canio_can_transmit_error_count_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_transmit_error_count_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - -//| receive_error_count: int -//| """The number of receive errors (read-only). Increased for a detected reception error, decreased for successful reception. Limited to the range from 0 to 255 inclusive. Also called REC.""" -//| -STATIC mp_obj_t canio_can_receive_error_count_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_receive_error_count_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_receive_error_count_get_obj, canio_can_receive_error_count_get); - -STATIC const mp_obj_property_t canio_can_receive_error_count_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_receive_error_count_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - -//| error_warning_state_count: int -//| """The number of times the controller enterted the Error Warning state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" -//| -STATIC mp_obj_t canio_can_error_warning_state_count_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_error_warning_state_count_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_error_warning_state_count_get_obj, canio_can_error_warning_state_count_get); - -STATIC const mp_obj_property_t canio_can_error_warning_state_count_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_error_warning_state_count_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - -//| error_passive_state_count: int -//| """The number of times the controller enterted the Error Passive state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" -//| -STATIC mp_obj_t canio_can_error_passive_state_count_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_error_passive_state_count_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_error_passive_state_count_get_obj, canio_can_error_passive_state_count_get); - -STATIC const mp_obj_property_t canio_can_error_passive_state_count_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_error_passive_state_count_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - -//| bus_off_state_count: int -//| """The number of times the controller enterted the Bus Off state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" -//| -STATIC mp_obj_t canio_can_bus_off_state_count_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_bus_off_state_count_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_bus_off_state_count_get_obj, canio_can_bus_off_state_count_get); - -STATIC const mp_obj_property_t canio_can_bus_off_state_count_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_bus_off_state_count_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - -//| state: State -//| """The current state of the bus.""" -STATIC mp_obj_t canio_can_state_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return cp_enum_find(&canio_bus_state_type, common_hal_canio_can_state_get(self)); -} - -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_state_get_obj, canio_can_state_get); - -STATIC const mp_obj_property_t canio_can_state_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_state_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - - -//| def restart(self) -> None: -//| """If the device is in the bus off state, restart it.""" -//| ... -//| -STATIC mp_obj_t canio_can_restart(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - common_hal_canio_can_restart(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_restart_obj, canio_can_restart); - -//| def listen(self, match: Optional[Sequence[Match]]=None, *, timeout: float=10) -> Listener: -//| """Start receiving messages that match any one of the filters. -//| -//| Creating a listener is an expensive operation and can interfere with reception of messages by other listeners. -//| -//| There is an implementation-defined maximum number of listeners and limit to the complexity of the filters. -//| -//| If the hardware cannot support all the requested matches, a ValueError is raised. Note that generally there are some number of hardware filters shared among all fifos. -//| -//| A message can be received by at most one Listener. If more than one listener matches a message, it is undefined which one actually receives it. -//| -//| An empty filter list causes all messages to be accepted. -//| -//| Timeout dictates how long readinto, read and next() will block.""" -//| ... -//| -STATIC mp_obj_t canio_can_listen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - common_hal_canio_can_check_for_deinit(self); - - enum { ARG_match, ARG_timeout, NUM_ARGS }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_match, MP_ARG_OBJ, {.u_obj = 0} }, - { MP_QSTR_timeout, MP_ARG_OBJ, {.u_obj = 0} }, - }; - 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); - - size_t nmatch = 0; - mp_obj_t *match_objects = NULL; - - if (args[ARG_match].u_obj) { - mp_obj_get_array(args[ARG_match].u_obj, &nmatch, &match_objects); - } - - canio_match_obj_t *matches[nmatch]; - for (size_t i=0; iname); - } - matches[i] = MP_OBJ_TO_PTR(match_objects[i]); - } - - float timeout = args[ARG_timeout].u_obj ? mp_obj_get_float(args[ARG_timeout].u_obj) : 10.0f; - canio_listener_obj_t *listener = m_new_obj(canio_listener_obj_t); - listener->base.type = &canio_listener_type; - common_hal_canio_listener_construct(listener, self, nmatch, matches, timeout); - return listener; -} -MP_DEFINE_CONST_FUN_OBJ_KW(canio_can_listen_obj, 1, canio_can_listen); - -//| loopback: bool -//| """True if the device was created in loopback mode, False otherwise""" -//| -STATIC mp_obj_t canio_can_loopback_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return mp_obj_new_bool(common_hal_canio_can_loopback_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_loopback_get_obj, canio_can_loopback_get); - -STATIC const mp_obj_property_t canio_can_loopback_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_loopback_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - - -//| def send(message: Message) -> None: -//| """Send a message on the bus with the given data and id. -//| If the message could not be sent due to a full fifo or a bus error condition, RuntimeError is raised. -//| """ -//| ... -//| -STATIC mp_obj_t canio_can_send(mp_obj_t self_in, mp_obj_t message_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - mp_obj_type_t *message_type = mp_obj_get_type(message_in); - if (message_type != &canio_message_type) { - mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Message, message_type->name); - } - - canio_message_obj_t *message = message_in; - common_hal_canio_can_send(self, message); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(canio_can_send_obj, canio_can_send); - -//| silent: bool -//| """True if the device was created in silent mode, False otherwise""" -//| -STATIC mp_obj_t canio_can_silent_get(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return mp_obj_new_bool(common_hal_canio_can_silent_get(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_can_silent_get_obj, canio_can_silent_get); - -STATIC const mp_obj_property_t canio_can_silent_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_can_silent_get_obj, - (mp_obj_t)mp_const_none, - (mp_obj_t)mp_const_none}, -}; - - -//| def deinit(self) -> None: -//| """Deinitialize this object, freeing its hardware resources""" -//| ... -//| -STATIC mp_obj_t canio_can_deinit(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_deinit_obj, canio_can_deinit); - -//| def __enter__(self) -> CAN: -//| """Returns self, to allow the object to be used in a `with` statement for resource control""" -//| ... -//| -STATIC mp_obj_t canio_can_enter(mp_obj_t self_in) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_can_check_for_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_enter_obj, canio_can_enter); - -//| def __exit__(self, unused1, unused2, unused3) -> None: -//| """Calls deinit()""" -//| ... -STATIC mp_obj_t canio_can_exit(size_t num_args, const mp_obj_t args[]) { - canio_can_obj_t *self = MP_OBJ_TO_PTR(args[0]); - common_hal_canio_can_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_can_exit_obj, 4, 4, canio_can_exit); - -STATIC const mp_rom_map_elem_t canio_can_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_can_enter_obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_can_exit_obj) }, - { MP_ROM_QSTR(MP_QSTR_auto_restart), MP_ROM_PTR(&canio_can_auto_restart_obj) }, - { MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&canio_can_baudrate_obj) }, - { MP_ROM_QSTR(MP_QSTR_bus_off_state_count), MP_ROM_PTR(&canio_can_bus_off_state_count_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_can_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_error_passive_state_count), MP_ROM_PTR(&canio_can_error_passive_state_count_obj) }, - { MP_ROM_QSTR(MP_QSTR_error_warning_state_count), MP_ROM_PTR(&canio_can_error_warning_state_count_obj) }, - { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&canio_can_listen_obj) }, - { MP_ROM_QSTR(MP_QSTR_loopback), MP_ROM_PTR(&canio_can_loopback_obj) }, - { MP_ROM_QSTR(MP_QSTR_receive_error_count), MP_ROM_PTR(&canio_can_receive_error_count_obj) }, - { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&canio_can_restart_obj) }, - { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&canio_can_send_obj) }, - { MP_ROM_QSTR(MP_QSTR_silent), MP_ROM_PTR(&canio_can_silent_obj) }, - { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&canio_can_state_obj) }, - { MP_ROM_QSTR(MP_QSTR_transmit_error_count), MP_ROM_PTR(&canio_can_transmit_error_count_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(canio_can_locals_dict, canio_can_locals_dict_table); - -const mp_obj_type_t canio_can_type = { - { &mp_type_type }, - .name = MP_QSTR_CAN, - .make_new = canio_can_make_new, - .locals_dict = (mp_obj_t)&canio_can_locals_dict, -}; diff --git a/shared-bindings/_canio/CAN.h b/shared-bindings/_canio/CAN.h deleted file mode 100644 index c591c8e6b..000000000 --- a/shared-bindings/_canio/CAN.h +++ /dev/null @@ -1,54 +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. - */ - -#pragma once - -#include "py/obj.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/_canio/Message.h" - -extern const mp_obj_type_t canio_can_type; - -typedef struct canio_can_obj canio_can_obj_t; - -void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent); -bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self); -bool common_hal_canio_can_deinited(canio_can_obj_t *self); -int common_hal_canio_can_baudrate_get(canio_can_obj_t *self); -int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self); -int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self); -int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self); -bool common_hal_canio_can_loopback_get(canio_can_obj_t *self); -int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self); -canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self); -bool common_hal_canio_can_silent_get(canio_can_obj_t *self); -int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self); -void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool auto_restart); -void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self); -void common_hal_canio_can_deinit(canio_can_obj_t *self); -void common_hal_canio_can_restart(canio_can_obj_t *self); -void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message); -void common_hal_canio_reset(void); diff --git a/shared-bindings/_canio/Listener.c b/shared-bindings/_canio/Listener.c deleted file mode 100644 index 6186f3bbd..000000000 --- a/shared-bindings/_canio/Listener.c +++ /dev/null @@ -1,193 +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 "shared-bindings/_canio/Listener.h" -#include "shared-bindings/_canio/Message.h" -#include "common-hal/_canio/Listener.h" - -#include "py/runtime.h" -#include "py/objproperty.h" - -//| class Listener: -//| """Listens for CAN message -//| -//| _canio.Listener is not constructed directly, but instead by calling the -//| Listen method of a _canio.CAN object.""" -//| - -//| def read(self) -> Optional[Message]: -//| """Reads a message, after waiting up to self.timeout seconds -//| -//| If no message is received in time, None is returned. Otherwise, -//| a Message is returned.""" -//| ... -//| -STATIC mp_obj_t canio_listener_read(mp_obj_t self_in) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_listener_check_for_deinit(self); - - canio_message_obj_t *message = m_new_obj(canio_message_obj_t); - self->base.type = &canio_message_type; - - if (common_hal_canio_listener_readinto(self, message)) { - return message; - } else { - m_free(message); // message did not escape into vm - } - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_read_obj, canio_listener_read); - -//| def readinto(self, message: Message) -> bool: -//| """Returns True (and modifies message) if a message was received -//| before ``timeout`` seconds elapsed, False otherwise.""" -//| ... -//| -STATIC mp_obj_t canio_listener_readinto(mp_obj_t self_in, mp_obj_t message) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_type_t *type = mp_obj_get_type(message); - if (type != &canio_message_type) { - mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Message, type->name); - } - common_hal_canio_listener_check_for_deinit(self); - return mp_obj_new_bool(common_hal_canio_listener_readinto(self, message)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(canio_listener_readinto_obj, canio_listener_readinto); - -//| def in_waiting(self) -> int: -//| """Returns the number of messages waiting""" -//| ... -//| -STATIC mp_obj_t canio_listener_in_waiting(mp_obj_t self_in) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_listener_check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_listener_in_waiting(self)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_in_waiting_obj, canio_listener_in_waiting); - -//| def __iter__(self): -//| """Returns self, unless the object is deinitialized""" -//| ... -//| -STATIC mp_obj_t canio_listener_iter(mp_obj_t self_in) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_listener_check_for_deinit(self); - return self; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_iter_obj, canio_listener_iter); - -//| def __next__(self): -//| """Reads a message, after waiting up to self.timeout seconds -//| -//| If no message is received in time, raises StopIteration. Otherwise, -//| a Message is returned.""" -//| ... -//| -STATIC mp_obj_t canio_listener_next(mp_obj_t self_in) { - mp_obj_t result = canio_listener_read(self_in); - if (result == mp_const_none) { - return MP_OBJ_STOP_ITERATION; - } - return result; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_next_obj, canio_listener_next); - -//| def deinit(self) -> None: -//| """Deinitialize this object, freeing its hardware resources""" -//| ... -//| -STATIC mp_obj_t canio_listener_deinit(mp_obj_t self_in) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_listener_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_deinit_obj, canio_listener_deinit); - -//| def __enter__(self) -> CAN: -//| """Returns self, to allow the object to be used in a `with` statement for resource control""" -//| ... -//| -STATIC mp_obj_t canio_listener_enter(mp_obj_t self_in) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_listener_check_for_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_enter_obj, canio_listener_enter); - -//| def __exit__(self, unused1, unused2, unused3) -> None: -//| """Calls deinit()""" -//| ... -STATIC mp_obj_t canio_listener_exit(size_t num_args, const mp_obj_t args[]) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(args[0]); - common_hal_canio_listener_deinit(self); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_listener_exit_obj, 4, 4, canio_listener_exit); - - -//| timeout : float -STATIC mp_obj_t canio_listener_timeout_get(mp_obj_t self_in) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_listener_check_for_deinit(self); - return mp_obj_new_float(common_hal_canio_listener_get_timeout(self)); -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_timeout_get_obj, canio_listener_timeout_get); - -STATIC mp_obj_t canio_listener_timeout_set(mp_obj_t self_in, mp_obj_t timeout_in) { - canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_canio_listener_check_for_deinit(self); - common_hal_canio_listener_set_timeout(self, mp_obj_get_float(timeout_in)); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_2(canio_listener_timeout_set_obj, canio_listener_timeout_set); - -STATIC const mp_obj_property_t canio_listener_timeout_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_listener_timeout_get_obj, - (mp_obj_t)&canio_listener_timeout_set_obj, - (mp_obj_t)mp_const_none}, -}; - - - -STATIC const mp_rom_map_elem_t canio_listener_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_listener_enter_obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_listener_exit_obj) }, - { MP_ROM_QSTR(MP_QSTR___iter__), MP_ROM_PTR(&canio_listener_iter_obj) }, - { MP_ROM_QSTR(MP_QSTR___next__), MP_ROM_PTR(&canio_listener_next_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_listener_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&canio_listener_in_waiting_obj) }, - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&canio_listener_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&canio_listener_readinto_obj) }, - { MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&canio_listener_timeout_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(canio_listener_locals_dict, canio_listener_locals_dict_table); - -const mp_obj_type_t canio_listener_type = { - { &mp_type_type }, - .name = MP_QSTR_Listener, - .locals_dict = (mp_obj_dict_t*)&canio_listener_locals_dict, -}; diff --git a/shared-bindings/_canio/Listener.h b/shared-bindings/_canio/Listener.h deleted file mode 100644 index eaa3490df..000000000 --- a/shared-bindings/_canio/Listener.h +++ /dev/null @@ -1,31 +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. - */ - -#pragma once - -#include "py/obj.h" - -extern const mp_obj_type_t canio_listener_type; diff --git a/shared-bindings/_canio/Match.c b/shared-bindings/_canio/Match.c deleted file mode 100644 index 4ff35906b..000000000 --- a/shared-bindings/_canio/Match.c +++ /dev/null @@ -1,139 +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 "shared-bindings/_canio/Match.h" - -#include "py/objproperty.h" -#include "py/runtime.h" - -//| class Match: -//| """Describe CAN bus messages to match""" -//| -//| -//| def __init__(self, address: int, *, mask: int = 0, extended: bool = False): -//| """Construct a Match with the given properties. -//| -//| If mask is nonzero, then the filter is for any sender which matches all -//| the nonzero bits in mask. Otherwise, it matches exactly the given address. -//| If extended is true then only extended addresses are matched, otherwise -//| only standard addresses are matched.""" -//| - -STATIC mp_obj_t canio_match_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, ARG_mask, ARG_extended, NUM_ARGS }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_address, MP_ARG_INT | MP_ARG_REQUIRED }, - { MP_QSTR_mask, MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, - }; - 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); - - int address_bits = args[ARG_extended].u_bool ? 0x1fffffff : 0x7ff; - int address = args[ARG_address].u_int; - int mask = args[ARG_mask].u_int; - - if (address & ~address_bits) { - mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_address); - } - - if (mask & ~address_bits) { - mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_mask); - } - - canio_match_obj_t *self = m_new_obj(canio_match_obj_t); - self->base.type = &canio_match_type; - common_hal_canio_match_construct(self, args[ARG_address].u_int, args[ARG_mask].u_int, args[ARG_extended].u_bool); - return self; -} - -//| address: int -//| """The address to match""" -//| - -STATIC mp_obj_t canio_match_address_get(mp_obj_t self_in) { - canio_match_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_address(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_match_address_get_obj, canio_match_address_get); - -const mp_obj_property_t canio_match_address_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_match_address_get_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| -//| mask: int -//| """The optional mask of addresses to match""" -//| - -STATIC mp_obj_t canio_match_mask_get(mp_obj_t self_in) { - canio_match_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_mask(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_match_mask_get_obj, canio_match_mask_get); - -const mp_obj_property_t canio_match_mask_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_match_mask_get_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| extended: bool -//| """True to match extended addresses, False to match standard addresses""" -//| - -STATIC mp_obj_t canio_match_extended_get(mp_obj_t self_in) { - canio_match_obj_t *self = self_in; - return mp_obj_new_bool(common_hal_canio_match_get_extended(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_match_extended_get_obj, canio_match_extended_get); - -const mp_obj_property_t canio_match_extended_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_match_extended_get_obj, - (mp_obj_t)&mp_const_none_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -STATIC const mp_rom_map_elem_t canio_match_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&canio_match_address_obj) }, - { MP_ROM_QSTR(MP_QSTR_mask), MP_ROM_PTR(&canio_match_mask_obj) }, - { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_match_extended_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(canio_match_locals_dict, canio_match_locals_dict_table); - -const mp_obj_type_t canio_match_type = { - { &mp_type_type }, - .name = MP_QSTR_Match, - .make_new = canio_match_make_new, - .locals_dict = (mp_obj_dict_t*)&canio_match_locals_dict, -}; diff --git a/shared-bindings/_canio/Match.h b/shared-bindings/_canio/Match.h deleted file mode 100644 index 5522c2636..000000000 --- a/shared-bindings/_canio/Match.h +++ /dev/null @@ -1,37 +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. - */ - -#pragma once - -#include "py/obj.h" -#include "shared-module/_canio/Match.h" - -extern const mp_obj_type_t canio_match_type; - -void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended); -int common_hal_canio_match_get_address(const canio_match_obj_t *self); -int common_hal_canio_match_get_mask(const canio_match_obj_t *self); -bool common_hal_canio_match_get_extended(const canio_match_obj_t *self); diff --git a/shared-bindings/_canio/Message.c b/shared-bindings/_canio/Message.c deleted file mode 100644 index 487ac9bfd..000000000 --- a/shared-bindings/_canio/Message.c +++ /dev/null @@ -1,212 +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 "shared-bindings/_canio/Message.h" - -#include "py/obj.h" -#include "py/objproperty.h" -#include "py/runtime.h" - -//| class Message: -//| def __init__(self, id: int=0, data: Optional[bytes] = None, *, size: Optional[int] = None, rtr: bool = False, extended: bool = False): -//| """Construct a Message to use with a CAN bus. Provide arguments to create a message to send. Otherwise, use Listener.readinto() to read a message. -//| -//| :param int id: The numeric ID of the message -//| :param bytes data: The content of the message -//| :param int size: The amount of data requested, for an rtr -//| :param bool rtr: True if the message represents an rtr (Remote Transmission Request) -//| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier -//| -//| In CAN, messages can have a size from 0 to 8 bytes. -//| -//| For a non-rtr message, specify `data`. For an rtr-message, specify either `data` (a dummy buffer of the requested size) or `size`. -//| """ -//| ... -//| -STATIC mp_obj_t canio_message_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_id, ARG_data, ARG_size, ARG_rtr, ARG_extended, NUM_ARGS }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_id, MP_ARG_INT, {.u_obj = 0} }, - { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = 0} }, - { MP_QSTR_size, MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_rtr, MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, - }; - 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); - - bool rtr = args[ARG_rtr].u_bool; - bool extended = args[ARG_extended].u_bool; - size_t size = (size_t)args[ARG_size].u_int; - bool specified_size = (size != (size_t)-1); - bool specified_data = (args[ARG_data].u_obj != NULL); - - if (specified_size && specified_data) { - mp_raise_TypeError(translate("specify size or data, but not both")); - } - - mp_buffer_info_t data; - if (specified_data) { - mp_get_buffer_raise(args[ARG_data].u_obj, &data, MP_BUFFER_READ); - } else if (specified_size) { - data.buf = 0; - data.len = size; - } else { - data.buf = 0; - data.len = 0; - } - - if (data.len > 8) { - mp_raise_ValueError(translate("Messages limited to 8 bytes")); - } - - canio_message_obj_t *self = m_new_obj(canio_message_obj_t); - self->base.type = &canio_message_type; - common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, rtr, extended); - return self; -} - -//| id: int -//| """The numeric ID of the message""" -//| -STATIC mp_obj_t canio_message_id_get(const mp_obj_t self_in) { - canio_message_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_get_id(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_message_id_get_obj, canio_message_id_get); - -STATIC mp_obj_t canio_message_id_set(const mp_obj_t self_in, const mp_obj_t id) { - canio_message_obj_t *self = self_in; - common_hal_canio_message_set_id(self, mp_obj_get_int(id)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(canio_message_id_set_obj, canio_message_id_set); - -STATIC const mp_obj_property_t canio_message_id_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_message_id_get_obj, - (mp_obj_t)&canio_message_id_set_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - -//| data: bytes -//| """The content of the message, or dummy content in the case of an rtr. -//| -//| Assigning to data also sets the length and clears the rtr flag.""" -//| -STATIC mp_obj_t canio_message_data_get(const mp_obj_t self_in) { - canio_message_obj_t *self = self_in; - return mp_obj_new_bytes((const byte*)common_hal_canio_message_get_data(self), common_hal_canio_message_get_size(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_message_data_get_obj, canio_message_data_get); - -STATIC mp_obj_t canio_message_data_set(const mp_obj_t self_in, const mp_obj_t data_in) { - canio_message_obj_t *self = self_in; - mp_buffer_info_t data; - mp_get_buffer_raise(data_in, &data, MP_BUFFER_READ); - if (data.len > 8) { - mp_raise_ValueError(translate("Messages limited to 8 bytes")); - } - common_hal_canio_message_set_data(self, data.buf, data.len); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(canio_message_data_set_obj, canio_message_data_set); - - -STATIC const mp_obj_property_t canio_message_data_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_message_data_get_obj, - (mp_obj_t)&canio_message_data_set_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - - -//| extended: bool -//| """True if the message represents a remote transmission request (RTR)""" -//| -STATIC mp_obj_t canio_message_extended_get(const mp_obj_t self_in) { - canio_message_obj_t *self = self_in; - return mp_obj_new_bool(common_hal_canio_message_get_extended(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_message_extended_get_obj, canio_message_extended_get); - -STATIC mp_obj_t canio_message_extended_set(const mp_obj_t self_in, const mp_obj_t extended) { - canio_message_obj_t *self = self_in; - common_hal_canio_message_set_extended(self, mp_obj_is_true(extended)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(canio_message_extended_set_obj, canio_message_extended_set); - - -STATIC const mp_obj_property_t canio_message_extended_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_message_extended_get_obj, - (mp_obj_t)&canio_message_extended_set_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - - -//| rtr: bool -//| """True if the message represents a remote transmission request (RTR). Setting rtr to true zeros out data""" -//| -STATIC mp_obj_t canio_message_rtr_get(const mp_obj_t self_in) { - canio_message_obj_t *self = self_in; - return mp_obj_new_bool(common_hal_canio_message_get_rtr(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_message_rtr_get_obj, canio_message_rtr_get); - -STATIC mp_obj_t canio_message_rtr_set(const mp_obj_t self_in, const mp_obj_t rtr) { - canio_message_obj_t *self = self_in; - common_hal_canio_message_set_rtr(self, mp_obj_is_true(rtr)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(canio_message_rtr_set_obj, canio_message_rtr_set); - - -STATIC const mp_obj_property_t canio_message_rtr_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_message_rtr_get_obj, - (mp_obj_t)&canio_message_rtr_set_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - - -STATIC const mp_rom_map_elem_t canio_message_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) }, - { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&canio_message_data_obj) }, - { MP_ROM_QSTR(MP_QSTR_rtr), MP_ROM_PTR(&canio_message_rtr_obj) }, - { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_message_extended_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(canio_message_locals_dict, canio_message_locals_dict_table); - -const mp_obj_type_t canio_message_type = { - { &mp_type_type }, - .name = MP_QSTR_Message, - .make_new = canio_message_make_new, - .locals_dict = (mp_obj_t)&canio_message_locals_dict, -}; diff --git a/shared-bindings/_canio/Message.h b/shared-bindings/_canio/Message.h deleted file mode 100644 index ed739af0d..000000000 --- a/shared-bindings/_canio/Message.h +++ /dev/null @@ -1,44 +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. - */ - -#pragma once - -#include "py/obj.h" -#include "shared-module/_canio/Message.h" - -extern const mp_obj_type_t canio_message_type; - -void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended); -const void *common_hal_canio_message_get_data(const canio_message_obj_t *self); -void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size); -bool common_hal_canio_message_get_extended(const canio_message_obj_t *self); -void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended); -int common_hal_canio_message_get_id(const canio_message_obj_t *self); -void common_hal_canio_message_set_id(canio_message_obj_t *self, int id); -bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self); -void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr); -size_t common_hal_canio_message_get_size(const canio_message_obj_t *self); -void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size); diff --git a/shared-bindings/_canio/__init__.c b/shared-bindings/_canio/__init__.c deleted file mode 100644 index 29e43c5c4..000000000 --- a/shared-bindings/_canio/__init__.c +++ /dev/null @@ -1,124 +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. - */ - -//| """CAN bus access -//| -//| The `_canio` module contains low level classes to support the CAN bus -//| protocol. -//| -//| CAN and Listener 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 _canio -//| from board import * -//| -//| can = _canio.CAN(board.CAN_RX, board.CAN_TX, baudrate=1000000) -//| message = _canio.Message(id=0x0408, data="adafruit" -//| can.write(message)) -//| can.deinit() -//| -//| This example will write the data 'adafruit' onto the CAN bus to any -//| device listening for message id 0x0408. -//| -//| A CAN bus involves a transceiver, which is often a separate chip with a "standby" pin. -//| If your board has a CAN_STANDBY pin, ensure to set it to an output with the value False -//| to enable the transceiver. -//| -//| Other implementations of the CAN device may exist (for instance, attached -//| via an SPI bus). If so their constructor arguments may differ, but -//| otherwise we encourage implementors to follow the API that the core uses. -//| """ -//| - -#include "py/obj.h" -#include "py/enum.h" - -#include "shared-bindings/_canio/__init__.h" -#include "shared-bindings/_canio/CAN.h" -#include "shared-bindings/_canio/Match.h" -#include "shared-bindings/_canio/Message.h" -#include "shared-bindings/_canio/Listener.h" - -MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_ACTIVE, BUS_STATE_ERROR_ACTIVE); -MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_PASSIVE, BUS_STATE_ERROR_PASSIVE); -MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_WARNING, BUS_STATE_ERROR_WARNING); -MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, BUS_OFF, BUS_STATE_OFF); - -//| class BusState: -//| """The state of the CAN bus""" -//| -//| ERROR_ACTIVE: object -//| """The bus is in the normal (active) state""" -//| -//| ERROR_WARNING: object -//| """The bus is in the normal (active) state, but a moderate number of errors have occurred recently. -//| -//| NOTE: Not all implementations may use ERROR_WARNING. Do not rely on seeing ERROR_WARNING before ERROR_PASSIVE.""" -//| -//| ERROR_PASSIVE: object -//| """The bus is in the passive state due to the number of errors that have occurred recently. -//| -//| This device will acknowledge packets it receives, but cannot transmit messages. -//| If additional errors occur, this device may progress to BUS_OFF. -//| If it successfully acknowledges other packets on the bus, it can return to ERROR_WARNING or ERROR_ACTIVE and transmit packets. -//| """ -//| -//| BUS_OFF: object -//| """The bus has turned off due to the number of errors that have -//| occurred recently. It must be restarted before it will send or receive -//| packets. This device will neither send or acknowledge packets on the bus.""" -//| -MAKE_ENUM_MAP(canio_bus_state) { - MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_ACTIVE), - MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_PASSIVE), - MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_WARNING), - MAKE_ENUM_MAP_ENTRY(bus_state, BUS_OFF), -}; -STATIC MP_DEFINE_CONST_DICT(canio_bus_state_locals_dict, canio_bus_state_locals_table); - -MAKE_PRINTER(_canio, canio_bus_state); - -MAKE_ENUM_TYPE(_canio, BusState, canio_bus_state); - -STATIC const mp_rom_map_elem_t canio_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR_BusState), MP_ROM_PTR(&canio_bus_state_type) }, - { MP_ROM_QSTR(MP_QSTR_CAN), MP_ROM_PTR(&canio_can_type) }, - { MP_ROM_QSTR(MP_QSTR_Listener), MP_ROM_PTR(&canio_listener_type) }, - { MP_ROM_QSTR(MP_QSTR_Match), MP_ROM_PTR(&canio_match_type) }, - { MP_ROM_QSTR(MP_QSTR_Message), MP_ROM_PTR(&canio_message_type) }, - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__canio) }, -}; - -STATIC MP_DEFINE_CONST_DICT(canio_module_globals, canio_module_globals_table); - -const mp_obj_module_t canio_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&canio_module_globals, -}; diff --git a/shared-bindings/_canio/__init__.h b/shared-bindings/_canio/__init__.h deleted file mode 100644 index e24eba92c..000000000 --- a/shared-bindings/_canio/__init__.h +++ /dev/null @@ -1,33 +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. - */ - -#pragma once - -typedef enum { - BUS_STATE_ERROR_ACTIVE, BUS_STATE_ERROR_PASSIVE, BUS_STATE_ERROR_WARNING, BUS_STATE_OFF -} canio_bus_state_t; - -extern const mp_obj_type_t canio_bus_state_type; diff --git a/shared-bindings/canio/CAN.c b/shared-bindings/canio/CAN.c new file mode 100644 index 000000000..482d11546 --- /dev/null +++ b/shared-bindings/canio/CAN.c @@ -0,0 +1,422 @@ +/* + * 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/enum.h" +#include "common-hal/canio/CAN.h" +#include "common-hal/canio/Listener.h" +#include "shared-bindings/canio/__init__.h" +#include "shared-bindings/canio/CAN.h" +#include "shared-bindings/canio/Listener.h" +#include "shared-bindings/canio/Match.h" +#include "shared-bindings/canio/Message.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "py/objproperty.h" +#include "py/runtime.h" + +//| +//| class CAN: +//| """CAN bus protocol""" +//| +//| def __init__(self, +//| tx: microcontroller.Pin, +//| rx: microcontroller.Pin, +//| *, +//| baudrate: int = 250000, +//| loopback: bool = False, +//| silent: bool = False, +//| auto_restart: bool = False, +//| ): +//| """A common shared-bus protocol. The rx and tx pins are generally +//| connected to a transceiver which controls the H and L pins on a +//| shared bus. +//| +//| :param ~microcontroller.Pin rx: the pin to receive with +//| :param ~microcontroller.Pin tx: the pin to transmit with +//| :param int baudrate: The bit rate of the bus in Hz. All devices on the bus must agree on this value. +//| :param bool loopback: When True the ``rx`` pin's value is ignored, and the device receives the packets it sends. +//| :param bool silent: When True the ``tx`` pin is always driven to the high logic level. This mode can be used to "sniff" a CAN bus without interfering. +//| :param bool auto_restart: If True, will restart communications after entering bus-off state +//| """ +//| ... +//| +STATIC mp_obj_t canio_can_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_rx, ARG_tx, ARG_baudrate, ARG_loopback, ARG_silent, ARG_auto_restart, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_tx, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_rx, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 250000} }, + { MP_QSTR_loopback, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_silent, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_auto_restart, MP_ARG_BOOL, {.u_bool = false} }, + }; + 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 *rx_pin = validate_obj_is_free_pin_or_none(args[ARG_rx].u_obj); + mcu_pin_obj_t *tx_pin = validate_obj_is_free_pin_or_none(args[ARG_tx].u_obj); + if (!rx_pin && !tx_pin) { + mp_raise_ValueError(translate("tx and rx cannot both be None")); + } + + canio_can_obj_t *self = m_new_obj(canio_can_obj_t); + self->base.type = &canio_can_type; + common_hal_canio_can_construct(self, tx_pin, rx_pin, args[ARG_baudrate].u_int, args[ARG_loopback].u_bool, args[ARG_silent].u_bool); + + common_hal_canio_can_auto_restart_set(self, args[ARG_auto_restart].u_bool); + + return MP_OBJ_FROM_PTR(self); +} + + +//| auto_restart: bool +//| """If True, will restart communications after entering bus-off state""" +//| +STATIC mp_obj_t canio_can_auto_restart_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return mp_obj_new_bool(common_hal_canio_can_auto_restart_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_auto_restart_get_obj, canio_can_auto_restart_get); + +STATIC mp_obj_t canio_can_auto_restart_set(mp_obj_t self_in, mp_obj_t flag_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + common_hal_canio_can_auto_restart_set(self, mp_obj_is_true(flag_in)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_can_auto_restart_set_obj, canio_can_auto_restart_set); + +STATIC const mp_obj_property_t canio_can_auto_restart_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_auto_restart_get_obj, + (mp_obj_t)&canio_can_auto_restart_set_obj, + (mp_obj_t)mp_const_none}, +}; + + +//| baudrate: int +//| """The baud rate (read-only)""" +//| +STATIC mp_obj_t canio_can_baudrate_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_baudrate_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_baudrate_get_obj, canio_can_baudrate_get); + +STATIC const mp_obj_property_t canio_can_baudrate_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_baudrate_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| transmit_error_count: int +//| """The number of transmit errors (read-only). Increased for a detected transmission error, decreased for successful transmission. Limited to the range from 0 to 255 inclusive. Also called TEC.""" +//| +STATIC mp_obj_t canio_can_transmit_error_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_transmit_error_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_transmit_error_count_get_obj, canio_can_transmit_error_count_get); + +STATIC const mp_obj_property_t canio_can_transmit_error_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_transmit_error_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| receive_error_count: int +//| """The number of receive errors (read-only). Increased for a detected reception error, decreased for successful reception. Limited to the range from 0 to 255 inclusive. Also called REC.""" +//| +STATIC mp_obj_t canio_can_receive_error_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_receive_error_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_receive_error_count_get_obj, canio_can_receive_error_count_get); + +STATIC const mp_obj_property_t canio_can_receive_error_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_receive_error_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| error_warning_state_count: int +//| """The number of times the controller enterted the Error Warning state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" +//| +STATIC mp_obj_t canio_can_error_warning_state_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_error_warning_state_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_error_warning_state_count_get_obj, canio_can_error_warning_state_count_get); + +STATIC const mp_obj_property_t canio_can_error_warning_state_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_error_warning_state_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| error_passive_state_count: int +//| """The number of times the controller enterted the Error Passive state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" +//| +STATIC mp_obj_t canio_can_error_passive_state_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_error_passive_state_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_error_passive_state_count_get_obj, canio_can_error_passive_state_count_get); + +STATIC const mp_obj_property_t canio_can_error_passive_state_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_error_passive_state_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| bus_off_state_count: int +//| """The number of times the controller enterted the Bus Off state (read-only). This number wraps around to 0 after an implementation-defined number of errors.""" +//| +STATIC mp_obj_t canio_can_bus_off_state_count_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_bus_off_state_count_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_bus_off_state_count_get_obj, canio_can_bus_off_state_count_get); + +STATIC const mp_obj_property_t canio_can_bus_off_state_count_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_bus_off_state_count_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + +//| state: State +//| """The current state of the bus.""" +STATIC mp_obj_t canio_can_state_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return cp_enum_find(&canio_bus_state_type, common_hal_canio_can_state_get(self)); +} + +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_state_get_obj, canio_can_state_get); + +STATIC const mp_obj_property_t canio_can_state_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_state_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + + +//| def restart(self) -> None: +//| """If the device is in the bus off state, restart it.""" +//| ... +//| +STATIC mp_obj_t canio_can_restart(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + common_hal_canio_can_restart(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_restart_obj, canio_can_restart); + +//| def listen(self, match: Optional[Sequence[Match]]=None, *, timeout: float=10) -> Listener: +//| """Start receiving messages that match any one of the filters. +//| +//| Creating a listener is an expensive operation and can interfere with reception of messages by other listeners. +//| +//| There is an implementation-defined maximum number of listeners and limit to the complexity of the filters. +//| +//| If the hardware cannot support all the requested matches, a ValueError is raised. Note that generally there are some number of hardware filters shared among all fifos. +//| +//| A message can be received by at most one Listener. If more than one listener matches a message, it is undefined which one actually receives it. +//| +//| An empty filter list causes all messages to be accepted. +//| +//| Timeout dictates how long readinto, read and next() will block.""" +//| ... +//| +STATIC mp_obj_t canio_can_listen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + common_hal_canio_can_check_for_deinit(self); + + enum { ARG_match, ARG_timeout, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_match, MP_ARG_OBJ, {.u_obj = 0} }, + { MP_QSTR_timeout, MP_ARG_OBJ, {.u_obj = 0} }, + }; + 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); + + size_t nmatch = 0; + mp_obj_t *match_objects = NULL; + + if (args[ARG_match].u_obj) { + mp_obj_get_array(args[ARG_match].u_obj, &nmatch, &match_objects); + } + + canio_match_obj_t *matches[nmatch]; + for (size_t i=0; iname); + } + matches[i] = MP_OBJ_TO_PTR(match_objects[i]); + } + + float timeout = args[ARG_timeout].u_obj ? mp_obj_get_float(args[ARG_timeout].u_obj) : 10.0f; + canio_listener_obj_t *listener = m_new_obj(canio_listener_obj_t); + listener->base.type = &canio_listener_type; + common_hal_canio_listener_construct(listener, self, nmatch, matches, timeout); + return listener; +} +MP_DEFINE_CONST_FUN_OBJ_KW(canio_can_listen_obj, 1, canio_can_listen); + +//| loopback: bool +//| """True if the device was created in loopback mode, False otherwise""" +//| +STATIC mp_obj_t canio_can_loopback_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return mp_obj_new_bool(common_hal_canio_can_loopback_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_loopback_get_obj, canio_can_loopback_get); + +STATIC const mp_obj_property_t canio_can_loopback_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_loopback_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + + +//| def send(message: Message) -> None: +//| """Send a message on the bus with the given data and id. +//| If the message could not be sent due to a full fifo or a bus error condition, RuntimeError is raised. +//| """ +//| ... +//| +STATIC mp_obj_t canio_can_send(mp_obj_t self_in, mp_obj_t message_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + mp_obj_type_t *message_type = mp_obj_get_type(message_in); + if (message_type != &canio_message_type) { + mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Message, message_type->name); + } + + canio_message_obj_t *message = message_in; + common_hal_canio_can_send(self, message); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_can_send_obj, canio_can_send); + +//| silent: bool +//| """True if the device was created in silent mode, False otherwise""" +//| +STATIC mp_obj_t canio_can_silent_get(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return mp_obj_new_bool(common_hal_canio_can_silent_get(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_can_silent_get_obj, canio_can_silent_get); + +STATIC const mp_obj_property_t canio_can_silent_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_can_silent_get_obj, + (mp_obj_t)mp_const_none, + (mp_obj_t)mp_const_none}, +}; + + +//| def deinit(self) -> None: +//| """Deinitialize this object, freeing its hardware resources""" +//| ... +//| +STATIC mp_obj_t canio_can_deinit(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_deinit_obj, canio_can_deinit); + +//| def __enter__(self) -> CAN: +//| """Returns self, to allow the object to be used in a `with` statement for resource control""" +//| ... +//| +STATIC mp_obj_t canio_can_enter(mp_obj_t self_in) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_can_check_for_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_enter_obj, canio_can_enter); + +//| def __exit__(self, unused1, unused2, unused3) -> None: +//| """Calls deinit()""" +//| ... +STATIC mp_obj_t canio_can_exit(size_t num_args, const mp_obj_t args[]) { + canio_can_obj_t *self = MP_OBJ_TO_PTR(args[0]); + common_hal_canio_can_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_can_exit_obj, 4, 4, canio_can_exit); + +STATIC const mp_rom_map_elem_t canio_can_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_can_enter_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_can_exit_obj) }, + { MP_ROM_QSTR(MP_QSTR_auto_restart), MP_ROM_PTR(&canio_can_auto_restart_obj) }, + { MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&canio_can_baudrate_obj) }, + { MP_ROM_QSTR(MP_QSTR_bus_off_state_count), MP_ROM_PTR(&canio_can_bus_off_state_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_can_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_error_passive_state_count), MP_ROM_PTR(&canio_can_error_passive_state_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_error_warning_state_count), MP_ROM_PTR(&canio_can_error_warning_state_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&canio_can_listen_obj) }, + { MP_ROM_QSTR(MP_QSTR_loopback), MP_ROM_PTR(&canio_can_loopback_obj) }, + { MP_ROM_QSTR(MP_QSTR_receive_error_count), MP_ROM_PTR(&canio_can_receive_error_count_obj) }, + { MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&canio_can_restart_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&canio_can_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_silent), MP_ROM_PTR(&canio_can_silent_obj) }, + { MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&canio_can_state_obj) }, + { MP_ROM_QSTR(MP_QSTR_transmit_error_count), MP_ROM_PTR(&canio_can_transmit_error_count_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_can_locals_dict, canio_can_locals_dict_table); + +const mp_obj_type_t canio_can_type = { + { &mp_type_type }, + .name = MP_QSTR_CAN, + .make_new = canio_can_make_new, + .locals_dict = (mp_obj_t)&canio_can_locals_dict, +}; diff --git a/shared-bindings/canio/CAN.h b/shared-bindings/canio/CAN.h new file mode 100644 index 000000000..66c972c28 --- /dev/null +++ b/shared-bindings/canio/CAN.h @@ -0,0 +1,54 @@ +/* + * 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/microcontroller/Pin.h" +#include "shared-bindings/canio/Message.h" + +extern const mp_obj_type_t canio_can_type; + +typedef struct canio_can_obj canio_can_obj_t; + +void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *tx, mcu_pin_obj_t *rx, int baudrate, bool loopback, bool silent); +bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self); +bool common_hal_canio_can_deinited(canio_can_obj_t *self); +int common_hal_canio_can_baudrate_get(canio_can_obj_t *self); +int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self); +int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self); +int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self); +bool common_hal_canio_can_loopback_get(canio_can_obj_t *self); +int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self); +canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self); +bool common_hal_canio_can_silent_get(canio_can_obj_t *self); +int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self); +void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool auto_restart); +void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self); +void common_hal_canio_can_deinit(canio_can_obj_t *self); +void common_hal_canio_can_restart(canio_can_obj_t *self); +void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message); +void common_hal_canio_reset(void); diff --git a/shared-bindings/canio/Listener.c b/shared-bindings/canio/Listener.c new file mode 100644 index 000000000..0b50e5835 --- /dev/null +++ b/shared-bindings/canio/Listener.c @@ -0,0 +1,193 @@ +/* + * 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 "shared-bindings/canio/Listener.h" +#include "shared-bindings/canio/Message.h" +#include "common-hal/canio/Listener.h" + +#include "py/runtime.h" +#include "py/objproperty.h" + +//| class Listener: +//| """Listens for CAN message +//| +//| _canio.Listener is not constructed directly, but instead by calling the +//| Listen method of a _canio.CAN object.""" +//| + +//| def read(self) -> Optional[Message]: +//| """Reads a message, after waiting up to self.timeout seconds +//| +//| If no message is received in time, None is returned. Otherwise, +//| a Message is returned.""" +//| ... +//| +STATIC mp_obj_t canio_listener_read(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + + canio_message_obj_t *message = m_new_obj(canio_message_obj_t); + self->base.type = &canio_message_type; + + if (common_hal_canio_listener_readinto(self, message)) { + return message; + } else { + m_free(message); // message did not escape into vm + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_read_obj, canio_listener_read); + +//| def readinto(self, message: Message) -> bool: +//| """Returns True (and modifies message) if a message was received +//| before ``timeout`` seconds elapsed, False otherwise.""" +//| ... +//| +STATIC mp_obj_t canio_listener_readinto(mp_obj_t self_in, mp_obj_t message) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_type_t *type = mp_obj_get_type(message); + if (type != &canio_message_type) { + mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Message, type->name); + } + common_hal_canio_listener_check_for_deinit(self); + return mp_obj_new_bool(common_hal_canio_listener_readinto(self, message)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(canio_listener_readinto_obj, canio_listener_readinto); + +//| def in_waiting(self) -> int: +//| """Returns the number of messages waiting""" +//| ... +//| +STATIC mp_obj_t canio_listener_in_waiting(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_listener_in_waiting(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_in_waiting_obj, canio_listener_in_waiting); + +//| def __iter__(self): +//| """Returns self, unless the object is deinitialized""" +//| ... +//| +STATIC mp_obj_t canio_listener_iter(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return self; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_iter_obj, canio_listener_iter); + +//| def __next__(self): +//| """Reads a message, after waiting up to self.timeout seconds +//| +//| If no message is received in time, raises StopIteration. Otherwise, +//| a Message is returned.""" +//| ... +//| +STATIC mp_obj_t canio_listener_next(mp_obj_t self_in) { + mp_obj_t result = canio_listener_read(self_in); + if (result == mp_const_none) { + return MP_OBJ_STOP_ITERATION; + } + return result; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_next_obj, canio_listener_next); + +//| def deinit(self) -> None: +//| """Deinitialize this object, freeing its hardware resources""" +//| ... +//| +STATIC mp_obj_t canio_listener_deinit(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_deinit_obj, canio_listener_deinit); + +//| def __enter__(self) -> CAN: +//| """Returns self, to allow the object to be used in a `with` statement for resource control""" +//| ... +//| +STATIC mp_obj_t canio_listener_enter(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_enter_obj, canio_listener_enter); + +//| def __exit__(self, unused1, unused2, unused3) -> None: +//| """Calls deinit()""" +//| ... +STATIC mp_obj_t canio_listener_exit(size_t num_args, const mp_obj_t args[]) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(args[0]); + common_hal_canio_listener_deinit(self); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_listener_exit_obj, 4, 4, canio_listener_exit); + + +//| timeout : float +STATIC mp_obj_t canio_listener_timeout_get(mp_obj_t self_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + return mp_obj_new_float(common_hal_canio_listener_get_timeout(self)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_listener_timeout_get_obj, canio_listener_timeout_get); + +STATIC mp_obj_t canio_listener_timeout_set(mp_obj_t self_in, mp_obj_t timeout_in) { + canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_canio_listener_check_for_deinit(self); + common_hal_canio_listener_set_timeout(self, mp_obj_get_float(timeout_in)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(canio_listener_timeout_set_obj, canio_listener_timeout_set); + +STATIC const mp_obj_property_t canio_listener_timeout_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_listener_timeout_get_obj, + (mp_obj_t)&canio_listener_timeout_set_obj, + (mp_obj_t)mp_const_none}, +}; + + + +STATIC const mp_rom_map_elem_t canio_listener_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_listener_enter_obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_listener_exit_obj) }, + { MP_ROM_QSTR(MP_QSTR___iter__), MP_ROM_PTR(&canio_listener_iter_obj) }, + { MP_ROM_QSTR(MP_QSTR___next__), MP_ROM_PTR(&canio_listener_next_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_listener_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&canio_listener_in_waiting_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&canio_listener_read_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&canio_listener_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&canio_listener_timeout_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_listener_locals_dict, canio_listener_locals_dict_table); + +const mp_obj_type_t canio_listener_type = { + { &mp_type_type }, + .name = MP_QSTR_Listener, + .locals_dict = (mp_obj_dict_t*)&canio_listener_locals_dict, +}; diff --git a/shared-bindings/canio/Listener.h b/shared-bindings/canio/Listener.h new file mode 100644 index 000000000..eaa3490df --- /dev/null +++ b/shared-bindings/canio/Listener.h @@ -0,0 +1,31 @@ +/* + * 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" + +extern const mp_obj_type_t canio_listener_type; diff --git a/shared-bindings/canio/Match.c b/shared-bindings/canio/Match.c new file mode 100644 index 000000000..ff5d028fa --- /dev/null +++ b/shared-bindings/canio/Match.c @@ -0,0 +1,139 @@ +/* + * 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 "shared-bindings/canio/Match.h" + +#include "py/objproperty.h" +#include "py/runtime.h" + +//| class Match: +//| """Describe CAN bus messages to match""" +//| +//| +//| def __init__(self, address: int, *, mask: int = 0, extended: bool = False): +//| """Construct a Match with the given properties. +//| +//| If mask is nonzero, then the filter is for any sender which matches all +//| the nonzero bits in mask. Otherwise, it matches exactly the given address. +//| If extended is true then only extended addresses are matched, otherwise +//| only standard addresses are matched.""" +//| + +STATIC mp_obj_t canio_match_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, ARG_mask, ARG_extended, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_mask, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, + }; + 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); + + int address_bits = args[ARG_extended].u_bool ? 0x1fffffff : 0x7ff; + int address = args[ARG_address].u_int; + int mask = args[ARG_mask].u_int; + + if (address & ~address_bits) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_address); + } + + if (mask & ~address_bits) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_mask); + } + + canio_match_obj_t *self = m_new_obj(canio_match_obj_t); + self->base.type = &canio_match_type; + common_hal_canio_match_construct(self, args[ARG_address].u_int, args[ARG_mask].u_int, args[ARG_extended].u_bool); + return self; +} + +//| address: int +//| """The address to match""" +//| + +STATIC mp_obj_t canio_match_address_get(mp_obj_t self_in) { + canio_match_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_address(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_match_address_get_obj, canio_match_address_get); + +const mp_obj_property_t canio_match_address_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_match_address_get_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| +//| mask: int +//| """The optional mask of addresses to match""" +//| + +STATIC mp_obj_t canio_match_mask_get(mp_obj_t self_in) { + canio_match_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_mask(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_match_mask_get_obj, canio_match_mask_get); + +const mp_obj_property_t canio_match_mask_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_match_mask_get_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| extended: bool +//| """True to match extended addresses, False to match standard addresses""" +//| + +STATIC mp_obj_t canio_match_extended_get(mp_obj_t self_in) { + canio_match_obj_t *self = self_in; + return mp_obj_new_bool(common_hal_canio_match_get_extended(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_match_extended_get_obj, canio_match_extended_get); + +const mp_obj_property_t canio_match_extended_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_match_extended_get_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t canio_match_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&canio_match_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_mask), MP_ROM_PTR(&canio_match_mask_obj) }, + { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_match_extended_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_match_locals_dict, canio_match_locals_dict_table); + +const mp_obj_type_t canio_match_type = { + { &mp_type_type }, + .name = MP_QSTR_Match, + .make_new = canio_match_make_new, + .locals_dict = (mp_obj_dict_t*)&canio_match_locals_dict, +}; diff --git a/shared-bindings/canio/Match.h b/shared-bindings/canio/Match.h new file mode 100644 index 000000000..88996d730 --- /dev/null +++ b/shared-bindings/canio/Match.h @@ -0,0 +1,37 @@ +/* + * 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-module/canio/Match.h" + +extern const mp_obj_type_t canio_match_type; + +void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended); +int common_hal_canio_match_get_address(const canio_match_obj_t *self); +int common_hal_canio_match_get_mask(const canio_match_obj_t *self); +bool common_hal_canio_match_get_extended(const canio_match_obj_t *self); diff --git a/shared-bindings/canio/Message.c b/shared-bindings/canio/Message.c new file mode 100644 index 000000000..11de6ded9 --- /dev/null +++ b/shared-bindings/canio/Message.c @@ -0,0 +1,212 @@ +/* + * 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 "shared-bindings/canio/Message.h" + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +//| class Message: +//| def __init__(self, id: int=0, data: Optional[bytes] = None, *, size: Optional[int] = None, rtr: bool = False, extended: bool = False): +//| """Construct a Message to use with a CAN bus. Provide arguments to create a message to send. Otherwise, use Listener.readinto() to read a message. +//| +//| :param int id: The numeric ID of the message +//| :param bytes data: The content of the message +//| :param int size: The amount of data requested, for an rtr +//| :param bool rtr: True if the message represents an rtr (Remote Transmission Request) +//| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier +//| +//| In CAN, messages can have a size from 0 to 8 bytes. +//| +//| For a non-rtr message, specify `data`. For an rtr-message, specify either `data` (a dummy buffer of the requested size) or `size`. +//| """ +//| ... +//| +STATIC mp_obj_t canio_message_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_id, ARG_data, ARG_size, ARG_rtr, ARG_extended, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT, {.u_obj = 0} }, + { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = 0} }, + { MP_QSTR_size, MP_ARG_INT, {.u_int = -1} }, + { MP_QSTR_rtr, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, + }; + 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); + + bool rtr = args[ARG_rtr].u_bool; + bool extended = args[ARG_extended].u_bool; + size_t size = (size_t)args[ARG_size].u_int; + bool specified_size = (size != (size_t)-1); + bool specified_data = (args[ARG_data].u_obj != NULL); + + if (specified_size && specified_data) { + mp_raise_TypeError(translate("specify size or data, but not both")); + } + + mp_buffer_info_t data; + if (specified_data) { + mp_get_buffer_raise(args[ARG_data].u_obj, &data, MP_BUFFER_READ); + } else if (specified_size) { + data.buf = 0; + data.len = size; + } else { + data.buf = 0; + data.len = 0; + } + + if (data.len > 8) { + mp_raise_ValueError(translate("Messages limited to 8 bytes")); + } + + canio_message_obj_t *self = m_new_obj(canio_message_obj_t); + self->base.type = &canio_message_type; + common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, rtr, extended); + return self; +} + +//| id: int +//| """The numeric ID of the message""" +//| +STATIC mp_obj_t canio_message_id_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_get_id(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_id_get_obj, canio_message_id_get); + +STATIC mp_obj_t canio_message_id_set(const mp_obj_t self_in, const mp_obj_t id) { + canio_message_obj_t *self = self_in; + common_hal_canio_message_set_id(self, mp_obj_get_int(id)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_id_set_obj, canio_message_id_set); + +STATIC const mp_obj_property_t canio_message_id_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_id_get_obj, + (mp_obj_t)&canio_message_id_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| data: bytes +//| """The content of the message, or dummy content in the case of an rtr. +//| +//| Assigning to data also sets the length and clears the rtr flag.""" +//| +STATIC mp_obj_t canio_message_data_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return mp_obj_new_bytes((const byte*)common_hal_canio_message_get_data(self), common_hal_canio_message_get_size(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_data_get_obj, canio_message_data_get); + +STATIC mp_obj_t canio_message_data_set(const mp_obj_t self_in, const mp_obj_t data_in) { + canio_message_obj_t *self = self_in; + mp_buffer_info_t data; + mp_get_buffer_raise(data_in, &data, MP_BUFFER_READ); + if (data.len > 8) { + mp_raise_ValueError(translate("Messages limited to 8 bytes")); + } + common_hal_canio_message_set_data(self, data.buf, data.len); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_data_set_obj, canio_message_data_set); + + +STATIC const mp_obj_property_t canio_message_data_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_data_get_obj, + (mp_obj_t)&canio_message_data_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +//| extended: bool +//| """True if the message represents a remote transmission request (RTR)""" +//| +STATIC mp_obj_t canio_message_extended_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return mp_obj_new_bool(common_hal_canio_message_get_extended(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_extended_get_obj, canio_message_extended_get); + +STATIC mp_obj_t canio_message_extended_set(const mp_obj_t self_in, const mp_obj_t extended) { + canio_message_obj_t *self = self_in; + common_hal_canio_message_set_extended(self, mp_obj_is_true(extended)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_extended_set_obj, canio_message_extended_set); + + +STATIC const mp_obj_property_t canio_message_extended_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_extended_get_obj, + (mp_obj_t)&canio_message_extended_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +//| rtr: bool +//| """True if the message represents a remote transmission request (RTR). Setting rtr to true zeros out data""" +//| +STATIC mp_obj_t canio_message_rtr_get(const mp_obj_t self_in) { + canio_message_obj_t *self = self_in; + return mp_obj_new_bool(common_hal_canio_message_get_rtr(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_message_rtr_get_obj, canio_message_rtr_get); + +STATIC mp_obj_t canio_message_rtr_set(const mp_obj_t self_in, const mp_obj_t rtr) { + canio_message_obj_t *self = self_in; + common_hal_canio_message_set_rtr(self, mp_obj_is_true(rtr)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_message_rtr_set_obj, canio_message_rtr_set); + + +STATIC const mp_obj_property_t canio_message_rtr_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_message_rtr_get_obj, + (mp_obj_t)&canio_message_rtr_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + + +STATIC const mp_rom_map_elem_t canio_message_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&canio_message_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_rtr), MP_ROM_PTR(&canio_message_rtr_obj) }, + { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_message_extended_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_message_locals_dict, canio_message_locals_dict_table); + +const mp_obj_type_t canio_message_type = { + { &mp_type_type }, + .name = MP_QSTR_Message, + .make_new = canio_message_make_new, + .locals_dict = (mp_obj_t)&canio_message_locals_dict, +}; diff --git a/shared-bindings/canio/Message.h b/shared-bindings/canio/Message.h new file mode 100644 index 000000000..34b632e84 --- /dev/null +++ b/shared-bindings/canio/Message.h @@ -0,0 +1,44 @@ +/* + * 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-module/canio/Message.h" + +extern const mp_obj_type_t canio_message_type; + +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended); +const void *common_hal_canio_message_get_data(const canio_message_obj_t *self); +void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size); +bool common_hal_canio_message_get_extended(const canio_message_obj_t *self); +void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended); +int common_hal_canio_message_get_id(const canio_message_obj_t *self); +void common_hal_canio_message_set_id(canio_message_obj_t *self, int id); +bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self); +void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr); +size_t common_hal_canio_message_get_size(const canio_message_obj_t *self); +void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size); diff --git a/shared-bindings/canio/__init__.c b/shared-bindings/canio/__init__.c new file mode 100644 index 000000000..bc191913d --- /dev/null +++ b/shared-bindings/canio/__init__.c @@ -0,0 +1,124 @@ +/* + * 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. + */ + +//| """CAN bus access +//| +//| The `_canio` module contains low level classes to support the CAN bus +//| protocol. +//| +//| CAN and Listener 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 _canio +//| from board import * +//| +//| can = _canio.CAN(board.CAN_RX, board.CAN_TX, baudrate=1000000) +//| message = _canio.Message(id=0x0408, data="adafruit" +//| can.write(message)) +//| can.deinit() +//| +//| This example will write the data 'adafruit' onto the CAN bus to any +//| device listening for message id 0x0408. +//| +//| A CAN bus involves a transceiver, which is often a separate chip with a "standby" pin. +//| If your board has a CAN_STANDBY pin, ensure to set it to an output with the value False +//| to enable the transceiver. +//| +//| Other implementations of the CAN device may exist (for instance, attached +//| via an SPI bus). If so their constructor arguments may differ, but +//| otherwise we encourage implementors to follow the API that the core uses. +//| """ +//| + +#include "py/obj.h" +#include "py/enum.h" + +#include "shared-bindings/canio/__init__.h" +#include "shared-bindings/canio/CAN.h" +#include "shared-bindings/canio/Match.h" +#include "shared-bindings/canio/Message.h" +#include "shared-bindings/canio/Listener.h" + +MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_ACTIVE, BUS_STATE_ERROR_ACTIVE); +MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_PASSIVE, BUS_STATE_ERROR_PASSIVE); +MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, ERROR_WARNING, BUS_STATE_ERROR_WARNING); +MAKE_ENUM_VALUE(canio_bus_state_type, bus_state, BUS_OFF, BUS_STATE_OFF); + +//| class BusState: +//| """The state of the CAN bus""" +//| +//| ERROR_ACTIVE: object +//| """The bus is in the normal (active) state""" +//| +//| ERROR_WARNING: object +//| """The bus is in the normal (active) state, but a moderate number of errors have occurred recently. +//| +//| NOTE: Not all implementations may use ERROR_WARNING. Do not rely on seeing ERROR_WARNING before ERROR_PASSIVE.""" +//| +//| ERROR_PASSIVE: object +//| """The bus is in the passive state due to the number of errors that have occurred recently. +//| +//| This device will acknowledge packets it receives, but cannot transmit messages. +//| If additional errors occur, this device may progress to BUS_OFF. +//| If it successfully acknowledges other packets on the bus, it can return to ERROR_WARNING or ERROR_ACTIVE and transmit packets. +//| """ +//| +//| BUS_OFF: object +//| """The bus has turned off due to the number of errors that have +//| occurred recently. It must be restarted before it will send or receive +//| packets. This device will neither send or acknowledge packets on the bus.""" +//| +MAKE_ENUM_MAP(canio_bus_state) { + MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_ACTIVE), + MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_PASSIVE), + MAKE_ENUM_MAP_ENTRY(bus_state, ERROR_WARNING), + MAKE_ENUM_MAP_ENTRY(bus_state, BUS_OFF), +}; +STATIC MP_DEFINE_CONST_DICT(canio_bus_state_locals_dict, canio_bus_state_locals_table); + +MAKE_PRINTER(_canio, canio_bus_state); + +MAKE_ENUM_TYPE(_canio, BusState, canio_bus_state); + +STATIC const mp_rom_map_elem_t canio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR_BusState), MP_ROM_PTR(&canio_bus_state_type) }, + { MP_ROM_QSTR(MP_QSTR_CAN), MP_ROM_PTR(&canio_can_type) }, + { MP_ROM_QSTR(MP_QSTR_Listener), MP_ROM_PTR(&canio_listener_type) }, + { MP_ROM_QSTR(MP_QSTR_Match), MP_ROM_PTR(&canio_match_type) }, + { MP_ROM_QSTR(MP_QSTR_Message), MP_ROM_PTR(&canio_message_type) }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__canio) }, +}; + +STATIC MP_DEFINE_CONST_DICT(canio_module_globals, canio_module_globals_table); + +const mp_obj_module_t canio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&canio_module_globals, +}; diff --git a/shared-bindings/canio/__init__.h b/shared-bindings/canio/__init__.h new file mode 100644 index 000000000..e24eba92c --- /dev/null +++ b/shared-bindings/canio/__init__.h @@ -0,0 +1,33 @@ +/* + * 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 + +typedef enum { + BUS_STATE_ERROR_ACTIVE, BUS_STATE_ERROR_PASSIVE, BUS_STATE_ERROR_WARNING, BUS_STATE_OFF +} canio_bus_state_t; + +extern const mp_obj_type_t canio_bus_state_type; diff --git a/shared-module/_canio/Match.c b/shared-module/_canio/Match.c deleted file mode 100644 index 3dcde18a7..000000000 --- a/shared-module/_canio/Match.c +++ /dev/null @@ -1,43 +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 "shared-module/_canio/Match.h" - -void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended) { - self->address = address; - self->mask = mask; - self->extended = extended; -} - -int common_hal_canio_match_get_address(const canio_match_obj_t *self) { - return self->address; -} -int common_hal_canio_match_get_mask(const canio_match_obj_t *self) { - return self->mask; -} -bool common_hal_canio_match_get_extended(const canio_match_obj_t *self) { - return self->extended; -} diff --git a/shared-module/_canio/Match.h b/shared-module/_canio/Match.h deleted file mode 100644 index 25f047f37..000000000 --- a/shared-module/_canio/Match.h +++ /dev/null @@ -1,36 +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. - */ - -#pragma once - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - int address; - int mask; - bool extended; -} canio_match_obj_t; diff --git a/shared-module/_canio/Message.c b/shared-module/_canio/Message.c deleted file mode 100644 index a02bd0127..000000000 --- a/shared-module/_canio/Message.c +++ /dev/null @@ -1,101 +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 "shared-module/_canio/Message.h" - -#include - -void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended) -{ - self->id = id; - self->size = size; - self->rtr = rtr; - self->extended = extended; - if (data) { - memcpy(self->data, data, size); - } else { - memset(self->data, 0, size); - } -} - -int common_hal_canio_message_get_id(const canio_message_obj_t *self) -{ - return self->id; -} - -void common_hal_canio_message_set_id(canio_message_obj_t *self, int id) -{ - self->id = id; -} - - -const void *common_hal_canio_message_get_data(const canio_message_obj_t *self) -{ - return self->data; -} - -const void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size) -{ - self->rtr = false; - self->size = size; - memcpy(self->data, data, size); -} - - -size_t common_hal_canio_message_get_size(const canio_message_obj_t *self) -{ - return self->size; -} - -void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size) -{ - memset(self->data, 0, size); - self->size = size; -} - - -bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self) -{ - return self->rtr; -} - -void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr) -{ - self->rtr = rtr; - if (rtr) { - memset(self->data, 0, self->size); - } -} - -bool common_hal_canio_message_get_extended(const canio_message_obj_t *self) -{ - return self->extended; -} - -void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended) -{ - self->extended = extended; -} diff --git a/shared-module/_canio/Message.h b/shared-module/_canio/Message.h deleted file mode 100644 index b99c5c48e..000000000 --- a/shared-module/_canio/Message.h +++ /dev/null @@ -1,38 +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. - */ - -#pragma once - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - int id; - uint8_t data[8]; - size_t size:4; - bool rtr:1; - bool extended:1; -} canio_message_obj_t; diff --git a/shared-module/canio/Match.c b/shared-module/canio/Match.c new file mode 100644 index 000000000..9e33b956f --- /dev/null +++ b/shared-module/canio/Match.c @@ -0,0 +1,43 @@ +/* + * 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 "shared-module/canio/Match.h" + +void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended) { + self->address = address; + self->mask = mask; + self->extended = extended; +} + +int common_hal_canio_match_get_address(const canio_match_obj_t *self) { + return self->address; +} +int common_hal_canio_match_get_mask(const canio_match_obj_t *self) { + return self->mask; +} +bool common_hal_canio_match_get_extended(const canio_match_obj_t *self) { + return self->extended; +} diff --git a/shared-module/canio/Match.h b/shared-module/canio/Match.h new file mode 100644 index 000000000..25f047f37 --- /dev/null +++ b/shared-module/canio/Match.h @@ -0,0 +1,36 @@ +/* + * 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" + +typedef struct { + mp_obj_base_t base; + int address; + int mask; + bool extended; +} canio_match_obj_t; diff --git a/shared-module/canio/Message.c b/shared-module/canio/Message.c new file mode 100644 index 000000000..b8ebb7859 --- /dev/null +++ b/shared-module/canio/Message.c @@ -0,0 +1,101 @@ +/* + * 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 "shared-module/canio/Message.h" + +#include + +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended) +{ + self->id = id; + self->size = size; + self->rtr = rtr; + self->extended = extended; + if (data) { + memcpy(self->data, data, size); + } else { + memset(self->data, 0, size); + } +} + +int common_hal_canio_message_get_id(const canio_message_obj_t *self) +{ + return self->id; +} + +void common_hal_canio_message_set_id(canio_message_obj_t *self, int id) +{ + self->id = id; +} + + +const void *common_hal_canio_message_get_data(const canio_message_obj_t *self) +{ + return self->data; +} + +const void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size) +{ + self->rtr = false; + self->size = size; + memcpy(self->data, data, size); +} + + +size_t common_hal_canio_message_get_size(const canio_message_obj_t *self) +{ + return self->size; +} + +void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size) +{ + memset(self->data, 0, size); + self->size = size; +} + + +bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self) +{ + return self->rtr; +} + +void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr) +{ + self->rtr = rtr; + if (rtr) { + memset(self->data, 0, self->size); + } +} + +bool common_hal_canio_message_get_extended(const canio_message_obj_t *self) +{ + return self->extended; +} + +void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended) +{ + self->extended = extended; +} diff --git a/shared-module/canio/Message.h b/shared-module/canio/Message.h new file mode 100644 index 000000000..b99c5c48e --- /dev/null +++ b/shared-module/canio/Message.h @@ -0,0 +1,38 @@ +/* + * 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" + +typedef struct { + mp_obj_base_t base; + int id; + uint8_t data[8]; + size_t size:4; + bool rtr:1; + bool extended:1; +} canio_message_obj_t; -- cgit v1.2.3 From f21dc253e094854670b829f6258aac3722eefc26 Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Mon, 21 Sep 2020 18:42:16 -0400 Subject: Initial commit bool column_and_page_addressing --- shared-bindings/displayio/Display.c | 5 ++++- shared-bindings/displayio/Display.h | 3 ++- shared-module/displayio/Display.c | 4 +++- shared-module/displayio/Display.h | 2 ++ 4 files changed, 11 insertions(+), 3 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index f36aeed18..634156f56 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -105,6 +105,7 @@ //| :param bool auto_brightness: If True, brightness is controlled via an ambient light sensor or other mechanism. //| :param bool single_byte_bounds: Display column and row commands use single bytes //| :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this. +//| :param bool column_and_page_addressing: Special quirk for SH1107, use upper/lower column set and page set //| :param bool auto_refresh: Automatically refresh the screen //| :param int native_frames_per_second: Number of display refreshes per second that occur with the given init_sequence. //| :param bool backlight_on_high: If True, pulling the backlight pin high turns the backlight on.""" @@ -139,6 +140,7 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a { MP_QSTR_auto_refresh, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, { MP_QSTR_native_frames_per_second, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 60} }, { MP_QSTR_backlight_on_high, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_column_and_page_addressing, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.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); @@ -180,7 +182,8 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a args[ARG_data_as_commands].u_bool, args[ARG_auto_refresh].u_bool, args[ARG_native_frames_per_second].u_int, - args[ARG_backlight_on_high].u_bool + args[ARG_backlight_on_high].u_bool, + args[ARG_column_and_page_addressing].u_bool ); return self; diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index e69c5b6b5..d6274a2b2 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -45,7 +45,8 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, - bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, bool backlight_on_high); + bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, + bool backlight_on_high, bool column_and_page_addressing); bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 021159c0d..d3e7ee175 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -48,7 +48,8 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, - bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, bool backlight_on_high) { + bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, + bool backlight_on_high), bool column_and_page_addressing { // Turn off auto-refresh as we init. self->auto_refresh = false; uint16_t ram_width = 0x100; @@ -68,6 +69,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->first_manual_refresh = !auto_refresh; self->data_as_commands = data_as_commands; self->backlight_on_high = backlight_on_high; + self->column_and_page_addressing = column_and_page_addressing; self->native_frames_per_second = native_frames_per_second; self->native_ms_per_frame = 1000 / native_frames_per_second; diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index bdb861aa0..86c2a9360 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -60,6 +60,8 @@ typedef struct { bool auto_brightness; bool updating_backlight; bool backlight_on_high; + // new quirk for sh1107 + bool column_and_page_addressing; } displayio_display_obj_t; void displayio_display_background(displayio_display_obj_t* self); -- cgit v1.2.3 From 08189edf247244c616b0bd4c58fdb678b6c53d0e Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Mon, 21 Sep 2020 21:07:42 -0400 Subject: Quirk coded up for ...set_region_to_update --- shared-module/displayio/Display.c | 2 +- shared-module/displayio/display_core.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index d3e7ee175..b0806af29 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -49,7 +49,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, - bool backlight_on_high), bool column_and_page_addressing { + bool backlight_on_high, bool column_and_page_addressing) { // Turn off auto-refresh as we init. self->auto_refresh = false; uint16_t ram_width = 0x100; diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 43f2d1937..f046ab9e4 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -253,8 +253,16 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, data[data_length++] = x2 >> 8; data[data_length++] = x2 & 0xff; } + // Quirk for SH1107 "column_and_page_addressing" + // Column lower command = 0x00, Column upper command = 0x10 + if (column_and_page_addressing) { + data[0] = 0x00 | (x1 & 0x0F); + data[1] = 0x10 | (x1 >> 4); + data_length = 2; + } self->send(self->bus, data_type, chip_select, data, data_length); displayio_display_core_end_transaction(self); + if (set_current_column_command != NO_COMMAND) { uint8_t command = set_current_column_command; displayio_display_core_begin_transaction(self); @@ -283,6 +291,14 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, data[data_length++] = y2 >> 8; data[data_length++] = y2 & 0xff; } + // Quirk for SH1107 "column_and_page_addressing" + // Page address command = 0xB0 + if (column_and_page_addressing) { + data[0] = 0xB0 | (y1 & 0x07); + data_length = 1; + } + self->send(self->bus, data_type, chip_select, data, data_length); + self->send(self->bus, data_type, chip_select, data, data_length); displayio_display_core_end_transaction(self); -- cgit v1.2.3 From 5536e574dba604b86ef5f6e8c4d86bc408ef8ac5 Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Mon, 21 Sep 2020 22:08:16 -0400 Subject: Changes to compile cleanly --- .gitignore | 1 + shared-bindings/displayio/Display.c | 2 +- shared-module/displayio/Display.c | 4 +++- shared-module/displayio/EPaperDisplay.c | 4 +++- shared-module/displayio/display_core.c | 5 ++++- shared-module/displayio/display_core.h | 5 ++++- 6 files changed, 16 insertions(+), 5 deletions(-) (limited to 'shared-module') diff --git a/.gitignore b/.gitignore index 03cd38f35..a8814be45 100644 --- a/.gitignore +++ b/.gitignore @@ -80,6 +80,7 @@ TAGS *.mo .vscode +.idea # Python Virtual Environments #################### diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 634156f56..2ae237350 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -112,7 +112,7 @@ //| ... //| STATIC mp_obj_t displayio_display_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_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high }; + enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high, ARG_column_and_page_addressing }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index b0806af29..b6979c0b2 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -288,7 +288,9 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* } remaining_rows -= rows_per_buffer; - displayio_display_core_set_region_to_update(&self->core, self->set_column_command, self->set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false, &subrectangle); + displayio_display_core_set_region_to_update(&self->core, self->set_column_command, + self->set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false, + &subrectangle, self->column_and_page_addressing); uint16_t subrectangle_size_bytes; if (self->core.colorspace.depth >= 8) { diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 6d9e915b4..397ceb4fd 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -239,7 +239,9 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c uint16_t remaining_rows = displayio_area_height(&clipped); if (self->set_row_window_command != NO_COMMAND) { - displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, false, self->chip_select, &clipped); + displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, + self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, + false, self->chip_select, &clipped, false); } uint8_t write_command = self->write_black_ram_command; diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index f046ab9e4..f01fda092 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -208,7 +208,10 @@ void displayio_display_core_end_transaction(displayio_display_core_t* self) { self->end_transaction(self->bus); } -void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, bool data_as_commands, bool always_toggle_chip_select, displayio_area_t* area) { +void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, + uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, + bool data_as_commands, bool always_toggle_chip_select, + displayio_area_t* area, bool column_and_page_addressing) { uint16_t x1 = area->x1; uint16_t x2 = area->x2; uint16_t y1 = area->y1; diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index e4fd62d4a..1c880be44 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -74,7 +74,10 @@ bool displayio_display_core_bus_free(displayio_display_core_t *self); bool displayio_display_core_begin_transaction(displayio_display_core_t* self); void displayio_display_core_end_transaction(displayio_display_core_t* self); -void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, bool data_as_commands, bool always_toggle_chip_select, displayio_area_t* area); +void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, + uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, + bool data_as_commands, bool always_toggle_chip_select, + displayio_area_t* area, bool column_and_page_addressing); void release_display_core(displayio_display_core_t* self); -- cgit v1.2.3 From dbf8a9ad69fa93b7ad9b85df22208e08790e5795 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 22 Sep 2020 10:25:31 -0500 Subject: Changed delay calls to avoid conflicts with qspi_disable --- shared-module/displayio/FourWire.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c index 726116208..8c56d7ab6 100644 --- a/shared-module/displayio/FourWire.c +++ b/shared-module/displayio/FourWire.c @@ -87,9 +87,9 @@ bool common_hal_displayio_fourwire_reset(mp_obj_t obj) { return false; } common_hal_digitalio_digitalinout_set_value(&self->reset, false); - common_hal_time_delay_ms(1); + common_hal_mcu_delay_us(1000); common_hal_digitalio_digitalinout_set_value(&self->reset, true); - common_hal_time_delay_ms(1); + common_hal_mcu_delay_us(1000); return true; } -- cgit v1.2.3 From 5a176c2c67cff17415d1a713ed2ee3cbf94dd020 Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Tue, 22 Sep 2020 13:41:25 -0400 Subject: Removed redundant send of page setting --- shared-module/displayio/display_core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index f01fda092..19e45e6b6 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -302,7 +302,6 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, } self->send(self->bus, data_type, chip_select, data, data_length); - self->send(self->bus, data_type, chip_select, data, data_length); displayio_display_core_end_transaction(self); if (set_current_row_command != NO_COMMAND) { -- cgit v1.2.3 From 06a3d152664a97cc0a2f2faee86d2f5ea4e063e2 Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Thu, 24 Sep 2020 22:07:33 -0400 Subject: Mostly-working-version with comments --- shared-bindings/displayio/Display.c | 18 ++++++++++++----- shared-bindings/displayio/Display.h | 2 +- shared-module/displayio/Display.c | 36 ++++++++++++++++++++++++++------- shared-module/displayio/Display.h | 2 +- shared-module/displayio/EPaperDisplay.c | 1 + shared-module/displayio/display_core.c | 33 ++++++++++++++++-------------- shared-module/displayio/display_core.h | 2 +- 7 files changed, 64 insertions(+), 30 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index 2ae237350..a81736e46 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -105,14 +105,22 @@ //| :param bool auto_brightness: If True, brightness is controlled via an ambient light sensor or other mechanism. //| :param bool single_byte_bounds: Display column and row commands use single bytes //| :param bool data_as_commands: Treat all init and boundary data as SPI commands. Certain displays require this. -//| :param bool column_and_page_addressing: Special quirk for SH1107, use upper/lower column set and page set +//| :param bool SH1107_addressing: Special quirk for SH1107, use upper/lower column set and page set //| :param bool auto_refresh: Automatically refresh the screen //| :param int native_frames_per_second: Number of display refreshes per second that occur with the given init_sequence. //| :param bool backlight_on_high: If True, pulling the backlight pin high turns the backlight on.""" //| ... //| -STATIC mp_obj_t displayio_display_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_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high, ARG_column_and_page_addressing }; +STATIC mp_obj_t displayio_display_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_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, + ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, + ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, + ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, + ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, + ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, + ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high, + ARG_SH1107_addressing }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -140,7 +148,7 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a { MP_QSTR_auto_refresh, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, { MP_QSTR_native_frames_per_second, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 60} }, { MP_QSTR_backlight_on_high, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, - { MP_QSTR_column_and_page_addressing, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_SH1107_addressing, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.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); @@ -183,7 +191,7 @@ STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_a args[ARG_auto_refresh].u_bool, args[ARG_native_frames_per_second].u_int, args[ARG_backlight_on_high].u_bool, - args[ARG_column_and_page_addressing].u_bool + args[ARG_SH1107_addressing].u_bool ); return self; diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index d6274a2b2..c1704eaad 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -46,7 +46,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, - bool backlight_on_high, bool column_and_page_addressing); + bool backlight_on_high, bool SH1107_addressing); bool common_hal_displayio_display_show(displayio_display_obj_t* self, displayio_group_t* root_group); diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index b6979c0b2..afc4b7564 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -49,7 +49,8 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, - bool backlight_on_high, bool column_and_page_addressing) { + bool backlight_on_high, bool SH1107_addressing) { + // Turn off auto-refresh as we init. self->auto_refresh = false; uint16_t ram_width = 0x100; @@ -69,7 +70,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, self->first_manual_refresh = !auto_refresh; self->data_as_commands = data_as_commands; self->backlight_on_high = backlight_on_high; - self->column_and_page_addressing = column_and_page_addressing; + self->SH1107_addressing = SH1107_addressing; self->native_frames_per_second = native_frames_per_second; self->native_ms_per_frame = 1000 / native_frames_per_second; @@ -242,11 +243,23 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* if (!displayio_display_core_clip_area(&self->core, area, &clipped)) { return true; } - uint16_t subrectangles = 1; 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); - if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { + + uint16_t subrectangles = 1; + // for SH1107 and other boundary constrained controllers + // write one single row at a time + if (self->SH1107_addressing) { + subrectangles = rows_per_buffer; // vertical (column mode) write each separately (height times) + } + + // Skip this recalculation of subrectangles if SH1107 (each subrectangle is a single row) + // [mdroberts1243] I am worried/confused about the pixels_in_byte_share_row calculation though + // since it makes sense to be on a byte boundary (actually a page boundary too) + // seems to work as is though. + if ((displayio_area_size(&clipped) > buffer_size * pixels_per_word) + && (!self->SH1107_addressing)) { rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); if (rows_per_buffer == 0) { rows_per_buffer = 1; @@ -283,14 +296,23 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* .x2 = clipped.x2, .y2 = clipped.y1 + rows_per_buffer * (j + 1) }; - if (remaining_rows < rows_per_buffer) { + if (self->SH1107_addressing) { + // one row only for SH1107 in vertical (column) mode + subrectangle.y1 = clipped.y1 + j; + subrectangle.y2 = clipped.y1 + (j + 1); + }; + if ((remaining_rows < rows_per_buffer) && (!self->SH1107_addressing)) { subrectangle.y2 = subrectangle.y1 + remaining_rows; } - remaining_rows -= rows_per_buffer; + if (self->SH1107_addressing) { + remaining_rows -= 1; + } else { + remaining_rows -= rows_per_buffer; + } displayio_display_core_set_region_to_update(&self->core, self->set_column_command, self->set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false, - &subrectangle, self->column_and_page_addressing); + &subrectangle, self->SH1107_addressing); uint16_t subrectangle_size_bytes; if (self->core.colorspace.depth >= 8) { diff --git a/shared-module/displayio/Display.h b/shared-module/displayio/Display.h index 86c2a9360..cc9cd54c4 100644 --- a/shared-module/displayio/Display.h +++ b/shared-module/displayio/Display.h @@ -61,7 +61,7 @@ typedef struct { bool updating_backlight; bool backlight_on_high; // new quirk for sh1107 - bool column_and_page_addressing; + bool SH1107_addressing; } displayio_display_obj_t; void displayio_display_background(displayio_display_obj_t* self); diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 397ceb4fd..3391a56b4 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -238,6 +238,7 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c for (uint8_t pass = 0; pass < passes; pass++) { uint16_t remaining_rows = displayio_area_height(&clipped); + // added false parameter at end for SH1107_addressing quirk if (self->set_row_window_command != NO_COMMAND) { displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 19e45e6b6..4e36e4dd1 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -41,7 +41,7 @@ #include #define DISPLAYIO_CORE_DEBUG(...) (void)0 -// #define DISPLAYIO_CORE_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) +//#define DISPLAYIO_CORE_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) void displayio_display_core_construct(displayio_display_core_t* self, mp_obj_t bus, uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, @@ -57,7 +57,7 @@ void displayio_display_core_construct(displayio_display_core_t* self, self->colstart = colstart; self->rowstart = rowstart; self->last_refresh = 0; - + // (framebufferdisplay already validated its 'bus' is a buffer-protocol object) if (bus) { if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { @@ -211,7 +211,7 @@ void displayio_display_core_end_transaction(displayio_display_core_t* self) { void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, bool data_as_commands, bool always_toggle_chip_select, - displayio_area_t* area, bool column_and_page_addressing) { + displayio_area_t* area, bool SH1107_addressing) { uint16_t x1 = area->x1; uint16_t x2 = area->x2; uint16_t y1 = area->y1; @@ -256,12 +256,13 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, data[data_length++] = x2 >> 8; data[data_length++] = x2 & 0xff; } - // Quirk for SH1107 "column_and_page_addressing" - // Column lower command = 0x00, Column upper command = 0x10 - if (column_and_page_addressing) { - data[0] = 0x00 | (x1 & 0x0F); - data[1] = 0x10 | (x1 >> 4); - data_length = 2; + // Quirk for SH1107 "SH1107_addressing" + // Note... column is y! page is x! + // Page address command = 0xB0 + if (SH1107_addressing) { + // set the page to our x value + data[0] = 0xB0 | (x1 & 0x07); + data_length = 1; } self->send(self->bus, data_type, chip_select, data, data_length); displayio_display_core_end_transaction(self); @@ -294,11 +295,13 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, data[data_length++] = y2 >> 8; data[data_length++] = y2 & 0xff; } - // Quirk for SH1107 "column_and_page_addressing" - // Page address command = 0xB0 - if (column_and_page_addressing) { - data[0] = 0xB0 | (y1 & 0x07); - data_length = 1; + // Quirk for SH1107 "SH1107_addressing" + // Note... column is y! page is x! + // Column lower command = 0x00, Column upper command = 0x10 + if (SH1107_addressing) { + data[0] = y1 & 0x0F; // 0x00 to 0x0F + data[1] = (y1 >> 4 & 0x0F) | 0x10; // 0x10 to 0x17 + data_length = 2; } self->send(self->bus, data_type, chip_select, data, data_length); @@ -319,7 +322,7 @@ void displayio_display_core_start_refresh(displayio_display_core_t* self) { void displayio_display_core_finish_refresh(displayio_display_core_t* self) { if (self->current_group != NULL) { - DISPLAYIO_CORE_DEBUG("displayiocore group_finish_refresh\n"); +// DISPLAYIO_CORE_DEBUG("displayiocore group_finish_refresh\n"); displayio_group_finish_refresh(self->current_group); } self->full_refresh = false; diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index 1c880be44..ad9998a2f 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -77,7 +77,7 @@ void displayio_display_core_end_transaction(displayio_display_core_t* self); void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, bool data_as_commands, bool always_toggle_chip_select, - displayio_area_t* area, bool column_and_page_addressing); + displayio_area_t* area, bool SH1107_addressing); void release_display_core(displayio_display_core_t* self); -- cgit v1.2.3 From 19dbff67f2a4921ccbe06fdf29e229225e8aed2d Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Fri, 25 Sep 2020 00:26:39 -0400 Subject: Fixed page set mask to be four bits! --- shared-module/displayio/display_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 4e36e4dd1..6e05b4757 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -261,7 +261,7 @@ void displayio_display_core_set_region_to_update(displayio_display_core_t* self, // Page address command = 0xB0 if (SH1107_addressing) { // set the page to our x value - data[0] = 0xB0 | (x1 & 0x07); + data[0] = 0xB0 | (x1 & 0x0F); data_length = 1; } self->send(self->bus, data_type, chip_select, data, data_length); -- cgit v1.2.3 From b9d68bc5a6b7b63f52da6c7034d379d6de51be7e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 25 Sep 2020 11:07:22 -0700 Subject: Change I2C default to 100khz Greater that 100khz is technically out of the original spec. Background here: https://github.com/adafruit/Adafruit_CircuitPython_CLUE/issues/36 --- shared-bindings/busio/I2C.c | 4 ++-- shared-module/board/__init__.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index 157e779fd..8b456dbd3 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -39,7 +39,7 @@ //| class I2C: //| """Two wire serial protocol""" //| -//| def __init__(self, scl: microcontroller.Pin, sda: microcontroller.Pin, *, frequency: int = 400000, timeout: int = 255) -> None: +//| def __init__(self, scl: microcontroller.Pin, sda: microcontroller.Pin, *, frequency: int = 100000, timeout: int = 255) -> None: //| //| """I2C is a two-wire protocol for communicating between devices. At the //| physical level it consists of 2 wires: SCL and SDA, the clock and data @@ -70,7 +70,7 @@ STATIC mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, con 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_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 400000} }, + { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} }, { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 255} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 7d99f2d4e..fb4f731b8 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -61,7 +61,7 @@ mp_obj_t common_hal_board_create_i2c(void) { busio_i2c_obj_t *self = &i2c_obj; self->base.type = &busio_i2c_type; - common_hal_busio_i2c_construct(self, DEFAULT_I2C_BUS_SCL, DEFAULT_I2C_BUS_SDA, 400000, 0); + common_hal_busio_i2c_construct(self, DEFAULT_I2C_BUS_SCL, DEFAULT_I2C_BUS_SDA, 100000, 0); i2c_singleton = (mp_obj_t)self; return i2c_singleton; } -- cgit v1.2.3 From b92154357145f4e7d976306490ef33b5d5fe9c92 Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Fri, 25 Sep 2020 21:27:29 -0400 Subject: Requested changes take 1 --- .../atmel-samd/boards/hallowing_m0_express/board.c | 3 ++- .../atmel-samd/boards/hallowing_m4_express/board.c | 3 ++- ports/atmel-samd/boards/monster_m4sk/board.c | 3 ++- ports/atmel-samd/boards/pewpew_m4/board.c | 3 ++- ports/atmel-samd/boards/pybadge/board.c | 3 ++- ports/atmel-samd/boards/pybadge_airlift/board.c | 3 ++- ports/atmel-samd/boards/pygamer/board.c | 3 ++- ports/atmel-samd/boards/pygamer_advance/board.c | 3 ++- ports/atmel-samd/boards/pyportal/board.c | 3 ++- ports/atmel-samd/boards/pyportal_titano/board.c | 3 ++- .../boards/seeeduino_wio_terminal/board.c | 3 ++- ports/nrf/boards/clue_nrf52840_express/board.c | 3 ++- ports/nrf/boards/hiibot_bluefi/board.c | 3 ++- .../boards/makerdiary_nrf52840_m2_devkit/board.c | 3 ++- ports/nrf/boards/ohs2020_badge/board.c | 3 ++- ports/stm/boards/meowbit_v121/board.c | 3 ++- shared-module/displayio/Display.c | 25 ++++++---------------- shared-module/displayio/display_core.c | 4 ++-- 18 files changed, 41 insertions(+), 36 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/boards/hallowing_m0_express/board.c b/ports/atmel-samd/boards/hallowing_m0_express/board.c index 4717e6ceb..14a2bdb81 100644 --- a/ports/atmel-samd/boards/hallowing_m0_express/board.c +++ b/ports/atmel-samd/boards/hallowing_m0_express/board.c @@ -110,7 +110,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // not SH1107 } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/hallowing_m4_express/board.c b/ports/atmel-samd/boards/hallowing_m4_express/board.c index 7da1d8128..61e797d65 100644 --- a/ports/atmel-samd/boards/hallowing_m4_express/board.c +++ b/ports/atmel-samd/boards/hallowing_m4_express/board.c @@ -91,7 +91,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // not SH1107 } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/monster_m4sk/board.c b/ports/atmel-samd/boards/monster_m4sk/board.c index 4dd65f8c9..45fea9d52 100644 --- a/ports/atmel-samd/boards/monster_m4sk/board.c +++ b/ports/atmel-samd/boards/monster_m4sk/board.c @@ -92,7 +92,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pewpew_m4/board.c b/ports/atmel-samd/boards/pewpew_m4/board.c index 52a52b4b7..d02e0dc01 100644 --- a/ports/atmel-samd/boards/pewpew_m4/board.c +++ b/ports/atmel-samd/boards/pewpew_m4/board.c @@ -143,7 +143,8 @@ void board_init(void) { false, // data_as_commands false, // auto_refresh 20, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pybadge/board.c b/ports/atmel-samd/boards/pybadge/board.c index 45298acc2..35f228c75 100644 --- a/ports/atmel-samd/boards/pybadge/board.c +++ b/ports/atmel-samd/boards/pybadge/board.c @@ -114,7 +114,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pybadge_airlift/board.c b/ports/atmel-samd/boards/pybadge_airlift/board.c index 7495c7d48..fe3e4a017 100644 --- a/ports/atmel-samd/boards/pybadge_airlift/board.c +++ b/ports/atmel-samd/boards/pybadge_airlift/board.c @@ -92,7 +92,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pygamer/board.c b/ports/atmel-samd/boards/pygamer/board.c index 2e83440ea..b478b5947 100644 --- a/ports/atmel-samd/boards/pygamer/board.c +++ b/ports/atmel-samd/boards/pygamer/board.c @@ -114,7 +114,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pygamer_advance/board.c b/ports/atmel-samd/boards/pygamer_advance/board.c index 330446b6f..7dfe07c00 100644 --- a/ports/atmel-samd/boards/pygamer_advance/board.c +++ b/ports/atmel-samd/boards/pygamer_advance/board.c @@ -92,7 +92,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pyportal/board.c b/ports/atmel-samd/boards/pyportal/board.c index d14b6b6a5..cd94f6887 100644 --- a/ports/atmel-samd/boards/pyportal/board.c +++ b/ports/atmel-samd/boards/pyportal/board.c @@ -100,7 +100,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/pyportal_titano/board.c b/ports/atmel-samd/boards/pyportal_titano/board.c index 0ee2e68aa..dc417f5d1 100644 --- a/ports/atmel-samd/boards/pyportal_titano/board.c +++ b/ports/atmel-samd/boards/pyportal_titano/board.c @@ -117,7 +117,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c b/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c index b7fc736eb..58d0beca8 100644 --- a/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c +++ b/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c @@ -105,7 +105,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/nrf/boards/clue_nrf52840_express/board.c b/ports/nrf/boards/clue_nrf52840_express/board.c index 45452a35e..523bd7677 100644 --- a/ports/nrf/boards/clue_nrf52840_express/board.c +++ b/ports/nrf/boards/clue_nrf52840_express/board.c @@ -91,7 +91,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // not SH1107 } bool board_requests_safe_mode(void) { diff --git a/ports/nrf/boards/hiibot_bluefi/board.c b/ports/nrf/boards/hiibot_bluefi/board.c index 6b53cab13..93e31aef0 100644 --- a/ports/nrf/boards/hiibot_bluefi/board.c +++ b/ports/nrf/boards/hiibot_bluefi/board.c @@ -92,7 +92,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/nrf/boards/makerdiary_nrf52840_m2_devkit/board.c b/ports/nrf/boards/makerdiary_nrf52840_m2_devkit/board.c index e7f946f4d..e08d00dac 100644 --- a/ports/nrf/boards/makerdiary_nrf52840_m2_devkit/board.c +++ b/ports/nrf/boards/makerdiary_nrf52840_m2_devkit/board.c @@ -92,7 +92,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/nrf/boards/ohs2020_badge/board.c b/ports/nrf/boards/ohs2020_badge/board.c index 9fcf9d2bf..ec52690ce 100644 --- a/ports/nrf/boards/ohs2020_badge/board.c +++ b/ports/nrf/boards/ohs2020_badge/board.c @@ -91,7 +91,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - false); // backlight_on_high + false, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/ports/stm/boards/meowbit_v121/board.c b/ports/stm/boards/meowbit_v121/board.c index b74f13516..f67b4a49d 100644 --- a/ports/stm/boards/meowbit_v121/board.c +++ b/ports/stm/boards/meowbit_v121/board.c @@ -111,7 +111,8 @@ void board_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true); // backlight_on_high + true, // backlight_on_high + false); // SH1107_addressing } bool board_requests_safe_mode(void) { diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index afc4b7564..9864e9f9d 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -252,14 +252,8 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* // write one single row at a time if (self->SH1107_addressing) { subrectangles = rows_per_buffer; // vertical (column mode) write each separately (height times) - } - - // Skip this recalculation of subrectangles if SH1107 (each subrectangle is a single row) - // [mdroberts1243] I am worried/confused about the pixels_in_byte_share_row calculation though - // since it makes sense to be on a byte boundary (actually a page boundary too) - // seems to work as is though. - if ((displayio_area_size(&clipped) > buffer_size * pixels_per_word) - && (!self->SH1107_addressing)) { + rows_per_buffer = 1; + } else if (displayio_area_size(&clipped) > buffer_size * pixels_per_word) { rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); if (rows_per_buffer == 0) { rows_per_buffer = 1; @@ -297,18 +291,13 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* .y2 = clipped.y1 + rows_per_buffer * (j + 1) }; if (self->SH1107_addressing) { - // one row only for SH1107 in vertical (column) mode - subrectangle.y1 = clipped.y1 + j; - subrectangle.y2 = clipped.y1 + (j + 1); - }; - if ((remaining_rows < rows_per_buffer) && (!self->SH1107_addressing)) { + // one row only for SH1107 in vertical (column) mode + subrectangle.y1 = clipped.y1 + j; + subrectangle.y2 = clipped.y1 + (j + 1); + } else if (remaining_rows < rows_per_buffer) { subrectangle.y2 = subrectangle.y1 + remaining_rows; } - if (self->SH1107_addressing) { - remaining_rows -= 1; - } else { - remaining_rows -= rows_per_buffer; - } + remaining_rows -= rows_per_buffer; displayio_display_core_set_region_to_update(&self->core, self->set_column_command, self->set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false, diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 6e05b4757..eb8c8f3b4 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -41,7 +41,7 @@ #include #define DISPLAYIO_CORE_DEBUG(...) (void)0 -//#define DISPLAYIO_CORE_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) +// #define DISPLAYIO_CORE_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) void displayio_display_core_construct(displayio_display_core_t* self, mp_obj_t bus, uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, @@ -322,7 +322,7 @@ void displayio_display_core_start_refresh(displayio_display_core_t* self) { void displayio_display_core_finish_refresh(displayio_display_core_t* self) { if (self->current_group != NULL) { -// DISPLAYIO_CORE_DEBUG("displayiocore group_finish_refresh\n"); + DISPLAYIO_CORE_DEBUG("displayiocore group_finish_refresh\n"); displayio_group_finish_refresh(self->current_group); } self->full_refresh = false; -- cgit v1.2.3 From 79ca430ddf25a71c73d6219fb68160fb405c3777 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 24 Sep 2020 13:58:45 -0500 Subject: Match: address -> id --- ports/atmel-samd/common-hal/canio/Listener.c | 60 ++++++++++++++-------------- shared-bindings/canio/Match.c | 46 ++++++++++----------- shared-bindings/canio/Match.h | 4 +- shared-module/canio/Match.c | 8 ++-- shared-module/canio/Match.h | 2 +- 5 files changed, 60 insertions(+), 60 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/common-hal/canio/Listener.c b/ports/atmel-samd/common-hal/canio/Listener.c index 02cfde9cc..d21ebbb31 100644 --- a/ports/atmel-samd/common-hal/canio/Listener.c +++ b/ports/atmel-samd/common-hal/canio/Listener.c @@ -58,8 +58,8 @@ STATIC void static_assertions(void) { MP_STATIC_ASSERT(CAN_XIDFE_0_EFEC_STF0M_Val + 1 == CAN_XIDFE_0_EFEC_STF1M_Val); } -STATIC bool single_address_filter(canio_match_obj_t *match) { - return match->mask == 0 || match->mask == match->address; +STATIC bool single_id_filter(canio_match_obj_t *match) { + return match->mask == 0 || match->mask == match->id; } STATIC bool standard_filter_in_use(CanMramSidfe *filter) { @@ -76,7 +76,7 @@ STATIC size_t num_filters_needed(size_t nmatch, canio_match_obj_t **matches, boo if (extended != matches[i]->extended) { continue; } - if (single_address_filter(matches[i])) { + if (single_id_filter(matches[i])) { num_half_filters_needed += 1; } else { num_half_filters_needed += 2; @@ -191,7 +191,7 @@ STATIC void install_extended_filter(CanMramXidfe *extended, int id1, int id2, in } -#define NO_ADDRESS (-1) +#define NO_ID (-1) void set_filters(canio_listener_obj_t *self, size_t nmatch, canio_match_obj_t **matches) { int fifo = self->fifo_idx; @@ -207,31 +207,31 @@ void set_filters(canio_listener_obj_t *self, size_t nmatch, canio_match_obj_t ** CanMramSidfe *standard = next_standard_filter(self, NULL); CanMramXidfe *extended = next_extended_filter(self, NULL); - int first_address = NO_ADDRESS; + int first_id = NO_ID; - // step 1: single address standard matches + // step 1: single id standard matches // we have to gather up pairs and stuff them in a single filter entry for(size_t i = 0; iextended) { continue; } - if (!single_address_filter(match)) { + if (!single_id_filter(match)) { continue; } - if (first_address != NO_ADDRESS) { - install_standard_filter(standard, first_address, match->address, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); - first_address = NO_ADDRESS; + if (first_id != NO_ID) { + install_standard_filter(standard, first_id, match->id, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); + first_id = NO_ID; standard = next_standard_filter(self, standard); } else { - first_address = match->address; + first_id = match->id; } } - // step 1.5. odd single address standard match - if (first_address != NO_ADDRESS) { - install_standard_filter(standard, first_address, first_address, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); + // step 1.5. odd single id standard match + if (first_id != NO_ID) { + install_standard_filter(standard, first_id, first_id, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_DUAL_Val); standard = next_standard_filter(self, standard); - first_address = NO_ADDRESS; + first_id = NO_ID; } // step 2: standard mask filter @@ -240,36 +240,36 @@ void set_filters(canio_listener_obj_t *self, size_t nmatch, canio_match_obj_t ** if (match->extended) { continue; } - if (single_address_filter(match)) { + if (single_id_filter(match)) { continue; } - install_standard_filter(standard, match->address, match->mask, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_CLASSIC_Val); + install_standard_filter(standard, match->id, match->mask, CAN_SIDFE_0_SFEC_STF0M_Val + fifo, CAN_SIDFE_0_SFT_CLASSIC_Val); standard = next_standard_filter(self, standard); } - // step 3: single address extended matches + // step 3: single id extended matches // we have to gather up pairs and stuff them in a single filter entry for(size_t i = 0; iextended) { continue; } - if (!single_address_filter(match)) { + if (!single_id_filter(match)) { continue; } - if (first_address != NO_ADDRESS) { - install_extended_filter(extended, first_address, match->address, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); - first_address = NO_ADDRESS; + if (first_id != NO_ID) { + install_extended_filter(extended, first_id, match->id, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); + first_id = NO_ID; extended = next_extended_filter(self, extended); } else { - first_address = match->address; + first_id = match->id; } } - // step 3.5. odd single address standard match - if (first_address != NO_ADDRESS) { - install_extended_filter(extended, first_address, first_address, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); + // step 3.5. odd single id standard match + if (first_id != NO_ID) { + install_extended_filter(extended, first_id, first_id, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_DUAL_Val); extended = next_extended_filter(self, extended); - first_address = NO_ADDRESS; + first_id = NO_ID; } // step 4: extended mask filters @@ -278,10 +278,10 @@ void set_filters(canio_listener_obj_t *self, size_t nmatch, canio_match_obj_t ** if (!match->extended) { continue; } - if (single_address_filter(match)) { + if (single_id_filter(match)) { continue; } - install_extended_filter(extended, match->address, match->mask, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_CLASSIC_Val); + install_extended_filter(extended, match->id, match->mask, CAN_XIDFE_0_EFEC_STF0M_Val + fifo, CAN_XIDFE_1_EFT_CLASSIC_Val); extended = next_extended_filter(self, extended); } @@ -363,7 +363,7 @@ bool common_hal_canio_listener_readinto(canio_listener_obj_t *self, canio_messag if (message->extended) { message->id = hw_message->rxf0.bit.ID; } else { - message->id = hw_message->rxf0.bit.ID >> 18; // short addresses are left-justified + message->id = hw_message->rxf0.bit.ID >> 18; // short ids are left-justified } message->rtr = hw_message->rxf0.bit.RTR; message->size = hw_message->rxf1.bit.DLC; diff --git a/shared-bindings/canio/Match.c b/shared-bindings/canio/Match.c index ff5d028fa..91a9dd02a 100644 --- a/shared-bindings/canio/Match.c +++ b/shared-bindings/canio/Match.c @@ -33,19 +33,19 @@ //| """Describe CAN bus messages to match""" //| //| -//| def __init__(self, address: int, *, mask: int = 0, extended: bool = False): +//| def __init__(self, id: int, *, mask: int = 0, extended: bool = False): //| """Construct a Match with the given properties. //| -//| If mask is nonzero, then the filter is for any sender which matches all -//| the nonzero bits in mask. Otherwise, it matches exactly the given address. -//| If extended is true then only extended addresses are matched, otherwise -//| only standard addresses are matched.""" +//| If mask is nonzero, then the filter is for any id which matches all +//| the nonzero bits in mask. Otherwise, it matches exactly the given id. +//| If extended is true then only extended ids are matched, otherwise +//| only standard ids are matched.""" //| STATIC mp_obj_t canio_match_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, ARG_mask, ARG_extended, NUM_ARGS }; + enum { ARG_id, ARG_mask, ARG_extended, NUM_ARGS }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_address, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_id, MP_ARG_INT | MP_ARG_REQUIRED }, { MP_QSTR_mask, MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, }; @@ -54,44 +54,44 @@ STATIC mp_obj_t canio_match_make_new(const mp_obj_type_t *type, size_t n_args, c mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - int address_bits = args[ARG_extended].u_bool ? 0x1fffffff : 0x7ff; - int address = args[ARG_address].u_int; + int id_bits = args[ARG_extended].u_bool ? 0x1fffffff : 0x7ff; + int id = args[ARG_id].u_int; int mask = args[ARG_mask].u_int; - if (address & ~address_bits) { - mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_address); + if (id & ~id_bits) { + mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_id); } - if (mask & ~address_bits) { + if (mask & ~id_bits) { mp_raise_ValueError_varg(translate("%q out of range"), MP_QSTR_mask); } canio_match_obj_t *self = m_new_obj(canio_match_obj_t); self->base.type = &canio_match_type; - common_hal_canio_match_construct(self, args[ARG_address].u_int, args[ARG_mask].u_int, args[ARG_extended].u_bool); + common_hal_canio_match_construct(self, args[ARG_id].u_int, args[ARG_mask].u_int, args[ARG_extended].u_bool); return self; } -//| address: int -//| """The address to match""" +//| id: int +//| """The id to match""" //| -STATIC mp_obj_t canio_match_address_get(mp_obj_t self_in) { +STATIC mp_obj_t canio_match_id_get(mp_obj_t self_in) { canio_match_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_address(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_match_get_id(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(canio_match_address_get_obj, canio_match_address_get); +MP_DEFINE_CONST_FUN_OBJ_1(canio_match_id_get_obj, canio_match_id_get); -const mp_obj_property_t canio_match_address_obj = { +const mp_obj_property_t canio_match_id_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_match_address_get_obj, + .proxy = {(mp_obj_t)&canio_match_id_get_obj, (mp_obj_t)&mp_const_none_obj, (mp_obj_t)&mp_const_none_obj}, }; //| //| mask: int -//| """The optional mask of addresses to match""" +//| """The optional mask of ids to match""" //| STATIC mp_obj_t canio_match_mask_get(mp_obj_t self_in) { @@ -108,7 +108,7 @@ const mp_obj_property_t canio_match_mask_obj = { }; //| extended: bool -//| """True to match extended addresses, False to match standard addresses""" +//| """True to match extended ids, False to match standard ides""" //| STATIC mp_obj_t canio_match_extended_get(mp_obj_t self_in) { @@ -125,7 +125,7 @@ const mp_obj_property_t canio_match_extended_obj = { }; STATIC const mp_rom_map_elem_t canio_match_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_address), MP_ROM_PTR(&canio_match_address_obj) }, + { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_match_id_obj) }, { MP_ROM_QSTR(MP_QSTR_mask), MP_ROM_PTR(&canio_match_mask_obj) }, { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_match_extended_obj) }, }; diff --git a/shared-bindings/canio/Match.h b/shared-bindings/canio/Match.h index 88996d730..01a75fd1c 100644 --- a/shared-bindings/canio/Match.h +++ b/shared-bindings/canio/Match.h @@ -31,7 +31,7 @@ extern const mp_obj_type_t canio_match_type; -void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended); -int common_hal_canio_match_get_address(const canio_match_obj_t *self); +void common_hal_canio_match_construct(canio_match_obj_t *self, int id, int mask, bool extended); +int common_hal_canio_match_get_id(const canio_match_obj_t *self); int common_hal_canio_match_get_mask(const canio_match_obj_t *self); bool common_hal_canio_match_get_extended(const canio_match_obj_t *self); diff --git a/shared-module/canio/Match.c b/shared-module/canio/Match.c index 9e33b956f..b4e8616e9 100644 --- a/shared-module/canio/Match.c +++ b/shared-module/canio/Match.c @@ -26,14 +26,14 @@ #include "shared-module/canio/Match.h" -void common_hal_canio_match_construct(canio_match_obj_t *self, int address, int mask, bool extended) { - self->address = address; +void common_hal_canio_match_construct(canio_match_obj_t *self, int id, int mask, bool extended) { + self->id = id; self->mask = mask; self->extended = extended; } -int common_hal_canio_match_get_address(const canio_match_obj_t *self) { - return self->address; +int common_hal_canio_match_get_id(const canio_match_obj_t *self) { + return self->id; } int common_hal_canio_match_get_mask(const canio_match_obj_t *self) { return self->mask; diff --git a/shared-module/canio/Match.h b/shared-module/canio/Match.h index 25f047f37..b52191d7c 100644 --- a/shared-module/canio/Match.h +++ b/shared-module/canio/Match.h @@ -30,7 +30,7 @@ typedef struct { mp_obj_base_t base; - int address; + int id; int mask; bool extended; } canio_match_obj_t; -- cgit v1.2.3 From 8d45be1cd99c6fbfcb69877ab335e010810c54fd Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 24 Sep 2020 15:25:06 -0500 Subject: canio: Split RemoteTransmissionRequest to its own class It reuses most of canio.Message's implementation, and structure --- shared-bindings/canio/CAN.c | 6 +- shared-bindings/canio/Listener.c | 6 +- shared-bindings/canio/Message.c | 132 ++++++++++++++++++++++++--------------- shared-bindings/canio/Message.h | 7 ++- shared-bindings/canio/__init__.c | 1 + shared-module/canio/Message.c | 10 ++- 6 files changed, 99 insertions(+), 63 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/canio/CAN.c b/shared-bindings/canio/CAN.c index ff27bb204..6b7a3878e 100644 --- a/shared-bindings/canio/CAN.c +++ b/shared-bindings/canio/CAN.c @@ -265,7 +265,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_restart_obj, canio_can_restart); //| //| An empty filter list causes all messages to be accepted. //| -//| Timeout dictates how long readinto, read and next() will block.""" +//| Timeout dictates how long receive() and next() will block.""" //| ... //| STATIC mp_obj_t canio_can_listen(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -334,8 +334,8 @@ STATIC mp_obj_t canio_can_send(mp_obj_t self_in, mp_obj_t message_in) { canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in); common_hal_canio_can_check_for_deinit(self); mp_obj_type_t *message_type = mp_obj_get_type(message_in); - if (message_type != &canio_message_type) { - mp_raise_TypeError_varg(translate("expected '%q' but got '%q'"), MP_QSTR_Message, message_type->name); + if (message_type != &canio_message_type && message_type != &canio_remote_transmission_request_type) { + mp_raise_TypeError_varg(translate("expected '%q' or '%q' but got '%q'"), MP_QSTR_Message, MP_QSTR_RemoteTransmissionRequest, message_type->name); } canio_message_obj_t *message = message_in; diff --git a/shared-bindings/canio/Listener.c b/shared-bindings/canio/Listener.c index 5159c8481..9f3fe05c5 100644 --- a/shared-bindings/canio/Listener.c +++ b/shared-bindings/canio/Listener.c @@ -50,9 +50,13 @@ STATIC mp_obj_t canio_listener_receive(mp_obj_t self_in) { common_hal_canio_listener_check_for_deinit(self); canio_message_obj_t *message = m_new_obj(canio_message_obj_t); - message->base.type = &canio_message_type; if (common_hal_canio_listener_receiveinto(self, message)) { + if (message->rtr) { + message->base.type = &canio_remote_transmission_request_type; + } else { + message->base.type = &canio_message_type; + } return message; } else { m_free(message); // message did not escape into vm diff --git a/shared-bindings/canio/Message.c b/shared-bindings/canio/Message.c index 8d1828fba..ae03c25e7 100644 --- a/shared-bindings/canio/Message.c +++ b/shared-bindings/canio/Message.c @@ -31,28 +31,22 @@ #include "py/runtime.h" //| class Message: -//| def __init__(self, id: int=0, data: Optional[bytes] = None, *, size: Optional[int] = None, rtr: bool = False, extended: bool = False): -//| """Construct a Message to use with a CAN bus. Provide arguments to create a message to send. Otherwise, use Listener.readinto() to read a message. +//| def __init__(self, id: int, data: bytes, *, extended: bool = False): +//| """Construct a Message to send on a CAN bus. //| //| :param int id: The numeric ID of the message //| :param bytes data: The content of the message -//| :param int size: The amount of data requested, for an rtr -//| :param bool rtr: True if the message represents an rtr (Remote Transmission Request) //| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier //| -//| In CAN, messages can have a size from 0 to 8 bytes. -//| -//| For a non-rtr message, specify ``data``. For an rtr-message, specify either ``data`` (a dummy buffer of the requested size) or ``size``. +//| In CAN, messages can have a length from 0 to 8 bytes. //| """ //| ... //| STATIC mp_obj_t canio_message_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_id, ARG_data, ARG_size, ARG_rtr, ARG_extended, NUM_ARGS }; + enum { ARG_id, ARG_data, ARG_extended, NUM_ARGS }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_id, MP_ARG_INT, {.u_obj = 0} }, - { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = 0} }, - { MP_QSTR_size, MP_ARG_INT, {.u_int = -1} }, - { MP_QSTR_rtr, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_id, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED }, { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -60,26 +54,8 @@ STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - bool rtr = args[ARG_rtr].u_bool; - bool extended = args[ARG_extended].u_bool; - size_t size = (size_t)args[ARG_size].u_int; - bool specified_size = (size != (size_t)-1); - bool specified_data = (args[ARG_data].u_obj != NULL); - - if (specified_size && specified_data) { - mp_raise_TypeError(translate("specify size or data, but not both")); - } - mp_buffer_info_t data; - if (specified_data) { - mp_get_buffer_raise(args[ARG_data].u_obj, &data, MP_BUFFER_READ); - } else if (specified_size) { - data.buf = 0; - data.len = size; - } else { - data.buf = 0; - data.len = 0; - } + mp_get_buffer_raise(args[ARG_data].u_obj, &data, MP_BUFFER_READ); if (data.len > 8) { mp_raise_ValueError(translate("Messages limited to 8 bytes")); @@ -87,7 +63,7 @@ STATIC mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, canio_message_obj_t *self = m_new_obj(canio_message_obj_t); self->base.type = &canio_message_type; - common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, rtr, extended); + common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, args[ARG_extended].u_bool); return self; } @@ -115,13 +91,11 @@ STATIC const mp_obj_property_t canio_message_id_obj = { }; //| data: bytes -//| """The content of the message, or dummy content in the case of an rtr. -//| -//| Assigning to data also clears the rtr flag, if it was set.""" +//| """The content of the message""" //| STATIC mp_obj_t canio_message_data_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; - return mp_obj_new_bytes((const byte*)common_hal_canio_message_get_data(self), common_hal_canio_message_get_size(self)); + return mp_obj_new_bytes((const byte*)common_hal_canio_message_get_data(self), common_hal_canio_message_get_length(self)); } MP_DEFINE_CONST_FUN_OBJ_1(canio_message_data_get_obj, canio_message_data_get); @@ -147,7 +121,7 @@ STATIC const mp_obj_property_t canio_message_data_obj = { //| extended: bool -//| """True if the message represents a remote transmission request (RTR)""" +//| """True if the message's id is an extended id""" //| STATIC mp_obj_t canio_message_extended_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; @@ -170,36 +144,80 @@ STATIC const mp_obj_property_t canio_message_extended_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| class RemoteTransmissionRequest: +//| def __init__(self, id: int, length: int, *, extended: bool = False): +//| """Construct a Message to send on a CAN bus. +//| +//| :param int id: The numeric ID of the requested message +//| :param int length: The length of the requested message +//| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier +//| +//| In CAN, messages can have a length from 0 to 8 bytes. +//| """ +//| ... +//| +STATIC mp_obj_t canio_remote_transmission_request_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_id, ARG_length, ARG_extended, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_length, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, + }; + 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); + + int length = args[ARG_length].u_int; + if (length < 0 || length > 8) { + mp_raise_ValueError(translate("Messages limited to 8 bytes")); + } -//| rtr: bool -//| """True if the message represents a remote transmission request (RTR). Setting rtr to true zeros out data""" + canio_message_obj_t *self = m_new_obj(canio_message_obj_t); + self->base.type = &canio_remote_transmission_request_type; + common_hal_canio_message_construct(self, args[ARG_id].u_int, NULL, length, args[ARG_extended].u_bool); + return self; +} + +//| extended: bool +//| """True if the message's id is an extended id""" +//| + +//| id: int +//| """The numeric ID of the message""" +//| + +//| length: int +//| """The length of the requested message.""" //| -STATIC mp_obj_t canio_message_rtr_get(const mp_obj_t self_in) { +STATIC mp_obj_t canio_remote_transmission_request_length_get(const mp_obj_t self_in) { canio_message_obj_t *self = self_in; - return mp_obj_new_bool(common_hal_canio_message_get_rtr(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_get_length(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(canio_message_rtr_get_obj, canio_message_rtr_get); +MP_DEFINE_CONST_FUN_OBJ_1(canio_remote_transmission_request_length_get_obj, canio_remote_transmission_request_length_get); -STATIC mp_obj_t canio_message_rtr_set(const mp_obj_t self_in, const mp_obj_t rtr) { +STATIC mp_obj_t canio_remote_transmission_request_length_set(const mp_obj_t self_in, const mp_obj_t length_in) { canio_message_obj_t *self = self_in; - common_hal_canio_message_set_rtr(self, mp_obj_is_true(rtr)); + int length = mp_obj_get_int(length_in); + if (length < 0 || length > 8) { + mp_raise_ValueError(translate("Messages limited to 8 bytes")); + } + common_hal_canio_remote_transmission_request_set_length(self, length); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_2(canio_message_rtr_set_obj, canio_message_rtr_set); +MP_DEFINE_CONST_FUN_OBJ_2(canio_remote_transmission_request_length_set_obj, canio_remote_transmission_request_length_set); -STATIC const mp_obj_property_t canio_message_rtr_obj = { +STATIC const mp_obj_property_t canio_remote_transmission_request_length_obj = { .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_message_rtr_get_obj, - (mp_obj_t)&canio_message_rtr_set_obj, + .proxy = {(mp_obj_t)&canio_remote_transmission_request_length_get_obj, + (mp_obj_t)&canio_remote_transmission_request_length_set_obj, (mp_obj_t)&mp_const_none_obj}, }; - STATIC const mp_rom_map_elem_t canio_message_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) }, { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&canio_message_data_obj) }, - { MP_ROM_QSTR(MP_QSTR_rtr), MP_ROM_PTR(&canio_message_rtr_obj) }, { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_message_extended_obj) }, }; STATIC MP_DEFINE_CONST_DICT(canio_message_locals_dict, canio_message_locals_dict_table); @@ -210,3 +228,17 @@ const mp_obj_type_t canio_message_type = { .make_new = canio_message_make_new, .locals_dict = (mp_obj_t)&canio_message_locals_dict, }; + +STATIC const mp_rom_map_elem_t canio_remote_transmission_request_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_length), MP_ROM_PTR(&canio_remote_transmission_request_length_obj) }, + { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_message_extended_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_remote_transmission_request_locals_dict, canio_remote_transmission_request_locals_dict_table); + +const mp_obj_type_t canio_remote_transmission_request_type = { + { &mp_type_type }, + .name = MP_QSTR_RemoteTransmissionRequest, + .make_new = canio_remote_transmission_request_make_new, + .locals_dict = (mp_obj_t)&canio_remote_transmission_request_locals_dict, +}; diff --git a/shared-bindings/canio/Message.h b/shared-bindings/canio/Message.h index 34b632e84..96716864c 100644 --- a/shared-bindings/canio/Message.h +++ b/shared-bindings/canio/Message.h @@ -30,8 +30,9 @@ #include "shared-module/canio/Message.h" extern const mp_obj_type_t canio_message_type; +extern const mp_obj_type_t canio_remote_transmission_request_type; -void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended); +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool extended); const void *common_hal_canio_message_get_data(const canio_message_obj_t *self); void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size); bool common_hal_canio_message_get_extended(const canio_message_obj_t *self); @@ -40,5 +41,5 @@ int common_hal_canio_message_get_id(const canio_message_obj_t *self); void common_hal_canio_message_set_id(canio_message_obj_t *self, int id); bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self); void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr); -size_t common_hal_canio_message_get_size(const canio_message_obj_t *self); -void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size); +size_t common_hal_canio_message_get_length(const canio_message_obj_t *self); +void common_hal_canio_remote_transmission_request_set_length(canio_message_obj_t *self, size_t length); diff --git a/shared-bindings/canio/__init__.c b/shared-bindings/canio/__init__.c index 409cc20cf..f29d3ab8a 100644 --- a/shared-bindings/canio/__init__.c +++ b/shared-bindings/canio/__init__.c @@ -113,6 +113,7 @@ STATIC const mp_rom_map_elem_t canio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Listener), MP_ROM_PTR(&canio_listener_type) }, { MP_ROM_QSTR(MP_QSTR_Match), MP_ROM_PTR(&canio_match_type) }, { MP_ROM_QSTR(MP_QSTR_Message), MP_ROM_PTR(&canio_message_type) }, + { MP_ROM_QSTR(MP_QSTR_RemoteTransmissionRequest), MP_ROM_PTR(&canio_remote_transmission_request_type) }, { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR__canio) }, }; diff --git a/shared-module/canio/Message.c b/shared-module/canio/Message.c index b8ebb7859..86a3b7106 100644 --- a/shared-module/canio/Message.c +++ b/shared-module/canio/Message.c @@ -28,16 +28,14 @@ #include -void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool rtr, bool extended) +void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void *data, size_t size, bool extended) { self->id = id; self->size = size; - self->rtr = rtr; + self->rtr = !data; self->extended = extended; if (data) { memcpy(self->data, data, size); - } else { - memset(self->data, 0, size); } } @@ -65,12 +63,12 @@ const void common_hal_canio_message_set_data(canio_message_obj_t *self, const vo } -size_t common_hal_canio_message_get_size(const canio_message_obj_t *self) +size_t common_hal_canio_message_get_length(const canio_message_obj_t *self) { return self->size; } -void common_hal_canio_message_set_size(canio_message_obj_t *self, size_t size) +void common_hal_canio_remote_transmission_request_set_length(canio_message_obj_t *self, size_t size) { memset(self->data, 0, size); self->size = size; -- cgit v1.2.3 From a4cc3ad6cb75845e0dc75ede97b8287bb1af0317 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 26 Sep 2020 09:44:11 -0500 Subject: canio: RemoteTransmissionRequest: Split implementation, keep one structure This already begins obscuring things, because now there are two sets of shared-module functions for manipulating the same structure, e.g., common_hal_canio_remote_transmission_request_get_id and common_hal_canio_message_get_id --- py/circuitpy_defns.mk | 1 + shared-bindings/canio/Message.c | 85 ----------- shared-bindings/canio/Message.h | 2 - shared-bindings/canio/RemoteTransmissionRequest.c | 164 ++++++++++++++++++++++ shared-bindings/canio/RemoteTransmissionRequest.h | 42 ++++++ shared-module/canio/Message.c | 20 --- shared-module/canio/RemoteTransmissionRequest.c | 68 +++++++++ shared-module/canio/RemoteTransmissionRequest.h | 33 +++++ 8 files changed, 308 insertions(+), 107 deletions(-) create mode 100644 shared-bindings/canio/RemoteTransmissionRequest.c create mode 100644 shared-bindings/canio/RemoteTransmissionRequest.h create mode 100644 shared-module/canio/RemoteTransmissionRequest.c create mode 100644 shared-module/canio/RemoteTransmissionRequest.h (limited to 'shared-module') diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 98fa7a5f2..76c0a4db6 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -411,6 +411,7 @@ SRC_SHARED_MODULE_ALL = \ _bleio/ScanResults.c \ canio/Match.c \ canio/Message.c \ + canio/RemoteTransmissionRequest.c \ _eve/__init__.c \ _pixelbuf/PixelBuf.c \ _pixelbuf/__init__.c \ diff --git a/shared-bindings/canio/Message.c b/shared-bindings/canio/Message.c index ae03c25e7..e47e997c7 100644 --- a/shared-bindings/canio/Message.c +++ b/shared-bindings/canio/Message.c @@ -144,77 +144,6 @@ STATIC const mp_obj_property_t canio_message_extended_obj = { (mp_obj_t)&mp_const_none_obj}, }; -//| class RemoteTransmissionRequest: -//| def __init__(self, id: int, length: int, *, extended: bool = False): -//| """Construct a Message to send on a CAN bus. -//| -//| :param int id: The numeric ID of the requested message -//| :param int length: The length of the requested message -//| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier -//| -//| In CAN, messages can have a length from 0 to 8 bytes. -//| """ -//| ... -//| -STATIC mp_obj_t canio_remote_transmission_request_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_id, ARG_length, ARG_extended, NUM_ARGS }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_id, MP_ARG_INT | MP_ARG_REQUIRED }, - { MP_QSTR_length, MP_ARG_INT | MP_ARG_REQUIRED }, - { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, - }; - 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); - - int length = args[ARG_length].u_int; - if (length < 0 || length > 8) { - mp_raise_ValueError(translate("Messages limited to 8 bytes")); - } - - canio_message_obj_t *self = m_new_obj(canio_message_obj_t); - self->base.type = &canio_remote_transmission_request_type; - common_hal_canio_message_construct(self, args[ARG_id].u_int, NULL, length, args[ARG_extended].u_bool); - return self; -} - -//| extended: bool -//| """True if the message's id is an extended id""" -//| - -//| id: int -//| """The numeric ID of the message""" -//| - -//| length: int -//| """The length of the requested message.""" -//| -STATIC mp_obj_t canio_remote_transmission_request_length_get(const mp_obj_t self_in) { - canio_message_obj_t *self = self_in; - return MP_OBJ_NEW_SMALL_INT(common_hal_canio_message_get_length(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(canio_remote_transmission_request_length_get_obj, canio_remote_transmission_request_length_get); - -STATIC mp_obj_t canio_remote_transmission_request_length_set(const mp_obj_t self_in, const mp_obj_t length_in) { - canio_message_obj_t *self = self_in; - int length = mp_obj_get_int(length_in); - if (length < 0 || length > 8) { - mp_raise_ValueError(translate("Messages limited to 8 bytes")); - } - common_hal_canio_remote_transmission_request_set_length(self, length); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(canio_remote_transmission_request_length_set_obj, canio_remote_transmission_request_length_set); - - -STATIC const mp_obj_property_t canio_remote_transmission_request_length_obj = { - .base.type = &mp_type_property, - .proxy = {(mp_obj_t)&canio_remote_transmission_request_length_get_obj, - (mp_obj_t)&canio_remote_transmission_request_length_set_obj, - (mp_obj_t)&mp_const_none_obj}, -}; - STATIC const mp_rom_map_elem_t canio_message_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) }, { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&canio_message_data_obj) }, @@ -228,17 +157,3 @@ const mp_obj_type_t canio_message_type = { .make_new = canio_message_make_new, .locals_dict = (mp_obj_t)&canio_message_locals_dict, }; - -STATIC const mp_rom_map_elem_t canio_remote_transmission_request_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_message_id_obj) }, - { MP_ROM_QSTR(MP_QSTR_length), MP_ROM_PTR(&canio_remote_transmission_request_length_obj) }, - { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_message_extended_obj) }, -}; -STATIC MP_DEFINE_CONST_DICT(canio_remote_transmission_request_locals_dict, canio_remote_transmission_request_locals_dict_table); - -const mp_obj_type_t canio_remote_transmission_request_type = { - { &mp_type_type }, - .name = MP_QSTR_RemoteTransmissionRequest, - .make_new = canio_remote_transmission_request_make_new, - .locals_dict = (mp_obj_t)&canio_remote_transmission_request_locals_dict, -}; diff --git a/shared-bindings/canio/Message.h b/shared-bindings/canio/Message.h index 96716864c..adcdb095c 100644 --- a/shared-bindings/canio/Message.h +++ b/shared-bindings/canio/Message.h @@ -39,7 +39,5 @@ bool common_hal_canio_message_get_extended(const canio_message_obj_t *self); void common_hal_canio_message_set_extended(canio_message_obj_t *self, bool extended); int common_hal_canio_message_get_id(const canio_message_obj_t *self); void common_hal_canio_message_set_id(canio_message_obj_t *self, int id); -bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self); -void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr); size_t common_hal_canio_message_get_length(const canio_message_obj_t *self); void common_hal_canio_remote_transmission_request_set_length(canio_message_obj_t *self, size_t length); diff --git a/shared-bindings/canio/RemoteTransmissionRequest.c b/shared-bindings/canio/RemoteTransmissionRequest.c new file mode 100644 index 000000000..4e3f67417 --- /dev/null +++ b/shared-bindings/canio/RemoteTransmissionRequest.c @@ -0,0 +1,164 @@ +/* + * 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 "shared-bindings/canio/RemoteTransmissionRequest.h" + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +//| class RemoteTransmissionRequest: +//| def __init__(self, id: int, length: int, *, extended: bool = False): +//| """Construct a RemoteTransmissionRequest to send on a CAN bus. +//| +//| :param int id: The numeric ID of the requested message +//| :param int length: The length of the requested message +//| :param bool extended: True if the message has an extended identifier, False if it has a standard identifier +//| +//| In CAN, messages can have a length from 0 to 8 bytes. +//| """ +//| ... +//| +STATIC mp_obj_t canio_remote_transmission_request_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_id, ARG_length, ARG_extended, NUM_ARGS }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_id, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_length, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_extended, MP_ARG_BOOL, {.u_bool = false} }, + }; + 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); + + int length = args[ARG_length].u_int; + if (length < 0 || length > 8) { + mp_raise_ValueError(translate("RemoteTransmissionRequests limited to 8 bytes")); + } + + canio_remote_transmission_request_obj_t *self = m_new_obj(canio_remote_transmission_request_obj_t); + self->base.type = &canio_remote_transmission_request_type; + common_hal_canio_remote_transmission_request_construct(self, args[ARG_id].u_int, length, args[ARG_extended].u_bool); + return self; +} + + +//| id: int +//| """The numeric ID of the message""" +//| +STATIC mp_obj_t canio_remote_transmission_request_id_get(const mp_obj_t self_in) { + canio_remote_transmission_request_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_remote_transmission_request_get_id(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_remote_transmission_request_id_get_obj, canio_remote_transmission_request_id_get); + +STATIC mp_obj_t canio_remote_transmission_request_id_set(const mp_obj_t self_in, const mp_obj_t id) { + canio_remote_transmission_request_obj_t *self = self_in; + common_hal_canio_remote_transmission_request_set_id(self, mp_obj_get_int(id)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_remote_transmission_request_id_set_obj, canio_remote_transmission_request_id_set); + +STATIC const mp_obj_property_t canio_remote_transmission_request_id_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_remote_transmission_request_id_get_obj, + (mp_obj_t)&canio_remote_transmission_request_id_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| extended: bool +//| """True if the message's id is an extended id""" +//| +STATIC mp_obj_t canio_remote_transmission_request_extended_get(const mp_obj_t self_in) { + canio_remote_transmission_request_obj_t *self = self_in; + return mp_obj_new_bool(common_hal_canio_remote_transmission_request_get_extended(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_remote_transmission_request_extended_get_obj, canio_remote_transmission_request_extended_get); + +STATIC mp_obj_t canio_remote_transmission_request_extended_set(const mp_obj_t self_in, const mp_obj_t extended) { + canio_remote_transmission_request_obj_t *self = self_in; + common_hal_canio_remote_transmission_request_set_extended(self, mp_obj_is_true(extended)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_remote_transmission_request_extended_set_obj, canio_remote_transmission_request_extended_set); + + +STATIC const mp_obj_property_t canio_remote_transmission_request_extended_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_remote_transmission_request_extended_get_obj, + (mp_obj_t)&canio_remote_transmission_request_extended_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +//| extended: bool +//| """True if the message's id is an extended id""" +//| + +//| id: int +//| """The numeric ID of the message""" +//| + +//| length: int +//| """The length of the requested message.""" +//| +STATIC mp_obj_t canio_remote_transmission_request_length_get(const mp_obj_t self_in) { + canio_remote_transmission_request_obj_t *self = self_in; + return MP_OBJ_NEW_SMALL_INT(common_hal_canio_remote_transmission_request_get_length(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(canio_remote_transmission_request_length_get_obj, canio_remote_transmission_request_length_get); + +STATIC mp_obj_t canio_remote_transmission_request_length_set(const mp_obj_t self_in, const mp_obj_t length_in) { + canio_remote_transmission_request_obj_t *self = self_in; + int length = mp_obj_get_int(length_in); + if (length < 0 || length > 8) { + mp_raise_ValueError(translate("RemoteTransmissionRequests limited to 8 bytes")); + } + common_hal_canio_remote_transmission_request_set_length(self, length); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(canio_remote_transmission_request_length_set_obj, canio_remote_transmission_request_length_set); + + +STATIC const mp_obj_property_t canio_remote_transmission_request_length_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&canio_remote_transmission_request_length_get_obj, + (mp_obj_t)&canio_remote_transmission_request_length_set_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + +STATIC const mp_rom_map_elem_t canio_remote_transmission_request_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_id), MP_ROM_PTR(&canio_remote_transmission_request_id_obj) }, + { MP_ROM_QSTR(MP_QSTR_length), MP_ROM_PTR(&canio_remote_transmission_request_length_obj) }, + { MP_ROM_QSTR(MP_QSTR_extended), MP_ROM_PTR(&canio_remote_transmission_request_extended_obj) }, +}; +STATIC MP_DEFINE_CONST_DICT(canio_remote_transmission_request_locals_dict, canio_remote_transmission_request_locals_dict_table); + +const mp_obj_type_t canio_remote_transmission_request_type = { + { &mp_type_type }, + .name = MP_QSTR_RemoteTransmissionRequest, + .make_new = canio_remote_transmission_request_make_new, + .locals_dict = (mp_obj_t)&canio_remote_transmission_request_locals_dict, +}; diff --git a/shared-bindings/canio/RemoteTransmissionRequest.h b/shared-bindings/canio/RemoteTransmissionRequest.h new file mode 100644 index 000000000..8956587b3 --- /dev/null +++ b/shared-bindings/canio/RemoteTransmissionRequest.h @@ -0,0 +1,42 @@ +/* + * 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-module/canio/RemoteTransmissionRequest.h" + +extern const mp_obj_type_t canio_remote_transmission_request_type; + +void common_hal_canio_remote_transmission_request_construct(canio_remote_transmission_request_obj_t *self, int id, size_t size, bool extended); +const void *common_hal_canio_remote_transmission_request_get_data(const canio_remote_transmission_request_obj_t *self); +void common_hal_canio_remote_transmission_request_set_data(canio_remote_transmission_request_obj_t *self, const void *data, size_t size); +bool common_hal_canio_remote_transmission_request_get_extended(const canio_remote_transmission_request_obj_t *self); +void common_hal_canio_remote_transmission_request_set_extended(canio_remote_transmission_request_obj_t *self, bool extended); +int common_hal_canio_remote_transmission_request_get_id(const canio_remote_transmission_request_obj_t *self); +void common_hal_canio_remote_transmission_request_set_id(canio_remote_transmission_request_obj_t *self, int id); +size_t common_hal_canio_remote_transmission_request_get_length(const canio_remote_transmission_request_obj_t *self); +void common_hal_canio_remote_transmission_request_set_length(canio_remote_transmission_request_obj_t *self, size_t length); diff --git a/shared-module/canio/Message.c b/shared-module/canio/Message.c index 86a3b7106..34c2e61f7 100644 --- a/shared-module/canio/Message.c +++ b/shared-module/canio/Message.c @@ -68,26 +68,6 @@ size_t common_hal_canio_message_get_length(const canio_message_obj_t *self) return self->size; } -void common_hal_canio_remote_transmission_request_set_length(canio_message_obj_t *self, size_t size) -{ - memset(self->data, 0, size); - self->size = size; -} - - -bool common_hal_canio_message_get_rtr(const canio_message_obj_t *self) -{ - return self->rtr; -} - -void common_hal_canio_message_set_rtr(canio_message_obj_t *self, bool rtr) -{ - self->rtr = rtr; - if (rtr) { - memset(self->data, 0, self->size); - } -} - bool common_hal_canio_message_get_extended(const canio_message_obj_t *self) { return self->extended; diff --git a/shared-module/canio/RemoteTransmissionRequest.c b/shared-module/canio/RemoteTransmissionRequest.c new file mode 100644 index 000000000..00c9334b0 --- /dev/null +++ b/shared-module/canio/RemoteTransmissionRequest.c @@ -0,0 +1,68 @@ +/* + * 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 "shared-module/canio/RemoteTransmissionRequest.h" +#include "shared-bindings/canio/RemoteTransmissionRequest.h" + +#include + +void common_hal_canio_remote_transmission_request_construct(canio_remote_transmission_request_obj_t *self, int id, size_t size, bool extended) +{ + self->id = id; + self->size = size; + self->rtr = true; + self->extended = extended; +} + +int common_hal_canio_remote_transmission_request_get_id(const canio_remote_transmission_request_obj_t *self) +{ + return self->id; +} + +void common_hal_canio_remote_transmission_request_set_id(canio_remote_transmission_request_obj_t *self, int id) +{ + self->id = id; +} + +size_t common_hal_canio_remote_transmission_request_get_length(const canio_remote_transmission_request_obj_t *self) +{ + return self->size; +} + +void common_hal_canio_remote_transmission_request_set_length(canio_remote_transmission_request_obj_t *self, size_t size) +{ + self->size = size; +} + +bool common_hal_canio_remote_transmission_request_get_extended(const canio_remote_transmission_request_obj_t *self) +{ + return self->extended; +} + +void common_hal_canio_remote_transmission_request_set_extended(canio_remote_transmission_request_obj_t *self, bool extended) +{ + self->extended = extended; +} diff --git a/shared-module/canio/RemoteTransmissionRequest.h b/shared-module/canio/RemoteTransmissionRequest.h new file mode 100644 index 000000000..2f09b19c6 --- /dev/null +++ b/shared-module/canio/RemoteTransmissionRequest.h @@ -0,0 +1,33 @@ +/* + * 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/canio/Message.h" + +typedef canio_message_obj_t canio_remote_transmission_request_obj_t; -- cgit v1.2.3 From f4e36fc7f6719cb938b6e11b3e5242b149600d7d Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 28 Sep 2020 17:14:39 -0500 Subject: CAN: Use mp_obj_t insteaed of canio_message_obj_t, get rid of rtr field --- ports/atmel-samd/common-hal/canio/CAN.c | 8 +++++--- ports/atmel-samd/common-hal/canio/Listener.c | 12 +++++++----- shared-bindings/canio/CAN.h | 2 +- shared-bindings/canio/Listener.c | 14 ++++---------- shared-bindings/canio/Listener.h | 2 +- shared-module/canio/Message.c | 2 -- shared-module/canio/Message.h | 1 - shared-module/canio/RemoteTransmissionRequest.c | 1 - 8 files changed, 18 insertions(+), 24 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/common-hal/canio/CAN.c b/ports/atmel-samd/common-hal/canio/CAN.c index 4f28698fb..ec6b75951 100644 --- a/ports/atmel-samd/common-hal/canio/CAN.c +++ b/ports/atmel-samd/common-hal/canio/CAN.c @@ -328,16 +328,18 @@ static void maybe_auto_restart(canio_can_obj_t *self) { } } -void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message) +void common_hal_canio_can_send(canio_can_obj_t *self, mp_obj_t message_in) { maybe_auto_restart(self); + canio_message_obj_t *message = message_in;; // We have just one dedicated TX buffer, use it! canio_can_tx_buffer_t *ent = &self->state->tx_buffer[0]; + bool rtr = message->base.type == &canio_remote_transmission_request_type; ent->txb0.bit.ESI = false; ent->txb0.bit.XTD = message->extended; - ent->txb0.bit.RTR = message->rtr; + ent->txb0.bit.RTR = rtr; if (message->extended) { ent->txb0.bit.ID = message->id; } else { @@ -350,7 +352,7 @@ void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *messa ent->txb1.bit.BRS = 0; // No bit rate switching ent->txb1.bit.DLC = message->size; - if (!message->rtr) { + if (!rtr) { memcpy(ent->data, message->data, message->size); } diff --git a/ports/atmel-samd/common-hal/canio/Listener.c b/ports/atmel-samd/common-hal/canio/Listener.c index 483802fa4..b27c8cd1b 100644 --- a/ports/atmel-samd/common-hal/canio/Listener.c +++ b/ports/atmel-samd/common-hal/canio/Listener.c @@ -349,30 +349,32 @@ int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self) { return self->hw->RXFS.bit.F0FL; } -bool common_hal_canio_listener_receiveinto(canio_listener_obj_t *self, canio_message_obj_t *message) { +mp_obj_t common_hal_canio_listener_receive(canio_listener_obj_t *self) { if (!common_hal_canio_listener_in_waiting(self)) { uint64_t deadline = supervisor_ticks_ms64() + self->timeout_ms; do { if (supervisor_ticks_ms64() > deadline) { - return false; + return NULL; } } while (!common_hal_canio_listener_in_waiting(self)); } int index = self->hw->RXFS.bit.F0GI; canio_can_rx_fifo_t *hw_message = &self->fifo[index]; + bool rtr = hw_message->rxf0.bit.RTR; + canio_message_obj_t *message = m_new_obj(canio_message_obj_t); + message->base.type = rtr ? &canio_remote_transmission_request_type : &canio_message_type; message->extended = hw_message->rxf0.bit.XTD; if (message->extended) { message->id = hw_message->rxf0.bit.ID; } else { message->id = hw_message->rxf0.bit.ID >> 18; // short ids are left-justified } - message->rtr = hw_message->rxf0.bit.RTR; message->size = hw_message->rxf1.bit.DLC; - if (!message->rtr) { + if (!rtr) { memcpy(message->data, hw_message->data, message->size); } self->hw->RXFA.bit.F0AI = index; - return true; + return message; } void common_hal_canio_listener_deinit(canio_listener_obj_t *self) { diff --git a/shared-bindings/canio/CAN.h b/shared-bindings/canio/CAN.h index 08166dfd4..8d61bc8ed 100644 --- a/shared-bindings/canio/CAN.h +++ b/shared-bindings/canio/CAN.h @@ -51,5 +51,5 @@ void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool auto_rest void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self); void common_hal_canio_can_deinit(canio_can_obj_t *self); void common_hal_canio_can_restart(canio_can_obj_t *self); -void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message); +void common_hal_canio_can_send(canio_can_obj_t *self, mp_obj_t message); void common_hal_canio_reset(void); diff --git a/shared-bindings/canio/Listener.c b/shared-bindings/canio/Listener.c index 7b0e59063..e5a9a2f83 100644 --- a/shared-bindings/canio/Listener.c +++ b/shared-bindings/canio/Listener.c @@ -49,17 +49,11 @@ STATIC mp_obj_t canio_listener_receive(mp_obj_t self_in) { canio_listener_obj_t *self = MP_OBJ_TO_PTR(self_in); common_hal_canio_listener_check_for_deinit(self); - canio_message_obj_t *message = m_new_obj(canio_message_obj_t); - - if (common_hal_canio_listener_receiveinto(self, message)) { - if (message->rtr) { - message->base.type = &canio_remote_transmission_request_type; - } else { - message->base.type = &canio_message_type; - } + mp_obj_t message = common_hal_canio_listener_receive(self); + // note: receive fills out the type field of the message + + if (message) { return message; - } else { - m_free(message); // message did not escape into vm } return mp_const_none; } diff --git a/shared-bindings/canio/Listener.h b/shared-bindings/canio/Listener.h index d925fa265..527ffe4cb 100644 --- a/shared-bindings/canio/Listener.h +++ b/shared-bindings/canio/Listener.h @@ -37,7 +37,7 @@ typedef struct canio_listener_obj canio_listener_obj_t; void common_hal_canio_listener_construct(canio_listener_obj_t *self, canio_can_obj_t *can, size_t nmatch, canio_match_obj_t **matches, float timeout); void common_hal_canio_listener_check_for_deinit(canio_listener_obj_t *self); void common_hal_canio_listener_deinit(canio_listener_obj_t *self); -bool common_hal_canio_listener_receiveinto(canio_listener_obj_t *self, canio_message_obj_t *message); +mp_obj_t common_hal_canio_listener_receive(canio_listener_obj_t *self); int common_hal_canio_listener_in_waiting(canio_listener_obj_t *self); float common_hal_canio_listener_get_timeout(canio_listener_obj_t *self); void common_hal_canio_listener_set_timeout(canio_listener_obj_t *self, float timeout); diff --git a/shared-module/canio/Message.c b/shared-module/canio/Message.c index 34c2e61f7..a1df4f693 100644 --- a/shared-module/canio/Message.c +++ b/shared-module/canio/Message.c @@ -32,7 +32,6 @@ void common_hal_canio_message_construct(canio_message_obj_t *self, int id, void { self->id = id; self->size = size; - self->rtr = !data; self->extended = extended; if (data) { memcpy(self->data, data, size); @@ -57,7 +56,6 @@ const void *common_hal_canio_message_get_data(const canio_message_obj_t *self) const void common_hal_canio_message_set_data(canio_message_obj_t *self, const void *data, size_t size) { - self->rtr = false; self->size = size; memcpy(self->data, data, size); } diff --git a/shared-module/canio/Message.h b/shared-module/canio/Message.h index b99c5c48e..1ca0d42e2 100644 --- a/shared-module/canio/Message.h +++ b/shared-module/canio/Message.h @@ -33,6 +33,5 @@ typedef struct { int id; uint8_t data[8]; size_t size:4; - bool rtr:1; bool extended:1; } canio_message_obj_t; diff --git a/shared-module/canio/RemoteTransmissionRequest.c b/shared-module/canio/RemoteTransmissionRequest.c index 00c9334b0..9b4d5632f 100644 --- a/shared-module/canio/RemoteTransmissionRequest.c +++ b/shared-module/canio/RemoteTransmissionRequest.c @@ -33,7 +33,6 @@ void common_hal_canio_remote_transmission_request_construct(canio_remote_transmi { self->id = id; self->size = size; - self->rtr = true; self->extended = extended; } -- cgit v1.2.3 From db74f97e60e58c22e6ce73bd068d9279e3daee57 Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Mon, 28 Sep 2020 19:10:47 -0400 Subject: modified _stage/__init__.c call to set region to update --- shared-module/_stage/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/_stage/__init__.c b/shared-module/_stage/__init__.c index 0323c32cb..6dfc18880 100644 --- a/shared-module/_stage/__init__.c +++ b/shared-module/_stage/__init__.c @@ -45,7 +45,7 @@ void render_stage(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, area.y2 = y1; displayio_display_core_set_region_to_update( &display->core, display->set_column_command, display->set_row_command, - NO_COMMAND, NO_COMMAND, display->data_as_commands, false, &area); + NO_COMMAND, NO_COMMAND, display->data_as_commands, false, &area, display->SH1107_addressing); while (!displayio_display_core_begin_transaction(&display->core)) { RUN_BACKGROUND_TASKS; -- cgit v1.2.3 From 9f19a8a7600ad59851953a7c0454d09245eadf4d Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Tue, 29 Sep 2020 15:37:06 -0400 Subject: Ran pre-commit locally --- shared-bindings/displayio/Display.c | 16 ++++++++-------- shared-bindings/displayio/Display.h | 2 +- shared-module/displayio/Display.c | 8 ++++---- shared-module/displayio/EPaperDisplay.c | 4 ++-- shared-module/displayio/display_core.c | 8 ++++---- shared-module/displayio/display_core.h | 6 +++--- 6 files changed, 22 insertions(+), 22 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/Display.c b/shared-bindings/displayio/Display.c index a81736e46..e78a893b0 100644 --- a/shared-bindings/displayio/Display.c +++ b/shared-bindings/displayio/Display.c @@ -111,15 +111,15 @@ //| :param bool backlight_on_high: If True, pulling the backlight pin high turns the backlight on.""" //| ... //| -STATIC mp_obj_t displayio_display_make_new(const mp_obj_type_t *type, size_t n_args, +STATIC mp_obj_t displayio_display_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_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, - ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, - ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, - ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, - ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, - ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, - ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high, + enum { ARG_display_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_colstart, ARG_rowstart, + ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, + ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, + ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, + ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, + ARG_brightness, ARG_auto_brightness, ARG_single_byte_bounds, ARG_data_as_commands, + ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high, ARG_SH1107_addressing }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, diff --git a/shared-bindings/displayio/Display.h b/shared-bindings/displayio/Display.h index c1704eaad..f9fbc157c 100644 --- a/shared-bindings/displayio/Display.h +++ b/shared-bindings/displayio/Display.h @@ -45,7 +45,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t set_column_command, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, - bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, + bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, bool backlight_on_high, bool SH1107_addressing); bool common_hal_displayio_display_show(displayio_display_obj_t* self, diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 9864e9f9d..f2b8e0447 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -48,7 +48,7 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, uint8_t set_row_command, uint8_t write_ram_command, uint8_t set_vertical_scroll, uint8_t* init_sequence, uint16_t init_sequence_len, const mcu_pin_obj_t* backlight_pin, uint16_t brightness_command, mp_float_t brightness, bool auto_brightness, - bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, + bool single_byte_bounds, bool data_as_commands, bool auto_refresh, uint16_t native_frames_per_second, bool backlight_on_high, bool SH1107_addressing) { // Turn off auto-refresh as we init. @@ -246,7 +246,7 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* 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); - + uint16_t subrectangles = 1; // for SH1107 and other boundary constrained controllers // write one single row at a time @@ -299,8 +299,8 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* } remaining_rows -= rows_per_buffer; - displayio_display_core_set_region_to_update(&self->core, self->set_column_command, - self->set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false, + displayio_display_core_set_region_to_update(&self->core, self->set_column_command, + self->set_row_command, NO_COMMAND, NO_COMMAND, self->data_as_commands, false, &subrectangle, self->SH1107_addressing); uint16_t subrectangle_size_bytes; diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 3391a56b4..5b055e62e 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -240,8 +240,8 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c // added false parameter at end for SH1107_addressing quirk if (self->set_row_window_command != NO_COMMAND) { - displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, - self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, + displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, + self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, false, self->chip_select, &clipped, false); } diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index eb8c8f3b4..c592202fb 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -57,7 +57,7 @@ void displayio_display_core_construct(displayio_display_core_t* self, self->colstart = colstart; self->rowstart = rowstart; self->last_refresh = 0; - + // (framebufferdisplay already validated its 'bus' is a buffer-protocol object) if (bus) { if (MP_OBJ_IS_TYPE(bus, &displayio_parallelbus_type)) { @@ -208,9 +208,9 @@ void displayio_display_core_end_transaction(displayio_display_core_t* self) { self->end_transaction(self->bus); } -void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, - uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, - bool data_as_commands, bool always_toggle_chip_select, +void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, + uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, + bool data_as_commands, bool always_toggle_chip_select, displayio_area_t* area, bool SH1107_addressing) { uint16_t x1 = area->x1; uint16_t x2 = area->x2; diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index ad9998a2f..3b45f7946 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -74,9 +74,9 @@ bool displayio_display_core_bus_free(displayio_display_core_t *self); bool displayio_display_core_begin_transaction(displayio_display_core_t* self); void displayio_display_core_end_transaction(displayio_display_core_t* self); -void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, - uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, - bool data_as_commands, bool always_toggle_chip_select, +void displayio_display_core_set_region_to_update(displayio_display_core_t* self, uint8_t column_command, + uint8_t row_command, uint16_t set_current_column_command, uint16_t set_current_row_command, + bool data_as_commands, bool always_toggle_chip_select, displayio_area_t* area, bool SH1107_addressing); void release_display_core(displayio_display_core_t* self); -- cgit v1.2.3 From ef245ef54ebab7c483a935dbfb100e2ab100f0ea Mon Sep 17 00:00:00 2001 From: Mark Roberts Date: Tue, 29 Sep 2020 19:48:14 -0400 Subject: Removed redundant subrectangle sizing code --- shared-module/displayio/Display.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index f2b8e0447..37d72a82f 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -290,11 +290,7 @@ STATIC bool _refresh_area(displayio_display_obj_t* self, const displayio_area_t* .x2 = clipped.x2, .y2 = clipped.y1 + rows_per_buffer * (j + 1) }; - if (self->SH1107_addressing) { - // one row only for SH1107 in vertical (column) mode - subrectangle.y1 = clipped.y1 + j; - subrectangle.y2 = clipped.y1 + (j + 1); - } else if (remaining_rows < rows_per_buffer) { + if (remaining_rows < rows_per_buffer) { subrectangle.y2 = subrectangle.y1 + remaining_rows; } remaining_rows -= rows_per_buffer; -- cgit v1.2.3 From d1bda47d94c2ab9e42a74de4a5209df73e46a4ea Mon Sep 17 00:00:00 2001 From: FoamyGuy Date: Wed, 30 Sep 2020 14:03:03 -0500 Subject: removing top level displayio background check --- shared-module/displayio/__init__.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 101dac4b3..5161923d6 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -40,8 +40,6 @@ STATIC bool any_display_uses_this_framebuffer(mp_obj_base_t *obj) { } #endif -// Check for recursive calls to displayio_background. -bool displayio_background_in_progress = false; void displayio_background(void) { if (mp_hal_is_interrupted()) { @@ -52,11 +50,6 @@ void displayio_background(void) { return; } - if (displayio_background_in_progress) { - // Don't allow recursive calls to this routine. - return; - } - displayio_background_in_progress = true; for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { @@ -75,8 +68,6 @@ void displayio_background(void) { } } - // All done. - displayio_background_in_progress = false; } void common_hal_displayio_release_displays(void) { -- cgit v1.2.3 From a739d314f1a9f5fee6517eb425a2c691969fd7f7 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 29 Sep 2020 13:04:39 -0700 Subject: Add Metro ESP32S2 Also fix two bugs: * Crash when resetting board.SPI when it hasn't been inited. * Reading back the output value is always false. Fixes #3353 --- .../esp32s2/boards/adafruit_metro_esp32s2/board.c | 43 +++++++++++++++++++ .../boards/adafruit_metro_esp32s2/mpconfigboard.h | 48 ++++++++++++++++++++++ .../boards/adafruit_metro_esp32s2/mpconfigboard.mk | 17 ++++++++ ports/esp32s2/boards/adafruit_metro_esp32s2/pins.c | 44 ++++++++++++++++++++ .../boards/adafruit_metro_esp32s2/sdkconfig | 33 +++++++++++++++ ports/esp32s2/common-hal/digitalio/DigitalInOut.c | 18 +++++++- ports/esp32s2/common-hal/digitalio/DigitalInOut.h | 1 + shared-module/board/__init__.c | 4 +- 8 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 ports/esp32s2/boards/adafruit_metro_esp32s2/board.c create mode 100644 ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h create mode 100644 ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.mk create mode 100644 ports/esp32s2/boards/adafruit_metro_esp32s2/pins.c create mode 100644 ports/esp32s2/boards/adafruit_metro_esp32s2/sdkconfig (limited to 'shared-module') diff --git a/ports/esp32s2/boards/adafruit_metro_esp32s2/board.c b/ports/esp32s2/boards/adafruit_metro_esp32s2/board.c new file mode 100644 index 000000000..7380be6da --- /dev/null +++ b/ports/esp32s2/boards/adafruit_metro_esp32s2/board.c @@ -0,0 +1,43 @@ +/* + * 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 "boards/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" + +void board_init(void) { + // USB + common_hal_never_reset_pin(&pin_GPIO19); + common_hal_never_reset_pin(&pin_GPIO20); +} + +bool board_requests_safe_mode(void) { + return false; +} + +void reset_board(void) { + +} diff --git a/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h b/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h new file mode 100644 index 000000000..7280aab9c --- /dev/null +++ b/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h @@ -0,0 +1,48 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 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. + */ + +//Micropython setup + +#define MICROPY_HW_BOARD_NAME "Metro ESP32S2" +#define MICROPY_HW_MCU_NAME "ESP32S2" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO45) + +#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) + +#define BOARD_USER_SAFE_MODE_ACTION translate("pressing boot button at start up.\n") + +#define AUTORESET_DELAY_MS 500 + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO34) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO33) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO36) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO35) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO37) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO5) +#define DEFAULT_UART_BUS_TX (&pin_GPIO6) diff --git a/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.mk b/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.mk new file mode 100644 index 000000000..e78098d64 --- /dev/null +++ b/ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.mk @@ -0,0 +1,17 @@ +USB_VID = 0x239A +USB_PID = 0x80E0 +USB_PRODUCT = "Metro ESP32S2" +USB_MANUFACTURER = "Adafruit" + +INTERNAL_FLASH_FILESYSTEM = 1 +LONGINT_IMPL = MPZ + +# The default queue depth of 16 overflows on release builds, +# so increase it to 32. +CFLAGS += -DCFG_TUD_TASK_QUEUE_SZ=32 + +CIRCUITPY_ESP_FLASH_MODE=dio +CIRCUITPY_ESP_FLASH_FREQ=40m +CIRCUITPY_ESP_FLASH_SIZE=4MB + +CIRCUITPY_MODULE=wrover diff --git a/ports/esp32s2/boards/adafruit_metro_esp32s2/pins.c b/ports/esp32s2/boards/adafruit_metro_esp32s2/pins.c new file mode 100644 index 000000000..08d2b2a1a --- /dev/null +++ b/ports/esp32s2/boards/adafruit_metro_esp32s2/pins.c @@ -0,0 +1,44 @@ +#include "shared-bindings/board/__init__.h" + +STATIC const mp_rom_map_elem_t board_global_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO17) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO18) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO1) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO2) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO3) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO5) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO5) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO6) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO6) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO7) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO8) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO9) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO10) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO11) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO12) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO13) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO14) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO15) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO16) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO21) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO42) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_SDA),MP_ROM_PTR(&pin_GPIO33) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SCL),MP_ROM_PTR(&pin_GPIO34) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO45) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_DEBUG_RX), MP_ROM_PTR(&pin_GPIO38) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_DEBUG_TX), MP_ROM_PTR(&pin_GPIO37) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MOSI),MP_ROM_PTR(&pin_GPIO35) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_MISO),MP_ROM_PTR(&pin_GPIO37) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/esp32s2/boards/adafruit_metro_esp32s2/sdkconfig b/ports/esp32s2/boards/adafruit_metro_esp32s2/sdkconfig new file mode 100644 index 000000000..9d8bbde96 --- /dev/null +++ b/ports/esp32s2/boards/adafruit_metro_esp32s2/sdkconfig @@ -0,0 +1,33 @@ +CONFIG_ESP32S2_SPIRAM_SUPPORT=y + +# +# SPI RAM config +# +# CONFIG_SPIRAM_TYPE_AUTO is not set +CONFIG_SPIRAM_TYPE_ESPPSRAM16=y +# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set +CONFIG_SPIRAM_SIZE=2097152 + +# +# PSRAM clock and cs IO for ESP32S2 +# +CONFIG_DEFAULT_PSRAM_CLK_IO=30 +CONFIG_DEFAULT_PSRAM_CS_IO=26 +# end of PSRAM clock and cs IO for ESP32S2 + +# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set +# CONFIG_SPIRAM_RODATA is not set +# CONFIG_SPIRAM_SPEED_80M is not set +CONFIG_SPIRAM_SPEED_40M=y +# CONFIG_SPIRAM_SPEED_26M is not set +# CONFIG_SPIRAM_SPEED_20M is not set +CONFIG_SPIRAM=y +CONFIG_SPIRAM_BOOT_INIT=y +# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set +CONFIG_SPIRAM_USE_MEMMAP=y +# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set +# CONFIG_SPIRAM_USE_MALLOC is not set +CONFIG_SPIRAM_MEMTEST=y +# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set +# end of SPI RAM config diff --git a/ports/esp32s2/common-hal/digitalio/DigitalInOut.c b/ports/esp32s2/common-hal/digitalio/DigitalInOut.c index fb3ee10ad..d27985181 100644 --- a/ports/esp32s2/common-hal/digitalio/DigitalInOut.c +++ b/ports/esp32s2/common-hal/digitalio/DigitalInOut.c @@ -42,6 +42,16 @@ digitalinout_result_t common_hal_digitalio_digitalinout_construct( claim_pin(pin); self->pin = pin; + gpio_config_t config; + config.pin_bit_mask = 1ull << pin->number; + config.mode = GPIO_MODE_INPUT; + config.pull_up_en = GPIO_PULLUP_DISABLE; + config.pull_down_en = GPIO_PULLDOWN_DISABLE; + config.intr_type = GPIO_INTR_DISABLE; + if (gpio_config(&config) != ESP_OK) { + return DIGITALINOUT_PIN_BUSY; + } + return DIGITALINOUT_OK; } @@ -67,7 +77,7 @@ void common_hal_digitalio_digitalinout_switch_to_input( digitalinout_result_t common_hal_digitalio_digitalinout_switch_to_output( digitalio_digitalinout_obj_t *self, bool value, digitalio_drive_mode_t drive_mode) { - gpio_set_level(self->pin->number, value); + common_hal_digitalio_digitalinout_set_value(self, value); return common_hal_digitalio_digitalinout_set_drive_mode(self, drive_mode); } @@ -82,12 +92,16 @@ digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( void common_hal_digitalio_digitalinout_set_value( digitalio_digitalinout_obj_t *self, bool value) { + self->output_value = value; gpio_set_level(self->pin->number, value); } bool common_hal_digitalio_digitalinout_get_value( digitalio_digitalinout_obj_t *self) { - return gpio_get_level(self->pin->number) == 1; + if (common_hal_digitalio_digitalinout_get_direction(self) == DIRECTION_INPUT) { + return gpio_get_level(self->pin->number) == 1; + } + return self->output_value; } digitalinout_result_t common_hal_digitalio_digitalinout_set_drive_mode( diff --git a/ports/esp32s2/common-hal/digitalio/DigitalInOut.h b/ports/esp32s2/common-hal/digitalio/DigitalInOut.h index 6877f1741..c09c5502d 100644 --- a/ports/esp32s2/common-hal/digitalio/DigitalInOut.h +++ b/ports/esp32s2/common-hal/digitalio/DigitalInOut.h @@ -33,6 +33,7 @@ typedef struct { mp_obj_base_t base; const mcu_pin_obj_t *pin; + bool output_value; } digitalio_digitalinout_obj_t; #endif // MICROPY_INCLUDED_ESP32S2_COMMON_HAL_DIGITALIO_DIGITALINOUT_H diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index fb4f731b8..39b68a0f1 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -167,7 +167,9 @@ void reset_board_busses(void) { } #endif // make sure SPI lock is not held over a soft reset - common_hal_busio_spi_unlock(&spi_obj); + if (spi_singleton != NULL) { + common_hal_busio_spi_unlock(spi_singleton); + } if (!display_using_spi) { spi_singleton = NULL; } -- cgit v1.2.3 From 422a7d4013ddaec7df5df9104e5d9ea533b31d1a Mon Sep 17 00:00:00 2001 From: FoamyGuy Date: Wed, 30 Sep 2020 17:25:58 -0500 Subject: remove remaining top level displayio background check --- shared-module/displayio/__init__.c | 1 - 1 file changed, 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 5161923d6..a9bb3b21b 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -50,7 +50,6 @@ void displayio_background(void) { return; } - displayio_background_in_progress = true; for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { if (displays[i].display.base.type == NULL || displays[i].display.base.type == &mp_type_NoneType) { -- cgit v1.2.3 From d7c3f811afd924bae8e0b009a4cfadd6fab29584 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 1 Oct 2020 09:21:39 -0500 Subject: sharpdisplay: Fix memory corruption across soft-reset It was incorrect to NULL out the pointer to our heap allocated buffer in `reset`, because subsequent to framebuffer_reset, but while the heap was still active, we could call `get_bufinfo` again, leading to a fresh allocation on the heap that is about to be destroyed. Typical stack trace: ``` #1 0x0006c368 in sharpdisplay_framebuffer_get_bufinfo #2 0x0006ad6e in _refresh_display #3 0x0006b168 in framebufferio_framebufferdisplay_background #4 0x00069d22 in displayio_background #5 0x00045496 in supervisor_background_tasks #6 0x000446e8 in background_callback_run_all #7 0x00045546 in supervisor_run_background_tasks_if_tick #8 0x0005b042 in common_hal_neopixel_write #9 0x00044c4c in clear_temp_status #10 0x000497de in spi_flash_flush_keep_cache #11 0x00049a66 in supervisor_external_flash_flush #12 0x00044b22 in supervisor_flash_flush #13 0x0004490e in filesystem_flush #14 0x00043e18 in cleanup_after_vm #15 0x0004414c in run_repl #16 0x000441ce in main ``` When this happened -- which was inconsistent -- the display would keep some heap allocation across reset which is exactly what we need to avoid. NULLing the pointer in reconstruct follows what RGBMatrix does, and that code is a bit more battle-tested anyway. If I had a motivation for structuring the SharpMemory code differently, I can no longer recall it. Testing performed: Ran my complicated calculator program over multiple iterations without observing signs of heap corruption. Closes: #3473 --- shared-module/sharpdisplay/SharpMemoryFramebuffer.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'shared-module') diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c index 71e00d7f0..c23446828 100644 --- a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c @@ -90,10 +90,6 @@ bool common_hal_sharpdisplay_framebuffer_get_pixels_in_byte_share_row(sharpdispl } 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() @@ -105,7 +101,9 @@ void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *s } void common_hal_sharpdisplay_framebuffer_reconstruct(sharpdisplay_framebuffer_obj_t *self) { - + if (!allocation_from_ptr(self->bufinfo.buf)) { + self->bufinfo.buf = NULL; + } } void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo) { -- cgit v1.2.3 From b1592564b286ca7a5374e77eba2c2efc768ffae9 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 2 Oct 2020 15:07:36 -0500 Subject: displayio: Fix matrixportal crash An RGBMatrix has no bus and no bus_free method. It is always possible to refresh the display. This was not a problem before, but the fix I suggested (#3449) added a call to core_bus_free when a FramebufferDisplay was being refreshed. This was not caught during testing. This is a band-aid fix and it brings to light a second problem in which a SharpDisplay + FrameBuffer will not have a 'bus' object, and yet does operate using a shared SPI bus. This kind of display will need a "bus-free" like function to be added, or it can have problems like #3309. --- shared-module/displayio/display_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 68572c44f..35d0c74a4 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -197,7 +197,7 @@ bool displayio_display_core_get_dither(displayio_display_core_t* self){ } bool displayio_display_core_bus_free(displayio_display_core_t *self) { - return self->bus_free(self->bus); + return !self->bus || self->bus_free(self->bus); } bool displayio_display_core_begin_transaction(displayio_display_core_t* self) { -- cgit v1.2.3 From 5e38bb98cbcc2d1ab607b19d11e628def4f48f4c Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sat, 10 Oct 2020 14:30:37 -0500 Subject: rgbmatrix: update protomatter to 1.0.5 tag this is compile-tested on stm32f405 feather matrixportal nrf52840 feather but not actually tested-tested. --- lib/protomatter | 2 +- py/circuitpy_defns.mk | 4 ++-- shared-bindings/rgbmatrix/RGBMatrix.h | 2 +- shared-module/rgbmatrix/RGBMatrix.c | 12 ++++++------ shared-module/rgbmatrix/RGBMatrix.h | 2 +- shared-module/rgbmatrix/allocator.h | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) (limited to 'shared-module') diff --git a/lib/protomatter b/lib/protomatter index 5f07ec618..de6b7704c 160000 --- a/lib/protomatter +++ b/lib/protomatter @@ -1 +1 @@ -Subproject commit 5f07ec6188852794a94138763e612844842f13e4 +Subproject commit de6b7704c530d886ad8dfa0fa1864764d86117ee diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 76c0a4db6..525e0b2bf 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -528,10 +528,10 @@ SRC_MOD += $(addprefix lib/mp3/src/, \ $(BUILD)/lib/mp3/src/buffers.o: CFLAGS += -include "py/misc.h" -D'MPDEC_ALLOCATOR(x)=m_malloc(x,0)' -D'MPDEC_FREE(x)=m_free(x)' endif ifeq ($(CIRCUITPY_RGBMATRIX),1) -SRC_MOD += $(addprefix lib/protomatter/, \ +SRC_MOD += $(addprefix lib/protomatter/src/, \ core.c \ ) -$(BUILD)/lib/protomatter/core.o: CFLAGS += -include "shared-module/rgbmatrix/allocator.h" -DCIRCUITPY -Wno-missing-braces +$(BUILD)/lib/protomatter/src/core.o: CFLAGS += -include "shared-module/rgbmatrix/allocator.h" -DCIRCUITPY -Wno-missing-braces endif # All possible sources are listed here, and are filtered by SRC_PATTERNS. diff --git a/shared-bindings/rgbmatrix/RGBMatrix.h b/shared-bindings/rgbmatrix/RGBMatrix.h index 1dc5a406c..bfe37c340 100644 --- a/shared-bindings/rgbmatrix/RGBMatrix.h +++ b/shared-bindings/rgbmatrix/RGBMatrix.h @@ -27,7 +27,7 @@ #pragma once #include "shared-module/rgbmatrix/RGBMatrix.h" -#include "lib/protomatter/core.h" +#include "lib/protomatter/src/core.h" extern const mp_obj_type_t rgbmatrix_RGBMatrix_type; diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index 3007ca4db..a77518130 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -78,10 +78,10 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, // verify that the matrix is big enough 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->protomatter.rgbPins); - _PM_FREE(self->protomatter.addr); - _PM_FREE(self->protomatter.screenData); + _PM_free(self->bufinfo.buf); + _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); @@ -164,13 +164,13 @@ void common_hal_rgbmatrix_rgbmatrix_deinit(rgbmatrix_rgbmatrix_obj_t* self) { free_pin(&self->oe_pin); if (self->protomatter.rgbPins) { - _PM_free(&self->protomatter); + _PM_deallocate(&self->protomatter); } 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 - _PM_FREE(self->bufinfo.buf); + _PM_free(self->bufinfo.buf); self->base.type = NULL; // If a framebuffer was passed in to the constructor, NULL the reference diff --git a/shared-module/rgbmatrix/RGBMatrix.h b/shared-module/rgbmatrix/RGBMatrix.h index 19d7d5f2e..6dbc6fd41 100644 --- a/shared-module/rgbmatrix/RGBMatrix.h +++ b/shared-module/rgbmatrix/RGBMatrix.h @@ -26,7 +26,7 @@ #pragma once -#include "lib/protomatter/core.h" +#include "lib/protomatter/src/core.h" extern const mp_obj_type_t rgbmatrix_RGBMatrix_type; typedef struct { diff --git a/shared-module/rgbmatrix/allocator.h b/shared-module/rgbmatrix/allocator.h index 323fa5ec0..3431046d5 100644 --- a/shared-module/rgbmatrix/allocator.h +++ b/shared-module/rgbmatrix/allocator.h @@ -31,7 +31,7 @@ #include "py/misc.h" #include "supervisor/memory.h" -#define _PM_ALLOCATOR common_hal_rgbmatrix_allocator_impl -#define _PM_FREE(x) (common_hal_rgbmatrix_free_impl((x)), (x)=NULL, (void)0) +#define _PM_allocate 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 774f2e16ba166b5976a46519c38ea894f897dca4 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 11 Oct 2020 21:09:08 -0500 Subject: displayio, framebufferio: Remove spurious call to supervisor_start_terminal A call to supervisor_start_terminal remained in common_hal_displayio_display_construct and was copied to other display _construct functions, even though it was also being done in displayio_display_core_construct when that was factored out. Originally, this was harmless, except it created an extra allocation. When investigating #3482, I found that this bug became harmful, especially for displays that were created in Python code, because it caused a supervisor allocation to leak. I believe that it is safe to merge #3482 after this PR is merged. --- shared-module/displayio/Display.c | 2 -- shared-module/displayio/EPaperDisplay.c | 2 -- shared-module/framebufferio/FramebufferDisplay.c | 2 -- 3 files changed, 6 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index bb7e40f41..499c00ffb 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -107,8 +107,6 @@ void common_hal_displayio_display_construct(displayio_display_obj_t* self, i += 2 + data_size; } - supervisor_start_terminal(width, height); - // Always set the backlight type in case we're reusing memory. self->backlight_inout.base.type = &mp_type_NoneType; if (backlight_pin != NULL && common_hal_mcu_pin_is_free(backlight_pin)) { diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 5b055e62e..46c7ea82e 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -90,8 +90,6 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* // TODO: Clear } - supervisor_start_terminal(width, height); - // Set the group after initialization otherwise we may send pixels while we delay in // initialization. common_hal_displayio_epaperdisplay_show(self, &circuitpython_splash); diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 5163c3a7b..6b506c7fa 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -96,8 +96,6 @@ void common_hal_framebufferio_framebufferdisplay_construct(framebufferio_framebu 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 // initialization. common_hal_framebufferio_framebufferdisplay_show(self, &circuitpython_splash); -- cgit v1.2.3 From 9696dbfd388aa4c21b686d4566832964c31f8035 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Mon, 12 Oct 2020 13:26:58 -0500 Subject: rgbmatrix: Don't crash when setting brightness=0 If the display is paused, `_PM_swapbuffer_maybe` will never return. So, when brightness is 0, refresh does nothing. This makes it necessary to update the display when unpausing. Closes: #3524 --- shared-module/rgbmatrix/RGBMatrix.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index 3007ca4db..abd6d500f 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -190,6 +190,8 @@ void common_hal_rgbmatrix_rgbmatrix_set_paused(rgbmatrix_rgbmatrix_obj_t* self, _PM_stop(&self->protomatter); } else if (!paused && self->paused) { _PM_resume(&self->protomatter); + _PM_convert_565(&self->protomatter, self->bufinfo.buf, self->width); + _PM_swapbuffer_maybe(&self->protomatter); } self->paused = paused; } @@ -199,8 +201,10 @@ 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->protomatter, self->bufinfo.buf, self->width); - _PM_swapbuffer_maybe(&self->protomatter); + if (!self->paused) { + _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) { -- cgit v1.2.3 From 57b44928a38b5a2328e0fd4fe8f2baee11062229 Mon Sep 17 00:00:00 2001 From: Jensen Date: Thu, 8 Oct 2020 21:40:55 -0500 Subject: displayio: Pass transparent_color to ColorConverter Signed-off-by: Jensen --- shared-bindings/displayio/ColorConverter.c | 5 ++++- shared-bindings/displayio/ColorConverter.h | 2 +- shared-module/displayio/ColorConverter.c | 12 +++++++++++- shared-module/displayio/ColorConverter.h | 1 + 4 files changed, 17 insertions(+), 3 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index a2b6699ef..d2cbcfc73 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -43,6 +43,7 @@ //| """Create a ColorConverter object to convert color formats. Only supports RGB888 to RGB565 //| currently. //| :param bool dither: Adds random noise to dither the output image""" +//| :param bool transparent_color: Sets one color in the colorset to transparent""" //| ... //| @@ -50,9 +51,11 @@ //| STATIC mp_obj_t displayio_colorconverter_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_dither}; + enum { ARG_transparent_color }; static const mp_arg_t allowed_args[] = { { MP_QSTR_dither, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_transparent_color, MP_ARG_KW_ONLY | MP_ARG_INT, {.uint32_t = 0} }, }; 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); @@ -60,7 +63,7 @@ STATIC mp_obj_t displayio_colorconverter_make_new(const mp_obj_type_t *type, siz displayio_colorconverter_t *self = m_new_obj(displayio_colorconverter_t); self->base.type = &displayio_colorconverter_type; - common_hal_displayio_colorconverter_construct(self, args[ARG_dither].u_bool); + common_hal_displayio_colorconverter_construct(self, args[ARG_dither].u_bool, args[ARG_transparent_color].uint32_t); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/displayio/ColorConverter.h b/shared-bindings/displayio/ColorConverter.h index d550d81be..146ad80bd 100644 --- a/shared-bindings/displayio/ColorConverter.h +++ b/shared-bindings/displayio/ColorConverter.h @@ -33,7 +33,7 @@ extern const mp_obj_type_t displayio_colorconverter_type; -void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither); +void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither, uint32_t transparent_color); void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color); void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t* self, bool dither); diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index c2c3214aa..c23286d04 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -39,8 +39,9 @@ uint32_t displayio_colorconverter_dither_noise_2(uint32_t x, uint32_t y) { return displayio_colorconverter_dither_noise_1(x + y * 0xFFFF); } -void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither) { +void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither, uint32_t transparent_color) { self->dither = dither; + self->transparent_color = transparent_color; } uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888) { @@ -161,6 +162,9 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d } output_color->pixel = packed; output_color->opaque = true; + if (self->transparent_color == pixel) { + output_color->opaque = false; + } return; } else if (colorspace->tricolor) { uint8_t luma = displayio_colorconverter_compute_luma(pixel); @@ -170,6 +174,9 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d output_color->pixel = 0; } output_color->opaque = true; + if (self->transparent_color == pixel) { + output_color->opaque = false; + } return; } uint8_t pixel_hue = displayio_colorconverter_compute_hue(pixel); @@ -179,6 +186,9 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d uint8_t luma = displayio_colorconverter_compute_luma(pixel); output_color->pixel = luma >> (8 - colorspace->depth); output_color->opaque = true; + if (self->transparent_color == pixel) { + output_color->opaque = false; + } return; } output_color->opaque = false; diff --git a/shared-module/displayio/ColorConverter.h b/shared-module/displayio/ColorConverter.h index 10b1604a4..b402625ef 100644 --- a/shared-module/displayio/ColorConverter.h +++ b/shared-module/displayio/ColorConverter.h @@ -36,6 +36,7 @@ typedef struct { mp_obj_base_t base; bool dither; + uint32_t transparent_color; } displayio_colorconverter_t; bool displayio_colorconverter_needs_refresh(displayio_colorconverter_t *self); -- cgit v1.2.3 From b359e2945ac9914c31afc7e692a4f46a837a854d Mon Sep 17 00:00:00 2001 From: Jensen Date: Sun, 11 Oct 2020 13:18:09 -0500 Subject: displayio: Add make_transparent and make_opaque to ColorConvertor --- shared-bindings/displayio/ColorConverter.c | 7 ++----- shared-bindings/displayio/ColorConverter.h | 5 ++++- shared-module/displayio/ColorConverter.c | 29 ++++++++++++++++++----------- 3 files changed, 24 insertions(+), 17 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index d2cbcfc73..c02dfdb6d 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -43,7 +43,6 @@ //| """Create a ColorConverter object to convert color formats. Only supports RGB888 to RGB565 //| currently. //| :param bool dither: Adds random noise to dither the output image""" -//| :param bool transparent_color: Sets one color in the colorset to transparent""" //| ... //| @@ -51,11 +50,9 @@ //| STATIC mp_obj_t displayio_colorconverter_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_dither}; - enum { ARG_transparent_color }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_dither, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_transparent_color, MP_ARG_KW_ONLY | MP_ARG_INT, {.uint32_t = 0} }, + { MP_QSTR_dither, 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); @@ -63,7 +60,7 @@ STATIC mp_obj_t displayio_colorconverter_make_new(const mp_obj_type_t *type, siz displayio_colorconverter_t *self = m_new_obj(displayio_colorconverter_t); self->base.type = &displayio_colorconverter_type; - common_hal_displayio_colorconverter_construct(self, args[ARG_dither].u_bool, args[ARG_transparent_color].uint32_t); + common_hal_displayio_colorconverter_construct(self, args[ARG_dither].u_bool); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/displayio/ColorConverter.h b/shared-bindings/displayio/ColorConverter.h index 146ad80bd..441f7c7ae 100644 --- a/shared-bindings/displayio/ColorConverter.h +++ b/shared-bindings/displayio/ColorConverter.h @@ -33,10 +33,13 @@ extern const mp_obj_type_t displayio_colorconverter_type; -void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither, uint32_t transparent_color); +void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither); void common_hal_displayio_colorconverter_convert(displayio_colorconverter_t *colorconverter, const _displayio_colorspace_t* colorspace, uint32_t input_color, uint32_t* output_color); void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t* self, bool dither); bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* self); +void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t* self, uint32_t transparent_color); +void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color); + #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index c23286d04..0a1a7dc06 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -39,9 +39,8 @@ uint32_t displayio_colorconverter_dither_noise_2(uint32_t x, uint32_t y) { return displayio_colorconverter_dither_noise_1(x + y * 0xFFFF); } -void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither, uint32_t transparent_color) { +void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither) { self->dither = dither; - self->transparent_color = transparent_color; } uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888) { @@ -129,9 +128,26 @@ bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* return self->dither; } +void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t* self, uint32_t transparent_color) { + self->transparent_color = transparent_color; + // TODO: Does this require refreshing like the other modules? +} + +void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color) { + if (self->transparent_color == transparent_color) { + m_del(uint8_t, self, transparent_color); + } + // TODO: Does this require refreshing like the other modules? +} + void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color) { uint32_t pixel = input_pixel->pixel; + if (self->transparent_color == pixel) { + output_color->opaque = false; + return; + } + if (self->dither){ uint8_t randr = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x,input_pixel->tile_y)); uint8_t randg = (displayio_colorconverter_dither_noise_2(input_pixel->tile_x+33,input_pixel->tile_y)); @@ -162,9 +178,6 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d } output_color->pixel = packed; output_color->opaque = true; - if (self->transparent_color == pixel) { - output_color->opaque = false; - } return; } else if (colorspace->tricolor) { uint8_t luma = displayio_colorconverter_compute_luma(pixel); @@ -174,9 +187,6 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d output_color->pixel = 0; } output_color->opaque = true; - if (self->transparent_color == pixel) { - output_color->opaque = false; - } return; } uint8_t pixel_hue = displayio_colorconverter_compute_hue(pixel); @@ -186,9 +196,6 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d uint8_t luma = displayio_colorconverter_compute_luma(pixel); output_color->pixel = luma >> (8 - colorspace->depth); output_color->opaque = true; - if (self->transparent_color == pixel) { - output_color->opaque = false; - } return; } output_color->opaque = false; -- cgit v1.2.3 From 337019626a8cd0632cd2a6f6bae4ae09ae26cf16 Mon Sep 17 00:00:00 2001 From: Jensen Date: Sun, 11 Oct 2020 17:29:16 -0500 Subject: displayio: Add make_transparent to ColorConverter --- locale/circuitpython.pot | 24 +++++++++++++++++++--- shared-bindings/displayio/ColorConverter.c | 32 ++++++++++++++++++++++++++++++ shared-module/displayio/ColorConverter.c | 12 +++++++---- 3 files changed, 61 insertions(+), 7 deletions(-) (limited to 'shared-module') diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index c4951f78f..081e2df9f 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-09-29 20:14-0500\n" +"POT-Creation-Date: 2020-10-12 20:47-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -285,6 +285,7 @@ msgid "All I2C peripherals are in use" msgstr "" #: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c msgid "All RX FIFOs in use" msgstr "" @@ -892,6 +893,7 @@ msgid "File exists" msgstr "" #: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c msgid "Filters too complex" msgstr "" @@ -928,7 +930,8 @@ msgid "Group full" msgstr "" #: ports/mimxrt10xx/common-hal/busio/SPI.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/canio/CAN.c +#: ports/stm/common-hal/sdioio/SDCard.c msgid "Hardware busy, try alternative pins" msgstr "" @@ -998,7 +1001,8 @@ msgid "Invalid %q pin" msgstr "" #: ports/stm/common-hal/busio/I2C.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c ports/stm/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/busio/UART.c ports/stm/common-hal/canio/CAN.c +#: ports/stm/common-hal/sdioio/SDCard.c msgid "Invalid %q pin selection" msgstr "" @@ -3144,6 +3148,7 @@ msgstr "" msgid "pow() with 3 arguments requires integers" msgstr "" +#: ports/esp32s2/boards/adafruit_metro_esp32s2/mpconfigboard.h #: ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.h #: ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.h #: ports/esp32s2/boards/espressif_saola_1_wroom/mpconfigboard.h @@ -3151,6 +3156,7 @@ msgstr "" #: ports/esp32s2/boards/microdev_micro_s2/mpconfigboard.h #: ports/esp32s2/boards/muselab_nanoesp32_s2/mpconfigboard.h #: ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.h +#: ports/esp32s2/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h msgid "pressing boot button at start up.\n" msgstr "" @@ -3388,6 +3394,18 @@ msgstr "" msgid "too many values to unpack (expected %d)" msgstr "" +#: shared-bindings/displayio/ColorConverter.c +msgid "transparent_color should be an int" +msgstr "" + +#: shared-module/displayio/ColorConverter.c +msgid "transparent_color value is already set" +msgstr "" + +#: shared-module/displayio/ColorConverter.c +msgid "transparent_color value is not transparent" +msgstr "" + #: extmod/ulab/code/approx/approx.c msgid "trapz is defined for 1D arrays of equal length" msgstr "" diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index c02dfdb6d..a041bbe59 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -110,9 +110,41 @@ const mp_obj_property_t displayio_colorconverter_dither_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| def make_transparent(self, pixel: int) -> None: +//| """Sets a pixel to not opaque.""" +//| +STATIC mp_obj_t displayio_colorconverter_make_transparent(mp_obj_t self_in, mp_obj_t transparent_color_obj) { + displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); + + mp_int_t transparent_color; + if (!mp_obj_get_int_maybe(transparent_color_obj, &transparent_color)) { + mp_raise_ValueError(translate("transparent_color should be an int")); + } + common_hal_displayio_colorconverter_make_transparent(self, transparent_color); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_transparent_obj, displayio_colorconverter_make_transparent); + +//| def make_opaque(self, pixel: int) -> None: +//| """Sets a pixel to opaque.""" +//| +STATIC mp_obj_t displayio_colorconverter_make_opaque(mp_obj_t self_in, mp_obj_t transparent_color_obj) { + displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); + + mp_int_t transparent_color; + if (!mp_obj_get_int_maybe(transparent_color_obj, &transparent_color)) { + mp_raise_ValueError(translate("transparent_color should be an int")); + } + common_hal_displayio_colorconverter_make_opaque(self, transparent_color); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_opaque_obj, displayio_colorconverter_make_opaque); + STATIC const mp_rom_map_elem_t displayio_colorconverter_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_convert), MP_ROM_PTR(&displayio_colorconverter_convert_obj) }, { MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&displayio_colorconverter_dither_obj) }, + { MP_ROM_QSTR(MP_QSTR_make_transparent), MP_ROM_PTR(&displayio_colorconverter_make_transparent_obj) }, + { MP_ROM_QSTR(MP_QSTR_make_opaque), MP_ROM_PTR(&displayio_colorconverter_make_opaque_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_colorconverter_locals_dict, displayio_colorconverter_locals_dict_table); diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 0a1a7dc06..fef71cdf5 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -27,6 +27,7 @@ #include "shared-bindings/displayio/ColorConverter.h" #include "py/misc.h" +#include "py/runtime.h" uint32_t displayio_colorconverter_dither_noise_1 (uint32_t n) { @@ -129,15 +130,18 @@ bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* } void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t* self, uint32_t transparent_color) { + if (self->transparent_color) { + mp_raise_RuntimeError(translate("transparent_color value is already set")); + } self->transparent_color = transparent_color; - // TODO: Does this require refreshing like the other modules? } void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color) { - if (self->transparent_color == transparent_color) { - m_del(uint8_t, self, transparent_color); + if (self->transparent_color != transparent_color) { + mp_raise_RuntimeError(translate("transparent_color value is not transparent")); } - // TODO: Does this require refreshing like the other modules? + // 0x1000000 will never equal a valid color + self->transparent_color = 0x1000000; } void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color) { -- cgit v1.2.3 From 2517e4b486563724771074da88bc7fd6eda02532 Mon Sep 17 00:00:00 2001 From: Jensen Date: Wed, 14 Oct 2020 21:51:22 -0500 Subject: displayio: ColorConverter handle if opaque color is black --- shared-bindings/displayio/ColorConverter.c | 15 +++++---------- shared-bindings/displayio/ColorConverter.h | 2 +- shared-module/displayio/ColorConverter.c | 9 +++------ 3 files changed, 9 insertions(+), 17 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index a041bbe59..40550af82 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -117,7 +117,7 @@ STATIC mp_obj_t displayio_colorconverter_make_transparent(mp_obj_t self_in, mp_o displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); mp_int_t transparent_color; - if (!mp_obj_get_int_maybe(transparent_color_obj, &transparent_color)) { + if (!mp_obj_get_int(&transparent_color)) { mp_raise_ValueError(translate("transparent_color should be an int")); } common_hal_displayio_colorconverter_make_transparent(self, transparent_color); @@ -125,20 +125,15 @@ STATIC mp_obj_t displayio_colorconverter_make_transparent(mp_obj_t self_in, mp_o } MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_transparent_obj, displayio_colorconverter_make_transparent); -//| def make_opaque(self, pixel: int) -> None: +//| def make_opaque(self) -> None: //| """Sets a pixel to opaque.""" //| -STATIC mp_obj_t displayio_colorconverter_make_opaque(mp_obj_t self_in, mp_obj_t transparent_color_obj) { +STATIC mp_obj_t displayio_colorconverter_make_opaque(mp_obj_t self_in) { displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); - - mp_int_t transparent_color; - if (!mp_obj_get_int_maybe(transparent_color_obj, &transparent_color)) { - mp_raise_ValueError(translate("transparent_color should be an int")); - } - common_hal_displayio_colorconverter_make_opaque(self, transparent_color); + common_hal_displayio_colorconverter_make_opaque(self); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_opaque_obj, displayio_colorconverter_make_opaque); +MP_DEFINE_CONST_FUN_OBJ_1(displayio_colorconverter_make_opaque_obj, displayio_colorconverter_make_opaque); STATIC const mp_rom_map_elem_t displayio_colorconverter_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_convert), MP_ROM_PTR(&displayio_colorconverter_convert_obj) }, diff --git a/shared-bindings/displayio/ColorConverter.h b/shared-bindings/displayio/ColorConverter.h index 441f7c7ae..e4ddd1972 100644 --- a/shared-bindings/displayio/ColorConverter.h +++ b/shared-bindings/displayio/ColorConverter.h @@ -40,6 +40,6 @@ void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t* bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* self); void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t* self, uint32_t transparent_color); -void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color); +void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index fef71cdf5..4089b2265 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -130,16 +130,13 @@ bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* } void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t* self, uint32_t transparent_color) { - if (self->transparent_color) { - mp_raise_RuntimeError(translate("transparent_color value is already set")); + if (self->transparent_color >= 0x1000000) { + mp_raise_RuntimeError(translate("Only one color can be transparent at a time")); } self->transparent_color = transparent_color; } -void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color) { - if (self->transparent_color != transparent_color) { - mp_raise_RuntimeError(translate("transparent_color value is not transparent")); - } +void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self) { // 0x1000000 will never equal a valid color self->transparent_color = 0x1000000; } -- cgit v1.2.3 From 88d07ef35b686ffd66487de81564396aac0818b8 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 13 Oct 2020 16:57:09 -0500 Subject: displayio: further ensure just one start_terminal call @cwalther determined that for boards with 2 displays (monster m4sk), start_terminal would be called for each one, leaking supervisor heap entries. Determine, by comparing addresses, whether the display being acted on is the first display (number zero) and do (or do not) call start_terminal. stop_terminal can safely be called multiple times, so there's no need to guard against calling it more than once. Slight behavioral change: The terminal size would follow the displays[0] size, not the displays[1] size --- shared-module/displayio/Display.c | 6 ++++-- shared-module/displayio/display_core.c | 5 ++++- shared-module/framebufferio/FramebufferDisplay.c | 6 ++++-- 3 files changed, 12 insertions(+), 5 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Display.c b/shared-module/displayio/Display.c index 499c00ffb..7c8c9280b 100644 --- a/shared-module/displayio/Display.c +++ b/shared-module/displayio/Display.c @@ -347,8 +347,10 @@ void common_hal_displayio_display_set_rotation(displayio_display_obj_t* self, in self->core.height = tmp; } displayio_display_core_set_rotation(&self->core, rotation); - supervisor_stop_terminal(); - supervisor_start_terminal(self->core.width, self->core.height); + if (self == &displays[0].display) { + supervisor_stop_terminal(); + supervisor_start_terminal(self->core.width, self->core.height); + } if (self->core.current_group != NULL) { displayio_group_update_transform(self->core.current_group, &self->core.transform); } diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 60a8ef213..411f9f373 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -85,7 +85,10 @@ void displayio_display_core_construct(displayio_display_core_t* self, self->bus = bus; - supervisor_start_terminal(width, height); + // (offsetof core is equal in all display types) + if (self == &displays[0].display.core) { + supervisor_start_terminal(width, height); + } self->width = width; self->height = height; diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 6b506c7fa..03e121c91 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -280,8 +280,10 @@ void common_hal_framebufferio_framebufferdisplay_set_rotation(framebufferio_fram self->core.height = tmp; } displayio_display_core_set_rotation(&self->core, rotation); - supervisor_stop_terminal(); - supervisor_start_terminal(self->core.width, self->core.height); + if (self == &displays[0].framebuffer_display) { + supervisor_stop_terminal(); + supervisor_start_terminal(self->core.width, self->core.height); + } if (self->core.current_group != NULL) { displayio_group_update_transform(self->core.current_group, &self->core.transform); } -- cgit v1.2.3 From 74c07a4bdcc942e57668f1a2181e00d1213864a7 Mon Sep 17 00:00:00 2001 From: Jensen Date: Fri, 16 Oct 2020 19:48:41 -0500 Subject: displayio: Add in opaque pixel option for future --- locale/circuitpython.pot | 6 +----- shared-bindings/displayio/ColorConverter.c | 8 +++++--- shared-bindings/displayio/ColorConverter.h | 2 +- shared-module/displayio/ColorConverter.c | 4 +++- 4 files changed, 10 insertions(+), 10 deletions(-) (limited to 'shared-module') diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index c4b40d361..35143e04e 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-10-14 22:22-0500\n" +"POT-Creation-Date: 2020-10-16 19:50-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -3408,10 +3408,6 @@ msgstr "" msgid "too many values to unpack (expected %d)" msgstr "" -#: shared-bindings/displayio/ColorConverter.c -msgid "transparent_color should be an int" -msgstr "" - #: extmod/ulab/code/approx/approx.c msgid "trapz is defined for 1D arrays of equal length" msgstr "" diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index 4e41ceff1..e47a961a5 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -125,12 +125,14 @@ MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_transparent_obj, display //| def make_opaque(self) -> None: //| """Sets a pixel to opaque.""" //| -STATIC mp_obj_t displayio_colorconverter_make_opaque(mp_obj_t self_in) { +STATIC mp_obj_t displayio_colorconverter_make_opaque(mp_obj_t self_in, mp_obj_t transparent_color_obj) { displayio_colorconverter_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_displayio_colorconverter_make_opaque(self); + + mp_int_t transparent_color = mp_obj_get_int(&transparent_color); + common_hal_displayio_colorconverter_make_opaque(self, transparent_color); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(displayio_colorconverter_make_opaque_obj, displayio_colorconverter_make_opaque); +MP_DEFINE_CONST_FUN_OBJ_2(displayio_colorconverter_make_opaque_obj, displayio_colorconverter_make_opaque); STATIC const mp_rom_map_elem_t displayio_colorconverter_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_convert), MP_ROM_PTR(&displayio_colorconverter_convert_obj) }, diff --git a/shared-bindings/displayio/ColorConverter.h b/shared-bindings/displayio/ColorConverter.h index e4ddd1972..441f7c7ae 100644 --- a/shared-bindings/displayio/ColorConverter.h +++ b/shared-bindings/displayio/ColorConverter.h @@ -40,6 +40,6 @@ void common_hal_displayio_colorconverter_set_dither(displayio_colorconverter_t* bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* self); void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t* self, uint32_t transparent_color); -void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self); +void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_DISPLAYIO_COLORCONVERTER_H diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 4089b2265..d1a4f16a9 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -136,7 +136,9 @@ void common_hal_displayio_colorconverter_make_transparent(displayio_colorconvert self->transparent_color = transparent_color; } -void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self) { +void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color) { + (void) transparent_color; + // 0x1000000 will never equal a valid color self->transparent_color = 0x1000000; } -- cgit v1.2.3 From fc3f2a3f7f670f28d1a57eb61dfbf065463c906a Mon Sep 17 00:00:00 2001 From: Jensen Date: Fri, 16 Oct 2020 20:05:39 -0500 Subject: displayio: Remove trailing whitespace --- shared-module/displayio/ColorConverter.c | 1 - 1 file changed, 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index d1a4f16a9..dc64da03d 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -138,7 +138,6 @@ void common_hal_displayio_colorconverter_make_transparent(displayio_colorconvert void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color) { (void) transparent_color; - // 0x1000000 will never equal a valid color self->transparent_color = 0x1000000; } -- cgit v1.2.3 From b520498c733356afdc418bd5a9841c7496a3926e Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 1 Oct 2020 10:30:35 -0500 Subject: sharpdisplay: Re-use supervisor allocations if possible This is enabled by #3482 I was unable to determine why previously I had added sizeof(void*) to the GC heap allocation, so I removed that code as a mistake. --- shared-module/sharpdisplay/SharpMemoryFramebuffer.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'shared-module') diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c index c23446828..b199e98d6 100644 --- a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c @@ -34,21 +34,22 @@ #include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" #include "supervisor/memory.h" +#include "supervisor/shared/safe_mode.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; - } +static void *hybrid_alloc(size_t sz) { + supervisor_allocation *allocation = allocate_memory(align32_size(sz), false); + if (allocation) { memset(allocation->ptr, 0, sz); return allocation->ptr; } + if (gc_alloc_possible()) { + return m_malloc(sz, true); + } + reset_into_safe_mode(MEM_MANAGE); + return NULL; // unreached } static inline void hybrid_free(void *ptr_in) { @@ -155,7 +156,8 @@ void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_ 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); + // re-use a supervisor allocation if possible + self->bufinfo.buf = hybrid_alloc(self->bufinfo.len); uint8_t *data = self->bufinfo.buf; *data++ = SHARPMEM_BIT_WRITECMD_LSB; -- cgit v1.2.3 From b637d3911e71c6136f761960f293954366dd76a1 Mon Sep 17 00:00:00 2001 From: gamblor21 Date: Sat, 24 Oct 2020 20:48:35 -0500 Subject: Initial commit --- py/circuitpy_defns.mk | 5 + py/circuitpy_mpconfig.h | 8 ++ py/circuitpy_mpconfig.mk | 3 + shared-bindings/busdevice/I2CDevice.c | 246 ++++++++++++++++++++++++++++++++++ shared-bindings/busdevice/I2CDevice.h | 58 ++++++++ shared-bindings/busdevice/__init__.c | 79 +++++++++++ shared-bindings/busdevice/__init__.h | 32 +++++ shared-module/busdevice/I2CDevice.c | 101 ++++++++++++++ shared-module/busdevice/I2CDevice.h | 40 ++++++ shared-module/busdevice/__init__.c | 0 10 files changed, 572 insertions(+) create mode 100644 shared-bindings/busdevice/I2CDevice.c create mode 100644 shared-bindings/busdevice/I2CDevice.h create mode 100644 shared-bindings/busdevice/__init__.c create mode 100644 shared-bindings/busdevice/__init__.h create mode 100644 shared-module/busdevice/I2CDevice.c create mode 100644 shared-module/busdevice/I2CDevice.h create mode 100644 shared-module/busdevice/__init__.c (limited to 'shared-module') diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index ccdf973e9..9318bd466 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -133,6 +133,9 @@ endif ifeq ($(CIRCUITPY_BOARD),1) SRC_PATTERNS += board/% endif +ifeq ($(CIRCUITPY_BUSDEVICE),1) +SRC_PATTERNS += busdevice/% +endif ifeq ($(CIRCUITPY_BUSIO),1) SRC_PATTERNS += busio/% bitbangio/OneWire.% endif @@ -432,6 +435,8 @@ SRC_SHARED_MODULE_ALL = \ bitbangio/SPI.c \ bitbangio/__init__.c \ board/__init__.c \ + busdevice/__init__.c \ + busdevice/I2CDevice.c \ busio/OneWire.c \ displayio/Bitmap.c \ displayio/ColorConverter.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 1e01bd9c5..240fac189 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -324,6 +324,13 @@ extern const struct _mp_obj_module_t board_module; #define BOARD_UART_ROOT_POINTER #endif +#if CIRCUITPY_BUSDEVICE +extern const struct _mp_obj_module_t busdevice_module; +#define BUSDEVICE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_busdevice), (mp_obj_t)&busdevice_module }, +#else +#define BUSDEVICE_MODULE +#endif + #if CIRCUITPY_BUSIO extern const struct _mp_obj_module_t busio_module; #define BUSIO_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_busio), (mp_obj_t)&busio_module }, @@ -773,6 +780,7 @@ extern const struct _mp_obj_module_t wifi_module; BITBANGIO_MODULE \ BLEIO_MODULE \ BOARD_MODULE \ + BUSDEVICE_MODULE \ BUSIO_MODULE \ CAMERA_MODULE \ CANIO_MODULE \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index a6aabec33..1f96a8f2d 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -90,6 +90,9 @@ CFLAGS += -DCIRCUITPY_BLEIO=$(CIRCUITPY_BLEIO) CIRCUITPY_BOARD ?= 1 CFLAGS += -DCIRCUITPY_BOARD=$(CIRCUITPY_BOARD) +CIRCUITPY_BUSDEVICE ?= 1 +CFLAGS += -DCIRCUITPY_BUSDEVICE=$(CIRCUITPY_BUSDEVICE) + CIRCUITPY_BUSIO ?= 1 CFLAGS += -DCIRCUITPY_BUSIO=$(CIRCUITPY_BUSIO) diff --git a/shared-bindings/busdevice/I2CDevice.c b/shared-bindings/busdevice/I2CDevice.c new file mode 100644 index 000000000..02dac6a95 --- /dev/null +++ b/shared-bindings/busdevice/I2CDevice.c @@ -0,0 +1,246 @@ +/* + * 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 +// busio.I2C class. + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/busdevice/I2CDevice.h" +#include "shared-bindings/util.h" +#include "shared-module/busdevice/I2CDevice.h" + +#include "lib/utils/buffer_helper.h" +#include "lib/utils/context_manager_helpers.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + +//| class I2CDevice: +//| """Two wire serial protocol""" +//| +//| def __init__(self, i2c, device_address, probe=True) -> None: +//| +//| ... +//| +STATIC mp_obj_t busdevice_i2cdevice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + busdevice_i2cdevice_obj_t *self = m_new_obj(busdevice_i2cdevice_obj_t); + self->base.type = &busdevice_i2cdevice_type; + enum { ARG_i2c, ARG_device_address, ARG_probe }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_i2c, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_device_address, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_probe, MP_ARG_BOOL, {.u_bool = true} }, + }; + 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_i2c_obj_t* i2c = args[ARG_i2c].u_obj; + + common_hal_busdevice_i2cdevice_construct(self, i2c, args[ARG_device_address].u_int, args[ARG_probe].u_bool); + return (mp_obj_t)self; +} + +//| def __enter__(self) -> None: +//| """Automatically initializes the hardware on context exit. See FIX +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t busdevice_i2cdevice_obj___enter__(mp_obj_t self_in) { + common_hal_busdevice_i2cdevice_lock(self_in); + return self_in; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(busdevice_i2cdevice___enter___obj, busdevice_i2cdevice_obj___enter__); + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware on context exit. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +STATIC mp_obj_t busdevice_i2cdevice_obj___exit__(size_t n_args, const mp_obj_t *args) { + common_hal_busdevice_i2cdevice_unlock(args[0]); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busdevice_i2cdevice___exit___obj, 4, 4, busdevice_i2cdevice_obj___exit__); + +STATIC void readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_WRITE); + + size_t length = bufinfo.len; + normalize_buffer_bounds(&start, end, &length); + if (length == 0) { + mp_raise_ValueError(translate("Buffer must be at least length 1")); + } + + uint8_t status = common_hal_busdevice_i2cdevice_readinto(self, ((uint8_t*)bufinfo.buf) + start, length); + if (status != 0) { + mp_raise_OSError(status); + } +} + +STATIC mp_obj_t busdevice_i2cdevice_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + + busdevice_i2cdevice_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); + + readinto(self, args[ARG_buffer].u_obj, args[ARG_start].u_int, args[ARG_end].u_int); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_readinto_obj, 2, busdevice_i2cdevice_readinto); + + +STATIC void write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); + + size_t length = bufinfo.len; + normalize_buffer_bounds(&start, end, &length); + if (length == 0) { + mp_raise_ValueError(translate("Buffer must be at least length 1")); + } + + uint8_t status = common_hal_busdevice_i2cdevice_write(self, ((uint8_t*)bufinfo.buf) + start, length); + if (status != 0) { + mp_raise_OSError(status); + } +} + +STATIC mp_obj_t busdevice_i2cdevice_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + busdevice_i2cdevice_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); + + write(self, args[ARG_buffer].u_obj, args[ARG_start].u_int, args[ARG_end].u_int); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_write_obj, 2, busdevice_i2cdevice_write); + + +/*STATIC void write_then_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t out_buffer, mp_obj_t in_buffer, + int32_t out_start, mp_int_t out_end, int32_t in_start, mp_int_t in_end) { + mp_buffer_info_t out_bufinfo; + mp_get_buffer_raise(out_buffer, &out_bufinfo, MP_BUFFER_READ); + + size_t out_length = out_bufinfo.len; + normalize_buffer_bounds(&out_start, out_end, &out_length); + if (out_length == 0) { + mp_raise_ValueError(translate("Buffer must be at least length 1")); + } + + mp_buffer_info_t in_bufinfo; + mp_get_buffer_raise(in_buffer, &in_bufinfo, MP_BUFFER_WRITE); + + size_t in_length = in_bufinfo.len; + normalize_buffer_bounds(&in_start, in_end, &in_length); + if (in_length == 0) { + mp_raise_ValueError(translate("Buffer must be at least length 1")); + } + + uint8_t status = common_hal_busdevice_i2cdevice_write_then_readinto(self, out_buffer, in_buffer, out_length, in_length); + if (status != 0) { + mp_raise_OSError(status); + } +}*/ + +STATIC mp_obj_t busdevice_i2cdevice_write_then_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + busdevice_i2cdevice_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); + + write(self, args[ARG_out_buffer].u_obj, args[ARG_out_start].u_int, args[ARG_out_end].u_int); + + readinto(self, args[ARG_in_buffer].u_obj, args[ARG_in_start].u_int, args[ARG_in_end].u_int); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_write_then_readinto_obj, 3, busdevice_i2cdevice_write_then_readinto); + + +STATIC mp_obj_t busdevice_i2cdevice___probe_for_device(mp_obj_t self_in) { + //busdevice_i2cdevice_obj_t *self = self_in; + + //common_hal_busdevice_i2cdevice_lock(self_in); + +/* + uint8_t buffer; + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(&buffer, &bufinfo, MP_BUFFER_WRITE); + + uint8_t status = common_hal_busdevice_i2cdevice_readinto(self_in, (uint8_t*)bufinfo.buf, 1); + if (status != 0) { + common_hal_busdevice_i2cdevice_unlock(self_in); + mp_raise_ValueError_varg(translate("No I2C device at address: %x"), self->device_address); + } +*/ + //common_hal_busdevice_i2cdevice_unlock(self_in); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(busdevice_i2cdevice___probe_for_device_obj, busdevice_i2cdevice___probe_for_device); + + +STATIC const mp_rom_map_elem_t busdevice_i2cdevice_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&busdevice_i2cdevice___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busdevice_i2cdevice___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&busdevice_i2cdevice_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&busdevice_i2cdevice_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_then_readinto), MP_ROM_PTR(&busdevice_i2cdevice_write_then_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR___probe_for_device), MP_ROM_PTR(&busdevice_i2cdevice___probe_for_device_obj) }, +}; + + +STATIC MP_DEFINE_CONST_DICT(busdevice_i2cdevice_locals_dict, busdevice_i2cdevice_locals_dict_table); + +const mp_obj_type_t busdevice_i2cdevice_type = { + { &mp_type_type }, + .name = MP_QSTR_I2CDevice, + .make_new = busdevice_i2cdevice_make_new, + .locals_dict = (mp_obj_dict_t*)&busdevice_i2cdevice_locals_dict, +}; \ No newline at end of file diff --git a/shared-bindings/busdevice/I2CDevice.h b/shared-bindings/busdevice/I2CDevice.h new file mode 100644 index 000000000..bc85023d7 --- /dev/null +++ b/shared-bindings/busdevice/I2CDevice.h @@ -0,0 +1,58 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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. + */ + +// Machine is the HAL for low-level, hardware accelerated functions. It is not +// meant to simplify APIs, its only meant to unify them so that other modules +// do not require port specific logic. +// +// This file includes externs for all functions a port should implement to +// support the machine module. + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H + +#include "py/obj.h" + +#include "common-hal/microcontroller/Pin.h" +#include "shared-module/busdevice/I2CDevice.h" +#include "shared-bindings/busio/I2C.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t busdevice_i2cdevice_type; + +// Initializes the hardware peripheral. +extern void common_hal_busdevice_i2cdevice_construct(busdevice_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address, bool probe); +extern void common_hal_busdevice_i2cdevice___enter__(busdevice_i2cdevice_obj_t *self); +extern void common_hal_busdevice_i2cdevice___exit__(busdevice_i2cdevice_obj_t *self); +extern uint8_t common_hal_busdevice_i2cdevice_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); +extern uint8_t common_hal_busdevice_i2cdevice_write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); +extern uint8_t common_hal_busdevice_i2cdevice_write_then_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t out_buffer, + mp_obj_t in_buffer, size_t out_length, size_t in_length); +extern uint8_t common_hal_busdevice_i2cdevice___probe_for_device(busdevice_i2cdevice_obj_t *self); +extern void common_hal_busdevice_i2cdevice_lock(busdevice_i2cdevice_obj_t *self); +extern void common_hal_busdevice_i2cdevice_unlock(busdevice_i2cdevice_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H diff --git a/shared-bindings/busdevice/__init__.c b/shared-bindings/busdevice/__init__.c new file mode 100644 index 000000000..6b24160a0 --- /dev/null +++ b/shared-bindings/busdevice/__init__.c @@ -0,0 +1,79 @@ +/* + * 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 "py/mphal.h" +#include "py/objproperty.h" + +#include "shared-bindings/busdevice/__init__.h" +#include "shared-bindings/busdevice/I2CDevice.h" + + +//| """Hardware accelerated external bus access +//| +//| The `busio` module contains classes to support a variety of serial +//| protocols. +//| +//| When the microcontroller does not support the behavior in a hardware +//| accelerated fashion it may internally use a bitbang routine. However, if +//| hardware support is available on a subset of pins but not those provided, +//| then a RuntimeError will be raised. Use the `bitbangio` module to explicitly +//| bitbang a serial protocol on any general purpose pins. +//| +//| 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 busio +//| from board import * +//| +//| i2c = busio.I2C(SCL, SDA) +//| print(i2c.scan()) +//| i2c.deinit() +//| +//| This example will initialize the the device, run +//| :py:meth:`~busio.I2C.scan` and then :py:meth:`~busio.I2C.deinit` the +//| hardware. The last step is optional because CircuitPython automatically +//| resets hardware after a program finishes.""" +//| + +STATIC const mp_rom_map_elem_t busdevice_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_busdevice) }, + { MP_ROM_QSTR(MP_QSTR_I2CDevice), MP_ROM_PTR(&busdevice_i2cdevice_type) }, +}; + +STATIC MP_DEFINE_CONST_DICT(busdevice_module_globals, busdevice_module_globals_table); + +const mp_obj_module_t busdevice_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&busdevice_module_globals, +}; diff --git a/shared-bindings/busdevice/__init__.h b/shared-bindings/busdevice/__init__.h new file mode 100644 index 000000000..4a669807b --- /dev/null +++ b/shared-bindings/busdevice/__init__.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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_BUSDEVICE___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE___INIT___H + +// Nothing now. + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE___INIT___H diff --git a/shared-module/busdevice/I2CDevice.c b/shared-module/busdevice/I2CDevice.c new file mode 100644 index 000000000..30f4aad33 --- /dev/null +++ b/shared-module/busdevice/I2CDevice.c @@ -0,0 +1,101 @@ +/* + * 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. + */ + +#include "shared-bindings/busdevice/I2CDevice.h" +#include "shared-bindings/busio/I2C.h" +#include "py/mperrno.h" +#include "py/nlr.h" + +void common_hal_busdevice_i2cdevice_construct(busdevice_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address, bool probe) { + self->i2c = i2c; + self->device_address = device_address; + self->probe = probe; + + if (self->probe == true) { + common_hal_busdevice_i2cdevice___probe_for_device(self); + } +} + +void common_hal_busdevice_i2cdevice_lock(busdevice_i2cdevice_obj_t *self) { + bool success = false; + while (!success) { + success = common_hal_busio_i2c_try_lock(self->i2c); + } +} + +void common_hal_busdevice_i2cdevice_unlock(busdevice_i2cdevice_obj_t *self) { + common_hal_busio_i2c_unlock(self->i2c); +} + +uint8_t common_hal_busdevice_i2cdevice_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length) { + uint8_t status = common_hal_busio_i2c_read(self->i2c, self->device_address, buffer, length); + + return status; +} + +uint8_t common_hal_busdevice_i2cdevice_write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length) { + uint8_t status = common_hal_busio_i2c_write(self->i2c, self->device_address, buffer, length, true); + + return status; +} + +uint8_t common_hal_busdevice_i2cdevice_write_then_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t out_buffer, mp_obj_t in_buffer, + size_t out_length, size_t in_length) { + uint8_t status = 0; + + status = common_hal_busio_i2c_write(self->i2c, self->device_address, out_buffer, out_length, true); + + status = common_hal_busio_i2c_read(self->i2c, self->device_address, in_buffer, in_length); + + return status; +} + +uint8_t common_hal_busdevice_i2cdevice___probe_for_device(busdevice_i2cdevice_obj_t *self) { + + + + + // write "" + + +/* + while not self.i2c.try_lock(): + pass + try: + self.i2c.writeto(self.device_address, b"") + except OSError: + # some OS's dont like writing an empty bytesting... + # Retry by reading a byte + try: + result = bytearray(1) + self.i2c.readfrom_into(self.device_address, result) + except OSError: + raise ValueError("No I2C device at address: %x" % self.device_address) + finally: + self.i2c.unlock() +*/ + return 0; +} diff --git a/shared-module/busdevice/I2CDevice.h b/shared-module/busdevice/I2CDevice.h new file mode 100644 index 000000000..c872704db --- /dev/null +++ b/shared-module/busdevice/I2CDevice.h @@ -0,0 +1,40 @@ +/* + * 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_SHARED_MODULE_BUSDEVICE_I2CDEVICE_H +#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_I2CDEVICE_H + +#include "py/obj.h" +#include "common-hal/busio/I2C.h" + +typedef struct { + mp_obj_base_t base; + busio_i2c_obj_t *i2c; + uint8_t device_address; + bool probe; +} busdevice_i2cdevice_obj_t; + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_I2CDEVICE_H diff --git a/shared-module/busdevice/__init__.c b/shared-module/busdevice/__init__.c new file mode 100644 index 000000000..e69de29bb -- cgit v1.2.3 From 12d770b427e77c207b85aa9ddcda0047fa6d040a Mon Sep 17 00:00:00 2001 From: gamblor21 Date: Sun, 25 Oct 2020 10:15:45 -0500 Subject: Added __probe_for_device --- shared-bindings/busdevice/I2CDevice.c | 24 +++++++++++++------- shared-bindings/busdevice/I2CDevice.h | 4 +--- shared-module/busdevice/I2CDevice.c | 41 ++++++++++++----------------------- 3 files changed, 31 insertions(+), 38 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/busdevice/I2CDevice.c b/shared-bindings/busdevice/I2CDevice.c index 02dac6a95..fa5cb02e0 100644 --- a/shared-bindings/busdevice/I2CDevice.c +++ b/shared-bindings/busdevice/I2CDevice.c @@ -37,6 +37,7 @@ #include "py/runtime.h" #include "supervisor/shared/translate.h" + //| class I2CDevice: //| """Two wire serial protocol""" //| @@ -59,6 +60,10 @@ STATIC mp_obj_t busdevice_i2cdevice_make_new(const mp_obj_type_t *type, size_t n busio_i2c_obj_t* i2c = args[ARG_i2c].u_obj; common_hal_busdevice_i2cdevice_construct(self, i2c, args[ARG_device_address].u_int, args[ARG_probe].u_bool); + if (args[ARG_probe].u_bool == true) { + common_hal_busdevice_i2cdevice___probe_for_device(self); + } + return (mp_obj_t)self; } @@ -204,28 +209,31 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_write_then_readinto_obj, 3, busde STATIC mp_obj_t busdevice_i2cdevice___probe_for_device(mp_obj_t self_in) { - //busdevice_i2cdevice_obj_t *self = self_in; + busdevice_i2cdevice_obj_t *self = self_in; + common_hal_busdevice_i2cdevice___probe_for_device(self); - //common_hal_busdevice_i2cdevice_lock(self_in); +/* common_hal_busdevice_i2cdevice_lock(self); -/* - uint8_t buffer; + + //uint8_t buffer; mp_buffer_info_t bufinfo; - mp_get_buffer_raise(&buffer, &bufinfo, MP_BUFFER_WRITE); + //mp_obj_t bufobj = MP_OBJ_FROM_PTR(&buffer) + mp_obj_t buffer = mp_obj_new_bytearray_of_zeros(1); + + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_WRITE); uint8_t status = common_hal_busdevice_i2cdevice_readinto(self_in, (uint8_t*)bufinfo.buf, 1); if (status != 0) { common_hal_busdevice_i2cdevice_unlock(self_in); mp_raise_ValueError_varg(translate("No I2C device at address: %x"), self->device_address); } + + common_hal_busdevice_i2cdevice_unlock(self); */ - //common_hal_busdevice_i2cdevice_unlock(self_in); - return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(busdevice_i2cdevice___probe_for_device_obj, busdevice_i2cdevice___probe_for_device); - STATIC const mp_rom_map_elem_t busdevice_i2cdevice_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&busdevice_i2cdevice___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busdevice_i2cdevice___exit___obj) }, diff --git a/shared-bindings/busdevice/I2CDevice.h b/shared-bindings/busdevice/I2CDevice.h index bc85023d7..795905b32 100644 --- a/shared-bindings/busdevice/I2CDevice.h +++ b/shared-bindings/busdevice/I2CDevice.h @@ -45,14 +45,12 @@ extern const mp_obj_type_t busdevice_i2cdevice_type; // Initializes the hardware peripheral. extern void common_hal_busdevice_i2cdevice_construct(busdevice_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address, bool probe); -extern void common_hal_busdevice_i2cdevice___enter__(busdevice_i2cdevice_obj_t *self); -extern void common_hal_busdevice_i2cdevice___exit__(busdevice_i2cdevice_obj_t *self); extern uint8_t common_hal_busdevice_i2cdevice_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); extern uint8_t common_hal_busdevice_i2cdevice_write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); extern uint8_t common_hal_busdevice_i2cdevice_write_then_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t out_buffer, mp_obj_t in_buffer, size_t out_length, size_t in_length); -extern uint8_t common_hal_busdevice_i2cdevice___probe_for_device(busdevice_i2cdevice_obj_t *self); extern void common_hal_busdevice_i2cdevice_lock(busdevice_i2cdevice_obj_t *self); extern void common_hal_busdevice_i2cdevice_unlock(busdevice_i2cdevice_obj_t *self); +extern void common_hal_busdevice_i2cdevice___probe_for_device(busdevice_i2cdevice_obj_t *self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H diff --git a/shared-module/busdevice/I2CDevice.c b/shared-module/busdevice/I2CDevice.c index 30f4aad33..516132c84 100644 --- a/shared-module/busdevice/I2CDevice.c +++ b/shared-module/busdevice/I2CDevice.c @@ -28,15 +28,12 @@ #include "shared-bindings/busio/I2C.h" #include "py/mperrno.h" #include "py/nlr.h" +#include "py/runtime.h" void common_hal_busdevice_i2cdevice_construct(busdevice_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address, bool probe) { self->i2c = i2c; self->device_address = device_address; self->probe = probe; - - if (self->probe == true) { - common_hal_busdevice_i2cdevice___probe_for_device(self); - } } void common_hal_busdevice_i2cdevice_lock(busdevice_i2cdevice_obj_t *self) { @@ -73,29 +70,19 @@ uint8_t common_hal_busdevice_i2cdevice_write_then_readinto(busdevice_i2cdevice_o return status; } -uint8_t common_hal_busdevice_i2cdevice___probe_for_device(busdevice_i2cdevice_obj_t *self) { - - +void common_hal_busdevice_i2cdevice___probe_for_device(busdevice_i2cdevice_obj_t *self) { + common_hal_busdevice_i2cdevice_lock(self); + mp_buffer_info_t bufinfo; + mp_obj_t buffer = mp_obj_new_bytearray_of_zeros(1); - // write "" + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_WRITE); - -/* - while not self.i2c.try_lock(): - pass - try: - self.i2c.writeto(self.device_address, b"") - except OSError: - # some OS's dont like writing an empty bytesting... - # Retry by reading a byte - try: - result = bytearray(1) - self.i2c.readfrom_into(self.device_address, result) - except OSError: - raise ValueError("No I2C device at address: %x" % self.device_address) - finally: - self.i2c.unlock() -*/ - return 0; -} + uint8_t status = common_hal_busdevice_i2cdevice_readinto(self, (uint8_t*)bufinfo.buf, 1); + if (status != 0) { + common_hal_busdevice_i2cdevice_unlock(self); + mp_raise_ValueError_varg(translate("No I2C device at address: %x"), self->device_address); + } + + common_hal_busdevice_i2cdevice_unlock(self); +} \ No newline at end of file -- cgit v1.2.3 From 1117edae63df7b66f1575980bf54d6836f9a8aa8 Mon Sep 17 00:00:00 2001 From: Christian Walther Date: Sat, 24 Oct 2020 17:13:10 +0200 Subject: Fix erroneous claim of board.I2C() by deinited display. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the end of a session that called displayio.release_displays() (and did not initialize a new display), a board.I2C() bus that was previously used by a display would wrongly be considered still in use. While I can’t think of any unrecoverable problem this would cause in the next session, it violates the assumption that a soft reboot resets everything not needed by displays, potentially leading to confusion. By itself, this change does not fix the problem yet - rather, it introduces the same issue as in #3581 for SPI. This needs to be solved in the same way for I2C and SPI. --- 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 39b68a0f1..856103b7b 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -139,7 +139,7 @@ void reset_board_busses(void) { bool display_using_i2c = false; #if CIRCUITPY_DISPLAYIO for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { - if (displays[i].i2cdisplay_bus.bus == i2c_singleton) { + if (displays[i].bus_base.type == &displayio_i2cdisplay_type && displays[i].i2cdisplay_bus.bus == i2c_singleton) { display_using_i2c = true; break; } -- cgit v1.2.3 From f4f80e07ca3dc2f5a93484e5342540837a94a505 Mon Sep 17 00:00:00 2001 From: Christian Walther Date: Sat, 24 Oct 2020 17:23:17 +0200 Subject: Fix lost board.SPI and board.I2C after being used by display. Fixes #3581. Pins were marked as never_reset by common_hal_displayio_fourwire_construct() and common_hal_sharpdisplay_framebuffer_construct(), but these marks were never removed, so at the end of a session after displayio.release_displays(), {spi|i2c}_singleton would be set to NULL but the pins would not be reset. In the next session, board.SPI() and board.I2C() were unable to reconstruct the object because the pins were still in use. For symmetry with creation of the singleton, add deinitialization before setting it to NULL in reset_board_busses(). This makes the pins resettable, so that reset_port(), moved behind it, then resets them. --- main.c | 4 +++- shared-module/board/__init__.c | 14 +++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'shared-module') diff --git a/main.c b/main.c index b43b3b8c8..80b163f60 100755 --- a/main.c +++ b/main.c @@ -234,10 +234,12 @@ void cleanup_after_vm(supervisor_allocation* heap) { common_hal_canio_reset(); #endif - reset_port(); + // reset_board_busses() first because it may release pins from the never_reset state, so that + // reset_port() can reset them. #if CIRCUITPY_BOARD reset_board_busses(); #endif + reset_port(); reset_board(); reset_status_led(); } diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 856103b7b..967b430d2 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -145,8 +145,11 @@ void reset_board_busses(void) { } } #endif - if (!display_using_i2c) { - i2c_singleton = NULL; + if (i2c_singleton != NULL) { + if (!display_using_i2c) { + common_hal_busio_i2c_deinit(i2c_singleton); + i2c_singleton = NULL; + } } #endif #if BOARD_SPI @@ -169,9 +172,10 @@ void reset_board_busses(void) { // make sure SPI lock is not held over a soft reset if (spi_singleton != NULL) { common_hal_busio_spi_unlock(spi_singleton); - } - if (!display_using_spi) { - spi_singleton = NULL; + if (!display_using_spi) { + common_hal_busio_spi_deinit(spi_singleton); + spi_singleton = NULL; + } } #endif #if BOARD_UART -- cgit v1.2.3 From 99a3750a2cfd1da8cdd266ca9a0367f0c3a54092 Mon Sep 17 00:00:00 2001 From: Christian Walther Date: Sat, 24 Oct 2020 17:50:11 +0200 Subject: Fix lost board.SPI and board.I2C after explicitly deiniting them. After calling board.SPI().deinit(), calling board.SPI() again would return the unusable deinited object and there was no way of getting it back into an initialized state until the end of the session. --- shared-bindings/board/__init__.c | 10 ++++++++-- shared-module/board/__init__.c | 10 ++++------ 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/board/__init__.c b/shared-bindings/board/__init__.c index 6837fc41c..717698408 100644 --- a/shared-bindings/board/__init__.c +++ b/shared-bindings/board/__init__.c @@ -28,6 +28,12 @@ #include "py/runtime.h" #include "shared-bindings/board/__init__.h" +#if BOARD_I2C +#include "shared-bindings/busio/I2C.h" +#endif +#if BOARD_SPI +#include "shared-bindings/busio/SPI.h" +#endif //| """Board specific pin names //| @@ -45,7 +51,7 @@ #if BOARD_I2C mp_obj_t board_i2c(void) { mp_obj_t singleton = common_hal_board_get_i2c(); - if (singleton != NULL) { + if (singleton != NULL && !common_hal_busio_i2c_deinited(singleton)) { return singleton; } assert_pin_free(DEFAULT_I2C_BUS_SDA); @@ -69,7 +75,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(board_i2c_obj, board_i2c); #if BOARD_SPI mp_obj_t board_spi(void) { mp_obj_t singleton = common_hal_board_get_spi(); - if (singleton != NULL) { + if (singleton != NULL && !common_hal_busio_spi_deinited(singleton)) { return singleton; } assert_pin_free(DEFAULT_SPI_BUS_SCK); diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 967b430d2..2f1c34e56 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -55,9 +55,8 @@ mp_obj_t common_hal_board_get_i2c(void) { } mp_obj_t common_hal_board_create_i2c(void) { - if (i2c_singleton != NULL) { - return i2c_singleton; - } + // All callers have either already verified this or come so early that it can't be otherwise. + assert(i2c_singleton == NULL || common_hal_busio_i2c_deinited(i2c_singleton)); busio_i2c_obj_t *self = &i2c_obj; self->base.type = &busio_i2c_type; @@ -79,9 +78,8 @@ mp_obj_t common_hal_board_get_spi(void) { } mp_obj_t common_hal_board_create_spi(void) { - if (spi_singleton != NULL) { - return spi_singleton; - } + // All callers have either already verified this or come so early that it can't be otherwise. + assert(spi_singleton == NULL || common_hal_busio_spi_deinited(spi_singleton)); busio_spi_obj_t *self = &spi_obj; self->base.type = &busio_spi_type; -- cgit v1.2.3 From 8a379830a8a583750daedb2b1c72369f6bb413ef Mon Sep 17 00:00:00 2001 From: gamblor21 Date: Mon, 26 Oct 2020 16:54:24 -0500 Subject: Added doc and translations --- locale/circuitpython.pot | 12 ++- shared-bindings/busdevice/I2CDevice.c | 141 +++++++++++++++++++--------------- shared-module/busdevice/I2CDevice.c | 2 +- 3 files changed, 89 insertions(+), 66 deletions(-) (limited to 'shared-module') diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 7ed2d1ba1..f96b67d2a 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-10-16 19:50-0500\n" +"POT-Creation-Date: 2020-10-26 16:48-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -477,7 +477,8 @@ msgstr "" msgid "Buffer must be a multiple of 512 bytes" msgstr "" -#: shared-bindings/bitbangio/I2C.c shared-bindings/busio/I2C.c +#: shared-bindings/bitbangio/I2C.c shared-bindings/busdevice/I2CDevice.c +#: shared-bindings/busio/I2C.c msgid "Buffer must be at least length 1" msgstr "" @@ -1251,6 +1252,11 @@ msgstr "" msgid "No DMA channel found" msgstr "" +#: shared-module/busdevice/I2CDevice.c +#, c-format +msgid "No I2C device at address: %x" +msgstr "" + #: ports/esp32s2/common-hal/busio/SPI.c ports/mimxrt10xx/common-hal/busio/SPI.c #: ports/stm/common-hal/busio/SPI.c msgid "No MISO Pin" @@ -3181,6 +3187,8 @@ msgstr "" #: ports/esp32s2/boards/espressif_saola_1_wrover/mpconfigboard.h #: ports/esp32s2/boards/microdev_micro_s2/mpconfigboard.h #: ports/esp32s2/boards/muselab_nanoesp32_s2/mpconfigboard.h +#: ports/esp32s2/boards/targett_module_clip_wroom/mpconfigboard.h +#: ports/esp32s2/boards/targett_module_clip_wrover/mpconfigboard.h #: ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.h #: ports/esp32s2/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h msgid "pressing boot button at start up.\n" diff --git a/shared-bindings/busdevice/I2CDevice.c b/shared-bindings/busdevice/I2CDevice.c index fa5cb02e0..d8db9362f 100644 --- a/shared-bindings/busdevice/I2CDevice.c +++ b/shared-bindings/busdevice/I2CDevice.c @@ -39,12 +39,29 @@ //| class I2CDevice: -//| """Two wire serial protocol""" -//| -//| def __init__(self, i2c, device_address, probe=True) -> None: -//| -//| ... -//| +//| """ +//| Represents a single I2C device and manages locking the bus and the device +//| address. +//| :param ~busio.I2C i2c: The I2C bus the device is on +//| :param int device_address: The 7 bit device address +//| :param bool probe: Probe for the device upon object creation, default is true +//| .. note:: This class is **NOT** built into CircuitPython. See +//| :ref:`here for install instructions `. +//| Example: +//| .. code-block:: python +//| import busio +//| from board import * +//| from adafruit_bus_device.i2c_device import I2CDevice +//| with busio.I2C(SCL, SDA) as i2c: +//| device = I2CDevice(i2c, 0x70) +//| bytes_read = bytearray(4) +//| with device: +//| device.readinto(bytes_read) +//| # A second transaction +//| with device: +//| device.write(bytes_read)""" +//| ... +//| STATIC mp_obj_t busdevice_i2cdevice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { busdevice_i2cdevice_obj_t *self = m_new_obj(busdevice_i2cdevice_obj_t); self->base.type = &busdevice_i2cdevice_type; @@ -67,28 +84,30 @@ STATIC mp_obj_t busdevice_i2cdevice_make_new(const mp_obj_type_t *type, size_t n return (mp_obj_t)self; } -//| def __enter__(self) -> None: -//| """Automatically initializes the hardware on context exit. See FIX -//| :ref:`lifetime-and-contextmanagers` for more info.""" -//| ... -//| STATIC mp_obj_t busdevice_i2cdevice_obj___enter__(mp_obj_t self_in) { common_hal_busdevice_i2cdevice_lock(self_in); return self_in; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(busdevice_i2cdevice___enter___obj, busdevice_i2cdevice_obj___enter__); -//| def __exit__(self) -> None: -//| """Automatically deinitializes the hardware on context exit. See -//| :ref:`lifetime-and-contextmanagers` for more info.""" -//| ... -//| STATIC mp_obj_t busdevice_i2cdevice_obj___exit__(size_t n_args, const mp_obj_t *args) { common_hal_busdevice_i2cdevice_unlock(args[0]); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busdevice_i2cdevice___exit___obj, 4, 4, busdevice_i2cdevice_obj___exit__); +//| def readinto(self, buf, *, start=0, end=None): +//| """ +//| Read into ``buf`` from the device. The number of bytes read will be the +//| length of ``buf``. +//| If ``start`` or ``end`` is provided, then the buffer will be sliced +//| as if ``buf[start:end]``. This will not cause an allocation like +//| ``buf[start:end]`` will so it saves memory. +//| :param bytearray buffer: buffer to write into +//| :param int start: Index to start writing at +//| :param int end: Index to write up to but not include; if None, use ``len(buf)``""" +//| ... +//| STATIC void readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_WRITE); @@ -123,7 +142,19 @@ STATIC mp_obj_t busdevice_i2cdevice_readinto(size_t n_args, const mp_obj_t *pos_ } STATIC MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_readinto_obj, 2, busdevice_i2cdevice_readinto); - +//| def write(self, buf, *, start=0, end=None): +//| """ +//| Write the bytes from ``buffer`` to the device, then transmit a stop +//| bit. +//| If ``start`` or ``end`` is provided, then the buffer will be sliced +//| as if ``buffer[start:end]``. This will not cause an allocation like +//| ``buffer[start:end]`` will so it saves memory. +//| :param bytearray buffer: buffer containing the bytes to write +//| :param int start: Index to start writing from +//| :param int end: Index to read up to but not include; if None, use ``len(buf)`` +//| """ +//| ... +//| STATIC void write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); @@ -158,32 +189,28 @@ STATIC mp_obj_t busdevice_i2cdevice_write(size_t n_args, const mp_obj_t *pos_arg MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_write_obj, 2, busdevice_i2cdevice_write); -/*STATIC void write_then_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t out_buffer, mp_obj_t in_buffer, - int32_t out_start, mp_int_t out_end, int32_t in_start, mp_int_t in_end) { - mp_buffer_info_t out_bufinfo; - mp_get_buffer_raise(out_buffer, &out_bufinfo, MP_BUFFER_READ); - - size_t out_length = out_bufinfo.len; - normalize_buffer_bounds(&out_start, out_end, &out_length); - if (out_length == 0) { - mp_raise_ValueError(translate("Buffer must be at least length 1")); - } - - mp_buffer_info_t in_bufinfo; - mp_get_buffer_raise(in_buffer, &in_bufinfo, MP_BUFFER_WRITE); - - size_t in_length = in_bufinfo.len; - normalize_buffer_bounds(&in_start, in_end, &in_length); - if (in_length == 0) { - mp_raise_ValueError(translate("Buffer must be at least length 1")); - } - - uint8_t status = common_hal_busdevice_i2cdevice_write_then_readinto(self, out_buffer, in_buffer, out_length, in_length); - if (status != 0) { - mp_raise_OSError(status); - } -}*/ - +//| def write_then_readinto(self, out_buffer, in_buffer, *, out_start=0, out_end=None, in_start=0, in_end=None): +//| """ +//| Write the bytes from ``out_buffer`` to the device, then immediately +//| reads into ``in_buffer`` from the device. The number of bytes read +//| will be the length of ``in_buffer``. +//| If ``out_start`` or ``out_end`` is provided, then the output buffer +//| will be sliced as if ``out_buffer[out_start:out_end]``. This will +//| not cause an allocation like ``buffer[out_start:out_end]`` will so +//| it saves memory. +//| If ``in_start`` or ``in_end`` is provided, then the input buffer +//| will be sliced as if ``in_buffer[in_start:in_end]``. This will not +//| cause an allocation like ``in_buffer[in_start:in_end]`` will so +//| it saves memory. +//| :param bytearray out_buffer: buffer containing the bytes to write +//| :param bytearray in_buffer: buffer containing the bytes to read into +//| :param int out_start: Index to start writing from +//| :param int out_end: Index to read up to but not include; if None, use ``len(out_buffer)`` +//| :param int in_start: Index to start writing at +//| :param int in_end: Index to write up to but not include; if None, use ``len(in_buffer)`` +//| """ +//| ... +//| STATIC mp_obj_t busdevice_i2cdevice_write_then_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; static const mp_arg_t allowed_args[] = { @@ -207,29 +234,17 @@ STATIC mp_obj_t busdevice_i2cdevice_write_then_readinto(size_t n_args, const mp_ } MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_write_then_readinto_obj, 3, busdevice_i2cdevice_write_then_readinto); - +//| def __probe_for_device(self): +//| """ +//| Try to read a byte from an address, +//| if you get an OSError it means the device is not there +//| or that the device does not support these means of probing +//| """ +//| ... +//| STATIC mp_obj_t busdevice_i2cdevice___probe_for_device(mp_obj_t self_in) { busdevice_i2cdevice_obj_t *self = self_in; common_hal_busdevice_i2cdevice___probe_for_device(self); - -/* common_hal_busdevice_i2cdevice_lock(self); - - - //uint8_t buffer; - mp_buffer_info_t bufinfo; - //mp_obj_t bufobj = MP_OBJ_FROM_PTR(&buffer) - mp_obj_t buffer = mp_obj_new_bytearray_of_zeros(1); - - mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_WRITE); - - uint8_t status = common_hal_busdevice_i2cdevice_readinto(self_in, (uint8_t*)bufinfo.buf, 1); - if (status != 0) { - common_hal_busdevice_i2cdevice_unlock(self_in); - mp_raise_ValueError_varg(translate("No I2C device at address: %x"), self->device_address); - } - - common_hal_busdevice_i2cdevice_unlock(self); -*/ return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_1(busdevice_i2cdevice___probe_for_device_obj, busdevice_i2cdevice___probe_for_device); diff --git a/shared-module/busdevice/I2CDevice.c b/shared-module/busdevice/I2CDevice.c index 516132c84..085c4171f 100644 --- a/shared-module/busdevice/I2CDevice.c +++ b/shared-module/busdevice/I2CDevice.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2017 Scott Shawcroft for Adafruit Industries + * Copyright (c) 2020 Mark Komus * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal -- cgit v1.2.3 From 0d1649880f1c23ec6c9c0a4834f3712a8495f9d8 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 26 Oct 2020 16:58:00 -0700 Subject: Add grayscale EInk support --- shared-bindings/displayio/EPaperDisplay.c | 35 +++++++++++++++++++++++++------ shared-bindings/displayio/EPaperDisplay.h | 2 +- shared-module/displayio/ColorConverter.c | 9 ++++---- shared-module/displayio/EPaperDisplay.c | 15 ++++++++----- shared-module/displayio/EPaperDisplay.h | 1 + shared-module/displayio/Palette.h | 1 + shared-module/displayio/display_core.c | 1 + 7 files changed, 48 insertions(+), 16 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index 8be4ee4c4..e0326d9c8 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -49,7 +49,19 @@ //| Most people should not use this class directly. Use a specific display driver instead that will //| contain the startup and shutdown sequences at minimum.""" //| -//| def __init__(self, display_bus: _DisplayBus, start_sequence: ReadableBuffer, stop_sequence: ReadableBuffer, *, width: int, height: int, ram_width: int, ram_height: int, colstart: int = 0, rowstart: int = 0, rotation: int = 0, set_column_window_command: Optional[int] = None, set_row_window_command: Optional[int] = None, single_byte_bounds: bool = False, write_black_ram_command: int, black_bits_inverted: bool = False, write_color_ram_command: Optional[int] = None, color_bits_inverted: bool = False, highlight_color: int = 0x000000, refresh_display_command: int, refresh_time: float = 40, busy_pin: Optional[microcontroller.Pin] = None, busy_state: bool = True, seconds_per_frame: float = 180, always_toggle_chip_select: bool = False) -> None: +//| def __init__(self, display_bus: _DisplayBus, +//| start_sequence: ReadableBuffer, stop_sequence: ReadableBuffer, *, +//| width: int, height: int, ram_width: int, ram_height: int, +//| colstart: int = 0, rowstart: int = 0, rotation: int = 0, +//| set_column_window_command: Optional[int] = None, +//| set_row_window_command: Optional[int] = None, single_byte_bounds: bool = False, +//| write_black_ram_command: int, black_bits_inverted: bool = False, +//| write_color_ram_command: Optional[int] = None, +//| color_bits_inverted: bool = False, highlight_color: int = 0x000000, +//| refresh_display_command: int, refresh_time: float = 40, +//| busy_pin: Optional[microcontroller.Pin] = None, busy_state: bool = True, +//| seconds_per_frame: float = 180, always_toggle_chip_select: bool = False, +//| grayscale: bool = False) -> None: //| """Create a EPaperDisplay object on the given display bus (`displayio.FourWire` or `displayio.ParallelBus`). //| //| The ``start_sequence`` and ``stop_sequence`` are bitpacked to minimize the ram impact. Every @@ -84,11 +96,18 @@ //| :param microcontroller.Pin busy_pin: Pin used to signify the display is busy //| :param bool busy_state: State of the busy pin when the display is busy //| :param float seconds_per_frame: Minimum number of seconds between screen refreshes -//| :param bool always_toggle_chip_select: When True, chip select is toggled every byte""" +//| :param bool always_toggle_chip_select: When True, chip select is toggled every byte +//| :param bool grayscale: When true, the color ram is the low bit of 2-bit grayscale""" //| ... //| STATIC mp_obj_t displayio_epaperdisplay_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_display_bus, ARG_start_sequence, ARG_stop_sequence, ARG_width, ARG_height, ARG_ram_width, ARG_ram_height, ARG_colstart, ARG_rowstart, ARG_rotation, ARG_set_column_window_command, ARG_set_row_window_command, ARG_set_current_column_command, ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted, ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color, ARG_refresh_display_command, ARG_refresh_time, ARG_busy_pin, ARG_busy_state, ARG_seconds_per_frame, ARG_always_toggle_chip_select }; + enum { ARG_display_bus, ARG_start_sequence, ARG_stop_sequence, ARG_width, ARG_height, + ARG_ram_width, ARG_ram_height, ARG_colstart, ARG_rowstart, ARG_rotation, + ARG_set_column_window_command, ARG_set_row_window_command, ARG_set_current_column_command, + ARG_set_current_row_command, ARG_write_black_ram_command, ARG_black_bits_inverted, + ARG_write_color_ram_command, ARG_color_bits_inverted, ARG_highlight_color, + ARG_refresh_display_command, ARG_refresh_time, ARG_busy_pin, ARG_busy_state, + ARG_seconds_per_frame, ARG_always_toggle_chip_select, ARG_grayscale }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_start_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -115,6 +134,7 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size { MP_QSTR_busy_state, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, { MP_QSTR_seconds_per_frame, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(180)} }, { MP_QSTR_always_toggle_chip_select, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_grayscale, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.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); @@ -151,11 +171,14 @@ STATIC mp_obj_t displayio_epaperdisplay_make_new(const mp_obj_type_t *type, size self, display_bus, start_bufinfo.buf, start_bufinfo.len, stop_bufinfo.buf, stop_bufinfo.len, - args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_ram_width].u_int, args[ARG_ram_height].u_int, args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, + args[ARG_width].u_int, args[ARG_height].u_int, args[ARG_ram_width].u_int, args[ARG_ram_height].u_int, + args[ARG_colstart].u_int, args[ARG_rowstart].u_int, rotation, args[ARG_set_column_window_command].u_int, args[ARG_set_row_window_command].u_int, args[ARG_set_current_column_command].u_int, args[ARG_set_current_row_command].u_int, - args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command, args[ARG_color_bits_inverted].u_bool, highlight_color, args[ARG_refresh_display_command].u_int, refresh_time, - busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame, args[ARG_always_toggle_chip_select].u_bool + args[ARG_write_black_ram_command].u_int, args[ARG_black_bits_inverted].u_bool, write_color_ram_command, + args[ARG_color_bits_inverted].u_bool, highlight_color, args[ARG_refresh_display_command].u_int, refresh_time, + busy_pin, args[ARG_busy_state].u_bool, seconds_per_frame, + args[ARG_always_toggle_chip_select].u_bool, args[ARG_grayscale].u_bool ); return self; diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index e4b81c883..352de899a 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -44,7 +44,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* uint16_t set_column_window_command, uint16_t set_row_window_command, uint16_t set_current_column_command, uint16_t set_current_row_command, uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, mp_float_t refresh_time, - const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select); + const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool always_toggle_chip_select, bool grayscale); bool common_hal_displayio_epaperdisplay_refresh(displayio_epaperdisplay_obj_t* self); diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index dc64da03d..03ec99ceb 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -165,9 +165,9 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d g8 = MIN(255,g8 + (randg&0x03)); } else { int bitmask = 0xFF >> colorspace->depth; - b8 = MIN(255,b8 + (randb&bitmask)); - r8 = MIN(255,r8 + (randr&bitmask)); - g8 = MIN(255,g8 + (randg&bitmask)); + b8 = MIN(255,b8 + (randb & bitmask)); + r8 = MIN(255,r8 + (randr & bitmask)); + g8 = MIN(255,g8 + (randg & bitmask)); } pixel = r8 << 16 | g8 << 8 | b8; } @@ -196,7 +196,8 @@ void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _d return; } else if (colorspace->grayscale && colorspace->depth <= 8) { uint8_t luma = displayio_colorconverter_compute_luma(pixel); - output_color->pixel = luma >> (8 - colorspace->depth); + size_t bitmask = (1 << colorspace->depth) - 1; + output_color->pixel = (luma >> colorspace->grayscale_bit) & bitmask; output_color->opaque = true; return; } diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 46c7ea82e..514b99a13 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -49,7 +49,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* uint16_t set_column_window_command, uint16_t set_row_window_command, uint16_t set_current_column_command, uint16_t set_current_row_command, uint16_t write_black_ram_command, bool black_bits_inverted, uint16_t write_color_ram_command, bool color_bits_inverted, uint32_t highlight_color, uint16_t refresh_display_command, mp_float_t refresh_time, - const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool chip_select) { + const mcu_pin_obj_t* busy_pin, bool busy_state, mp_float_t seconds_per_frame, bool chip_select, bool grayscale) { if (highlight_color != 0x000000) { self->core.colorspace.tricolor = true; self->core.colorspace.tricolor_hue = displayio_colorconverter_compute_hue(highlight_color); @@ -72,6 +72,7 @@ void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self->refreshing = false; self->milliseconds_per_frame = seconds_per_frame * 1000; self->chip_select = chip_select ? CHIP_SELECT_TOGGLE_EVERY_BYTE : CHIP_SELECT_UNTOUCHED; + self->grayscale = grayscale; self->start_sequence = start_sequence; self->start_sequence_len = start_sequence_len; @@ -230,17 +231,16 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c uint32_t mask[mask_length]; uint8_t passes = 1; - if (self->core.colorspace.tricolor) { + if (self->core.colorspace.tricolor || self->grayscale) { passes = 2; } for (uint8_t pass = 0; pass < passes; pass++) { uint16_t remaining_rows = displayio_area_height(&clipped); - // added false parameter at end for SH1107_addressing quirk if (self->set_row_window_command != NO_COMMAND) { displayio_display_core_set_region_to_update(&self->core, self->set_column_window_command, self->set_row_window_command, self->set_current_column_command, self->set_current_row_command, - false, self->chip_select, &clipped, false); + false, self->chip_select, &clipped, false /* SH1107_addressing */); } uint8_t write_command = self->write_black_ram_command; @@ -270,8 +270,13 @@ bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, c memset(buffer, 0, buffer_size * sizeof(buffer[0])); self->core.colorspace.grayscale = true; + self->core.colorspace.grayscale_bit = 7; if (pass == 1) { - self->core.colorspace.grayscale = false; + if (self->grayscale) { // 4-color grayscale + self->core.colorspace.grayscale_bit = 6; + } else { // Tri-color + self->core.colorspace.grayscale = false; + } } displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index 3b9f6e368..4103fe5fc 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -55,6 +55,7 @@ typedef struct { bool black_bits_inverted; bool color_bits_inverted; bool refreshing; + bool grayscale; display_chip_select_behavior_t chip_select; } displayio_epaperdisplay_obj_t; diff --git a/shared-module/displayio/Palette.h b/shared-module/displayio/Palette.h index da72f250f..993912cc5 100644 --- a/shared-module/displayio/Palette.h +++ b/shared-module/displayio/Palette.h @@ -37,6 +37,7 @@ typedef struct { uint8_t bytes_per_cell; uint8_t tricolor_hue; uint8_t tricolor_luma; + uint8_t grayscale_bit; // The lowest grayscale bit. Normally 8 - depth. bool grayscale; bool tricolor; bool pixels_in_byte_share_row; diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 411f9f373..57d33b565 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -48,6 +48,7 @@ void displayio_display_core_construct(displayio_display_core_t* self, uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, uint8_t bytes_per_cell, bool reverse_pixels_in_byte, bool reverse_bytes_in_word) { self->colorspace.depth = color_depth; self->colorspace.grayscale = grayscale; + self->colorspace.grayscale_bit = 8 - color_depth; self->colorspace.pixels_in_byte_share_row = pixels_in_byte_share_row; self->colorspace.bytes_per_cell = bytes_per_cell; self->colorspace.reverse_pixels_in_byte = reverse_pixels_in_byte; -- cgit v1.2.3 From 2374b0d013e60b543164f208315ed9f52895dac2 Mon Sep 17 00:00:00 2001 From: gamblor21 Date: Tue, 27 Oct 2020 09:13:14 -0500 Subject: Fixed whitespace issues --- shared-bindings/busdevice/I2CDevice.c | 16 ++++++++-------- shared-bindings/busdevice/__init__.c | 2 +- shared-module/busdevice/I2CDevice.c | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/busdevice/I2CDevice.c b/shared-bindings/busdevice/I2CDevice.c index d21ac8c6e..1f3da4652 100644 --- a/shared-bindings/busdevice/I2CDevice.c +++ b/shared-bindings/busdevice/I2CDevice.c @@ -61,7 +61,7 @@ //| with device: //| device.write(bytes_read)""" //| ... -//| +//| STATIC mp_obj_t busdevice_i2cdevice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { busdevice_i2cdevice_obj_t *self = m_new_obj(busdevice_i2cdevice_obj_t); self->base.type = &busdevice_i2cdevice_type; @@ -107,7 +107,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busdevice_i2cdevice___exit___obj, 4, //| :param int start: Index to start writing at //| :param int end: Index to write up to but not include; if None, use ``len(buf)``""" //| ... -//| +//| STATIC void readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_WRITE); @@ -131,7 +131,7 @@ STATIC mp_obj_t busdevice_i2cdevice_readinto(size_t n_args, const mp_obj_t *pos_ { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, }; - + busdevice_i2cdevice_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -179,7 +179,7 @@ STATIC mp_obj_t busdevice_i2cdevice_write(size_t n_args, const mp_obj_t *pos_arg { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, }; busdevice_i2cdevice_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); @@ -210,7 +210,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_write_obj, 2, busdevice_i2cdevice //| :param int in_end: Index to write up to but not include; if None, use ``len(in_buffer)`` //| """ //| ... -//| +//| STATIC mp_obj_t busdevice_i2cdevice_write_then_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; static const mp_arg_t allowed_args[] = { @@ -227,7 +227,7 @@ STATIC mp_obj_t busdevice_i2cdevice_write_then_readinto(size_t n_args, const mp_ mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); write(self, args[ARG_out_buffer].u_obj, args[ARG_out_start].u_int, args[ARG_out_end].u_int); - + readinto(self, args[ARG_in_buffer].u_obj, args[ARG_in_start].u_int, args[ARG_in_end].u_int); return mp_const_none; @@ -241,7 +241,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_write_then_readinto_obj, 3, busde //| or that the device does not support these means of probing //| """ //| ... -//| +//| STATIC mp_obj_t busdevice_i2cdevice___probe_for_device(mp_obj_t self_in) { busdevice_i2cdevice_obj_t *self = self_in; common_hal_busdevice_i2cdevice___probe_for_device(self); @@ -266,4 +266,4 @@ const mp_obj_type_t busdevice_i2cdevice_type = { .name = MP_QSTR_I2CDevice, .make_new = busdevice_i2cdevice_make_new, .locals_dict = (mp_obj_dict_t*)&busdevice_i2cdevice_locals_dict, -}; \ No newline at end of file +}; diff --git a/shared-bindings/busdevice/__init__.c b/shared-bindings/busdevice/__init__.c index 91f250c6a..112dabb7e 100644 --- a/shared-bindings/busdevice/__init__.c +++ b/shared-bindings/busdevice/__init__.c @@ -37,7 +37,7 @@ //| """Hardware accelerated external bus access //| -//| The I2CDevice and SPIDevice helper classes make managing transaction state on a bus easy. +//| The I2CDevice and SPIDevice helper classes make managing transaction state on a bus easy. //| For example, they manage locking the bus to prevent other concurrent access. For SPI //| devices, it manages the chip select and protocol changes such as mode. For I2C, it //| manages the device address. diff --git a/shared-module/busdevice/I2CDevice.c b/shared-module/busdevice/I2CDevice.c index 085c4171f..91013d52c 100644 --- a/shared-module/busdevice/I2CDevice.c +++ b/shared-module/busdevice/I2CDevice.c @@ -83,6 +83,6 @@ void common_hal_busdevice_i2cdevice___probe_for_device(busdevice_i2cdevice_obj_t common_hal_busdevice_i2cdevice_unlock(self); mp_raise_ValueError_varg(translate("No I2C device at address: %x"), self->device_address); } - + common_hal_busdevice_i2cdevice_unlock(self); -} \ No newline at end of file +} -- cgit v1.2.3 From e7da852db7c3784c8c162f7914815ba439baa989 Mon Sep 17 00:00:00 2001 From: gamblor21 Date: Thu, 29 Oct 2020 16:13:03 -0500 Subject: Fixing review comments --- shared-bindings/busdevice/I2CDevice.c | 40 +++++++++++------------------------ shared-bindings/busdevice/I2CDevice.h | 6 ++---- shared-module/busdevice/I2CDevice.c | 26 ++++++----------------- shared-module/busdevice/I2CDevice.h | 1 - 4 files changed, 20 insertions(+), 53 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/busdevice/I2CDevice.c b/shared-bindings/busdevice/I2CDevice.c index 1f3da4652..f5e968137 100644 --- a/shared-bindings/busdevice/I2CDevice.c +++ b/shared-bindings/busdevice/I2CDevice.c @@ -76,22 +76,23 @@ STATIC mp_obj_t busdevice_i2cdevice_make_new(const mp_obj_type_t *type, size_t n busio_i2c_obj_t* i2c = args[ARG_i2c].u_obj; - common_hal_busdevice_i2cdevice_construct(self, i2c, args[ARG_device_address].u_int, args[ARG_probe].u_bool); + common_hal_busdevice_i2cdevice_construct(MP_OBJ_TO_PTR(self), i2c, args[ARG_device_address].u_int); if (args[ARG_probe].u_bool == true) { - common_hal_busdevice_i2cdevice___probe_for_device(self); + common_hal_busdevice_i2cdevice_probe_for_device(self); } return (mp_obj_t)self; } STATIC mp_obj_t busdevice_i2cdevice_obj___enter__(mp_obj_t self_in) { - common_hal_busdevice_i2cdevice_lock(self_in); - return self_in; + busdevice_i2cdevice_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_busdevice_i2cdevice_lock(self); + return self; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(busdevice_i2cdevice___enter___obj, busdevice_i2cdevice_obj___enter__); STATIC mp_obj_t busdevice_i2cdevice_obj___exit__(size_t n_args, const mp_obj_t *args) { - common_hal_busdevice_i2cdevice_unlock(args[0]); + common_hal_busdevice_i2cdevice_unlock(MP_OBJ_TO_PTR(args[0])); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busdevice_i2cdevice___exit___obj, 4, 4, busdevice_i2cdevice_obj___exit__); @@ -118,7 +119,7 @@ STATIC void readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t s mp_raise_ValueError(translate("Buffer must be at least length 1")); } - uint8_t status = common_hal_busdevice_i2cdevice_readinto(self, ((uint8_t*)bufinfo.buf) + start, length); + uint8_t status = common_hal_busdevice_i2cdevice_readinto(MP_OBJ_TO_PTR(self), ((uint8_t*)bufinfo.buf) + start, length); if (status != 0) { mp_raise_OSError(status); } @@ -127,7 +128,7 @@ STATIC void readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t s STATIC mp_obj_t busdevice_i2cdevice_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_buffer, ARG_start, ARG_end }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, }; @@ -165,7 +166,7 @@ STATIC void write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t star mp_raise_ValueError(translate("Buffer must be at least length 1")); } - uint8_t status = common_hal_busdevice_i2cdevice_write(self, ((uint8_t*)bufinfo.buf) + start, length); + uint8_t status = common_hal_busdevice_i2cdevice_write(MP_OBJ_TO_PTR(self), ((uint8_t*)bufinfo.buf) + start, length); if (status != 0) { mp_raise_OSError(status); } @@ -174,7 +175,7 @@ STATIC void write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t star STATIC mp_obj_t busdevice_i2cdevice_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_buffer, ARG_start, ARG_end }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, }; @@ -214,8 +215,8 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_write_obj, 2, busdevice_i2cdevice STATIC mp_obj_t busdevice_i2cdevice_write_then_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, @@ -234,31 +235,14 @@ STATIC mp_obj_t busdevice_i2cdevice_write_then_readinto(size_t n_args, const mp_ } MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_write_then_readinto_obj, 3, busdevice_i2cdevice_write_then_readinto); -//| def __probe_for_device(self): -//| """ -//| Try to read a byte from an address, -//| if you get an OSError it means the device is not there -//| or that the device does not support these means of probing -//| """ -//| ... -//| -STATIC mp_obj_t busdevice_i2cdevice___probe_for_device(mp_obj_t self_in) { - busdevice_i2cdevice_obj_t *self = self_in; - common_hal_busdevice_i2cdevice___probe_for_device(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(busdevice_i2cdevice___probe_for_device_obj, busdevice_i2cdevice___probe_for_device); - STATIC const mp_rom_map_elem_t busdevice_i2cdevice_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&busdevice_i2cdevice___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busdevice_i2cdevice___exit___obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&busdevice_i2cdevice_readinto_obj) }, { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&busdevice_i2cdevice_write_obj) }, { MP_ROM_QSTR(MP_QSTR_write_then_readinto), MP_ROM_PTR(&busdevice_i2cdevice_write_then_readinto_obj) }, - { MP_ROM_QSTR(MP_QSTR___probe_for_device), MP_ROM_PTR(&busdevice_i2cdevice___probe_for_device_obj) }, }; - STATIC MP_DEFINE_CONST_DICT(busdevice_i2cdevice_locals_dict, busdevice_i2cdevice_locals_dict_table); const mp_obj_type_t busdevice_i2cdevice_type = { diff --git a/shared-bindings/busdevice/I2CDevice.h b/shared-bindings/busdevice/I2CDevice.h index 146013cb7..a1f869c45 100644 --- a/shared-bindings/busdevice/I2CDevice.h +++ b/shared-bindings/busdevice/I2CDevice.h @@ -43,13 +43,11 @@ extern const mp_obj_type_t busdevice_i2cdevice_type; // Initializes the hardware peripheral. -extern void common_hal_busdevice_i2cdevice_construct(busdevice_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address, bool probe); +extern void common_hal_busdevice_i2cdevice_construct(busdevice_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address); extern uint8_t common_hal_busdevice_i2cdevice_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); extern uint8_t common_hal_busdevice_i2cdevice_write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); -extern uint8_t common_hal_busdevice_i2cdevice_write_then_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t out_buffer, - mp_obj_t in_buffer, size_t out_length, size_t in_length); extern void common_hal_busdevice_i2cdevice_lock(busdevice_i2cdevice_obj_t *self); extern void common_hal_busdevice_i2cdevice_unlock(busdevice_i2cdevice_obj_t *self); -extern void common_hal_busdevice_i2cdevice___probe_for_device(busdevice_i2cdevice_obj_t *self); +extern void common_hal_busdevice_i2cdevice_probe_for_device(busdevice_i2cdevice_obj_t *self); #endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H diff --git a/shared-module/busdevice/I2CDevice.c b/shared-module/busdevice/I2CDevice.c index 91013d52c..41706c1a8 100644 --- a/shared-module/busdevice/I2CDevice.c +++ b/shared-module/busdevice/I2CDevice.c @@ -30,16 +30,17 @@ #include "py/nlr.h" #include "py/runtime.h" -void common_hal_busdevice_i2cdevice_construct(busdevice_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address, bool probe) { +void common_hal_busdevice_i2cdevice_construct(busdevice_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address) { self->i2c = i2c; self->device_address = device_address; - self->probe = probe; } void common_hal_busdevice_i2cdevice_lock(busdevice_i2cdevice_obj_t *self) { bool success = false; while (!success) { success = common_hal_busio_i2c_try_lock(self->i2c); + RUN_BACKGROUND_TASKS; + mp_handle_pending(); } } @@ -48,29 +49,14 @@ void common_hal_busdevice_i2cdevice_unlock(busdevice_i2cdevice_obj_t *self) { } uint8_t common_hal_busdevice_i2cdevice_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length) { - uint8_t status = common_hal_busio_i2c_read(self->i2c, self->device_address, buffer, length); - - return status; + return common_hal_busio_i2c_read(self->i2c, self->device_address, buffer, length); } uint8_t common_hal_busdevice_i2cdevice_write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length) { - uint8_t status = common_hal_busio_i2c_write(self->i2c, self->device_address, buffer, length, true); - - return status; -} - -uint8_t common_hal_busdevice_i2cdevice_write_then_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t out_buffer, mp_obj_t in_buffer, - size_t out_length, size_t in_length) { - uint8_t status = 0; - - status = common_hal_busio_i2c_write(self->i2c, self->device_address, out_buffer, out_length, true); - - status = common_hal_busio_i2c_read(self->i2c, self->device_address, in_buffer, in_length); - - return status; + return common_hal_busio_i2c_write(self->i2c, self->device_address, buffer, length, true); } -void common_hal_busdevice_i2cdevice___probe_for_device(busdevice_i2cdevice_obj_t *self) { +void common_hal_busdevice_i2cdevice_probe_for_device(busdevice_i2cdevice_obj_t *self) { common_hal_busdevice_i2cdevice_lock(self); mp_buffer_info_t bufinfo; diff --git a/shared-module/busdevice/I2CDevice.h b/shared-module/busdevice/I2CDevice.h index c872704db..918dc7719 100644 --- a/shared-module/busdevice/I2CDevice.h +++ b/shared-module/busdevice/I2CDevice.h @@ -34,7 +34,6 @@ typedef struct { mp_obj_base_t base; busio_i2c_obj_t *i2c; uint8_t device_address; - bool probe; } busdevice_i2cdevice_obj_t; #endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_I2CDEVICE_H -- cgit v1.2.3 From 78477a374afad09aa7141af5cf590652b32c141f Mon Sep 17 00:00:00 2001 From: gamblor21 Date: Sat, 31 Oct 2020 12:17:29 -0500 Subject: Initial SPI commit --- py/circuitpy_defns.mk | 1 + shared-bindings/busdevice/SPIDevice.c | 124 ++++++++++++++++++++++++++++++++++ shared-bindings/busdevice/SPIDevice.h | 50 ++++++++++++++ shared-module/busdevice/SPIDevice.c | 85 +++++++++++++++++++++++ shared-module/busdevice/SPIDevice.h | 44 ++++++++++++ 5 files changed, 304 insertions(+) create mode 100644 shared-bindings/busdevice/SPIDevice.c create mode 100644 shared-bindings/busdevice/SPIDevice.h create mode 100644 shared-module/busdevice/SPIDevice.c create mode 100644 shared-module/busdevice/SPIDevice.h (limited to 'shared-module') diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 9318bd466..4822c0320 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -437,6 +437,7 @@ SRC_SHARED_MODULE_ALL = \ board/__init__.c \ busdevice/__init__.c \ busdevice/I2CDevice.c \ + busdevice/SPIDevice.c \ busio/OneWire.c \ displayio/Bitmap.c \ displayio/ColorConverter.c \ diff --git a/shared-bindings/busdevice/SPIDevice.c b/shared-bindings/busdevice/SPIDevice.c new file mode 100644 index 000000000..7ef047349 --- /dev/null +++ b/shared-bindings/busdevice/SPIDevice.c @@ -0,0 +1,124 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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 +// busio.SPI class. + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/busdevice/SPIDevice.h" +#include "shared-bindings/util.h" +#include "shared-module/busdevice/SPIDevice.h" +#include "common-hal/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOut.h" + + +#include "lib/utils/buffer_helper.h" +#include "lib/utils/context_manager_helpers.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + + +//| class SPIDevice: +//| """ +//| Represents a single SPI device and manages locking the bus and the device +//| address. +//| :param ~busio.SPI spi: The SPI bus the device is on +//| :param int device_address: The 7 bit device address +//| :param bool probe: Probe for the device upon object creation, default is true +//| .. note:: This class is **NOT** built into CircuitPython. See +//| :ref:`here for install instructions `. +//| Example: +//| .. code-block:: python +//| import busio +//| from board import * +//| from adafruit_bus_device.spi_device import SPIDevice +//| with busio.SPI(SCL, SDA) as spi: +//| device = SPIDevice(spi, 0x70) +//| bytes_read = bytearray(4) +//| with device: +//| device.readinto(bytes_read) +//| # A second transaction +//| with device: +//| device.write(bytes_read)""" +//| ... +//| +STATIC mp_obj_t busdevice_spidevice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + busdevice_spidevice_obj_t *self = m_new_obj(busdevice_spidevice_obj_t); + self->base.type = &busdevice_spidevice_type; + enum { ARG_spi, ARG_chip_select, ARG_baudrate, ARG_polarity, ARG_phase, ARG_extra_clocks }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_spi, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_chip_select, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_extra_clocks, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + 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 = args[ARG_spi].u_obj; + + common_hal_busdevice_spidevice_construct(MP_OBJ_TO_PTR(self), spi, args[ARG_chip_select].u_obj, args[ARG_baudrate].u_int, args[ARG_polarity].u_int, + args[ARG_phase].u_int, args[ARG_extra_clocks].u_int); + + if (args[ARG_chip_select].u_obj != MP_OBJ_NULL) { + digitalinout_result_t result = common_hal_digitalio_digitalinout_switch_to_output(MP_OBJ_TO_PTR(args[ARG_chip_select].u_obj), + true, DRIVE_MODE_PUSH_PULL); + if (result == DIGITALINOUT_INPUT_ONLY) { + mp_raise_NotImplementedError(translate("Pin is input only")); + } + } + + return (mp_obj_t)self; +} + +STATIC mp_obj_t busdevice_spidevice_obj___enter__(mp_obj_t self_in) { + busdevice_spidevice_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_busdevice_spidevice_enter(self); + return self; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(busdevice_spidevice___enter___obj, busdevice_spidevice_obj___enter__); + +STATIC mp_obj_t busdevice_spidevice_obj___exit__(size_t n_args, const mp_obj_t *args) { + common_hal_busdevice_spidevice_exit(MP_OBJ_TO_PTR(args[0])); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busdevice_spidevice___exit___obj, 4, 4, busdevice_spidevice_obj___exit__); + +STATIC const mp_rom_map_elem_t busdevice_spidevice_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&busdevice_spidevice___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busdevice_spidevice___exit___obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(busdevice_spidevice_locals_dict, busdevice_spidevice_locals_dict_table); + +const mp_obj_type_t busdevice_spidevice_type = { + { &mp_type_type }, + .name = MP_QSTR_SPIDevice, + .make_new = busdevice_spidevice_make_new, + .locals_dict = (mp_obj_dict_t*)&busdevice_spidevice_locals_dict, +}; diff --git a/shared-bindings/busdevice/SPIDevice.h b/shared-bindings/busdevice/SPIDevice.h new file mode 100644 index 000000000..040f98548 --- /dev/null +++ b/shared-bindings/busdevice/SPIDevice.h @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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. + */ + +// Machine is the HAL for low-level, hardware accelerated functions. It is not +// meant to simplify APIs, its only meant to unify them so that other modules +// do not require port specific logic. +// +// This file includes externs for all functions a port should implement to +// support the machine module. + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H + +#include "py/obj.h" + +#include "shared-module/busdevice/SPIDevice.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t busdevice_spidevice_type; + +// Initializes the hardware peripheral. +extern void common_hal_busdevice_spidevice_construct(busdevice_spidevice_obj_t *self, busio_spi_obj_t *spi, digitalio_digitalinout_obj_t *cs, + uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t extra_clocks); +extern void common_hal_busdevice_spidevice_enter(busdevice_spidevice_obj_t *self); +extern void common_hal_busdevice_spidevice_exit(busdevice_spidevice_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H diff --git a/shared-module/busdevice/SPIDevice.c b/shared-module/busdevice/SPIDevice.c new file mode 100644 index 000000000..d9b63a007 --- /dev/null +++ b/shared-module/busdevice/SPIDevice.c @@ -0,0 +1,85 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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/busdevice/SPIDevice.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "py/mperrno.h" +#include "py/nlr.h" +#include "py/runtime.h" + +void common_hal_busdevice_spidevice_construct(busdevice_spidevice_obj_t *self, busio_spi_obj_t *spi, digitalio_digitalinout_obj_t *cs, + uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t extra_clocks) { + self->spi = spi; + self->baudrate = baudrate; + self->polarity = polarity; + self->phase = phase; + self->extra_clocks = extra_clocks; + self->chip_select = cs; +} + +void common_hal_busdevice_spidevice_enter(busdevice_spidevice_obj_t *self) { + bool success = false; + while (!success) { + success = common_hal_busio_spi_try_lock(self->spi); + RUN_BACKGROUND_TASKS; + mp_handle_pending(); + } + + common_hal_busio_spi_configure(self->spi, self->baudrate, self->polarity, self->phase, 8); + + if (self->chip_select != MP_OBJ_NULL) { + common_hal_digitalio_digitalinout_set_value(MP_OBJ_TO_PTR(self->chip_select), false); + } +} + +void common_hal_busdevice_spidevice_exit(busdevice_spidevice_obj_t *self) { + if (self->chip_select != MP_OBJ_NULL) { + common_hal_digitalio_digitalinout_set_value(MP_OBJ_TO_PTR(self->chip_select), true); + } + + if (self->extra_clocks > 0) { + + mp_buffer_info_t bufinfo; + mp_obj_t buffer = mp_obj_new_bytearray_of_zeros(1); + + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); + ((uint8_t*)bufinfo.buf)[0] = 0xFF; + + uint8_t clocks = self->extra_clocks / 8; + if ((self->extra_clocks % 8) != 0) + clocks += 1; + + while (clocks > 0) { + if (!common_hal_busio_spi_write(self->spi, ((uint8_t*)bufinfo.buf), 1)) { + mp_raise_OSError(MP_EIO); + } + clocks--; + } + } + + common_hal_busio_spi_unlock(self->spi); +} diff --git a/shared-module/busdevice/SPIDevice.h b/shared-module/busdevice/SPIDevice.h new file mode 100644 index 000000000..ffabf79df --- /dev/null +++ b/shared-module/busdevice/SPIDevice.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_SHARED_MODULE_BUSDEVICE_SPIDEVICE_H +#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_SPIDEVICE_H + +#include "py/obj.h" +#include "common-hal/busio/SPI.h" +#include "common-hal/digitalio/DigitalInOut.h" + +typedef struct { + mp_obj_base_t base; + busio_spi_obj_t *spi; + uint32_t baudrate; + uint8_t polarity; + uint8_t phase; + uint8_t extra_clocks; + digitalio_digitalinout_obj_t *chip_select; +} busdevice_spidevice_obj_t; + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_SPIDEVICE_H -- cgit v1.2.3 From 8bbbb2833ad6d9b649132559795f58f8f31f486f Mon Sep 17 00:00:00 2001 From: gamblor21 Date: Sun, 1 Nov 2020 21:38:20 -0600 Subject: Fixes from testing SPI --- shared-bindings/busdevice/SPIDevice.c | 2 +- shared-bindings/busdevice/__init__.c | 2 ++ shared-module/busdevice/I2CDevice.c | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/busdevice/SPIDevice.c b/shared-bindings/busdevice/SPIDevice.c index 4c633b4fd..631d0eec4 100644 --- a/shared-bindings/busdevice/SPIDevice.c +++ b/shared-bindings/busdevice/SPIDevice.c @@ -103,7 +103,7 @@ STATIC mp_obj_t busdevice_spidevice_make_new(const mp_obj_type_t *type, size_t n STATIC mp_obj_t busdevice_spidevice_obj___enter__(mp_obj_t self_in) { busdevice_spidevice_obj_t *self = MP_OBJ_TO_PTR(self_in); common_hal_busdevice_spidevice_enter(self); - return self; + return self->spi; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(busdevice_spidevice___enter___obj, busdevice_spidevice_obj___enter__); diff --git a/shared-bindings/busdevice/__init__.c b/shared-bindings/busdevice/__init__.c index 391d3698a..6e6ede532 100644 --- a/shared-bindings/busdevice/__init__.c +++ b/shared-bindings/busdevice/__init__.c @@ -33,6 +33,7 @@ #include "shared-bindings/busdevice/__init__.h" #include "shared-bindings/busdevice/I2CDevice.h" +#include "shared-bindings/busdevice/SPIDevice.h" //| """Hardware accelerated external bus access @@ -46,6 +47,7 @@ STATIC const mp_rom_map_elem_t busdevice_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_busdevice) }, { MP_ROM_QSTR(MP_QSTR_I2CDevice), MP_ROM_PTR(&busdevice_i2cdevice_type) }, + { MP_ROM_QSTR(MP_QSTR_SPIDevice), MP_ROM_PTR(&busdevice_spidevice_type) }, }; STATIC MP_DEFINE_CONST_DICT(busdevice_module_globals, busdevice_module_globals_table); diff --git a/shared-module/busdevice/I2CDevice.c b/shared-module/busdevice/I2CDevice.c index 41706c1a8..b9f8ee25c 100644 --- a/shared-module/busdevice/I2CDevice.c +++ b/shared-module/busdevice/I2CDevice.c @@ -39,8 +39,8 @@ void common_hal_busdevice_i2cdevice_lock(busdevice_i2cdevice_obj_t *self) { bool success = false; while (!success) { success = common_hal_busio_i2c_try_lock(self->i2c); - RUN_BACKGROUND_TASKS; - mp_handle_pending(); + //RUN_BACKGROUND_TASKS; + //mp_handle_pending(); } } -- cgit v1.2.3 From 4c93db35959e96889b3a28af792c837fbe1fdca5 Mon Sep 17 00:00:00 2001 From: gamblor21 Date: Tue, 3 Nov 2020 18:35:20 -0600 Subject: Renamed to adafruit_bus_device --- py/circuitpy_defns.mk | 8 +- py/circuitpy_mpconfig.h | 4 +- py/circuitpy_mpconfig.mk | 2 +- shared-bindings/adafruit_bus_device/I2CDevice.c | 262 ++++++++++++++++++++++++ shared-bindings/adafruit_bus_device/I2CDevice.h | 53 +++++ shared-bindings/adafruit_bus_device/SPIDevice.c | 128 ++++++++++++ shared-bindings/adafruit_bus_device/SPIDevice.h | 50 +++++ shared-bindings/adafruit_bus_device/__init__.c | 78 +++++++ shared-bindings/adafruit_bus_device/__init__.h | 32 +++ shared-bindings/busdevice/I2CDevice.c | 262 ------------------------ shared-bindings/busdevice/I2CDevice.h | 53 ----- shared-bindings/busdevice/SPIDevice.c | 128 ------------ shared-bindings/busdevice/SPIDevice.h | 50 ----- shared-bindings/busdevice/__init__.c | 78 ------- shared-bindings/busdevice/__init__.h | 32 --- shared-module/adafruit_bus_device/I2CDevice.c | 74 +++++++ shared-module/adafruit_bus_device/I2CDevice.h | 39 ++++ shared-module/adafruit_bus_device/SPIDevice.c | 85 ++++++++ shared-module/adafruit_bus_device/SPIDevice.h | 44 ++++ shared-module/adafruit_bus_device/__init__.c | 0 shared-module/busdevice/I2CDevice.c | 74 ------- shared-module/busdevice/I2CDevice.h | 39 ---- shared-module/busdevice/SPIDevice.c | 85 -------- shared-module/busdevice/SPIDevice.h | 44 ---- shared-module/busdevice/__init__.c | 0 25 files changed, 852 insertions(+), 852 deletions(-) create mode 100644 shared-bindings/adafruit_bus_device/I2CDevice.c create mode 100644 shared-bindings/adafruit_bus_device/I2CDevice.h create mode 100644 shared-bindings/adafruit_bus_device/SPIDevice.c create mode 100644 shared-bindings/adafruit_bus_device/SPIDevice.h create mode 100644 shared-bindings/adafruit_bus_device/__init__.c create mode 100644 shared-bindings/adafruit_bus_device/__init__.h delete mode 100644 shared-bindings/busdevice/I2CDevice.c delete mode 100644 shared-bindings/busdevice/I2CDevice.h delete mode 100644 shared-bindings/busdevice/SPIDevice.c delete mode 100644 shared-bindings/busdevice/SPIDevice.h delete mode 100644 shared-bindings/busdevice/__init__.c delete mode 100644 shared-bindings/busdevice/__init__.h create mode 100644 shared-module/adafruit_bus_device/I2CDevice.c create mode 100644 shared-module/adafruit_bus_device/I2CDevice.h create mode 100644 shared-module/adafruit_bus_device/SPIDevice.c create mode 100644 shared-module/adafruit_bus_device/SPIDevice.h create mode 100644 shared-module/adafruit_bus_device/__init__.c delete mode 100644 shared-module/busdevice/I2CDevice.c delete mode 100644 shared-module/busdevice/I2CDevice.h delete mode 100644 shared-module/busdevice/SPIDevice.c delete mode 100644 shared-module/busdevice/SPIDevice.h delete mode 100644 shared-module/busdevice/__init__.c (limited to 'shared-module') diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 4822c0320..41ef8d742 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -134,7 +134,7 @@ ifeq ($(CIRCUITPY_BOARD),1) SRC_PATTERNS += board/% endif ifeq ($(CIRCUITPY_BUSDEVICE),1) -SRC_PATTERNS += busdevice/% +SRC_PATTERNS += adafruit_bus_device/% endif ifeq ($(CIRCUITPY_BUSIO),1) SRC_PATTERNS += busio/% bitbangio/OneWire.% @@ -435,9 +435,9 @@ SRC_SHARED_MODULE_ALL = \ bitbangio/SPI.c \ bitbangio/__init__.c \ board/__init__.c \ - busdevice/__init__.c \ - busdevice/I2CDevice.c \ - busdevice/SPIDevice.c \ + adafruit_bus_device/__init__.c \ + adafruit_bus_device/I2CDevice.c \ + adafruit_bus_device/SPIDevice.c \ busio/OneWire.c \ displayio/Bitmap.c \ displayio/ColorConverter.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 240fac189..78de7905a 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -325,8 +325,8 @@ extern const struct _mp_obj_module_t board_module; #endif #if CIRCUITPY_BUSDEVICE -extern const struct _mp_obj_module_t busdevice_module; -#define BUSDEVICE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_busdevice), (mp_obj_t)&busdevice_module }, +extern const struct _mp_obj_module_t adafruit_bus_device_module; +#define BUSDEVICE_MODULE { MP_OBJ_NEW_QSTR(MP_QSTR_adafruit_bus_device), (mp_obj_t)&adafruit_bus_device_module }, #else #define BUSDEVICE_MODULE #endif diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 1f96a8f2d..e814edd16 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -90,7 +90,7 @@ CFLAGS += -DCIRCUITPY_BLEIO=$(CIRCUITPY_BLEIO) CIRCUITPY_BOARD ?= 1 CFLAGS += -DCIRCUITPY_BOARD=$(CIRCUITPY_BOARD) -CIRCUITPY_BUSDEVICE ?= 1 +CIRCUITPY_BUSDEVICE ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_BUSDEVICE=$(CIRCUITPY_BUSDEVICE) CIRCUITPY_BUSIO ?= 1 diff --git a/shared-bindings/adafruit_bus_device/I2CDevice.c b/shared-bindings/adafruit_bus_device/I2CDevice.c new file mode 100644 index 000000000..3ec4dae12 --- /dev/null +++ b/shared-bindings/adafruit_bus_device/I2CDevice.c @@ -0,0 +1,262 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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 +// busio.I2C class. + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/adafruit_bus_device/I2CDevice.h" +#include "shared-bindings/util.h" +#include "shared-module/adafruit_bus_device/I2CDevice.h" + +#include "lib/utils/buffer_helper.h" +#include "lib/utils/context_manager_helpers.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + + +//| class I2CDevice: +//| """I2C Device Manager""" +//| +//| def __init__(self, i2c: busio.I2C, device_address: int, probe: bool = True) -> None: +//| +//| """Represents a single I2C device and manages locking the bus and the device +//| address. +//| :param ~busio.I2C i2c: The I2C bus the device is on +//| :param int device_address: The 7 bit device address +//| :param bool probe: Probe for the device upon object creation, default is true +//| +//| Example:: +//| +//| import busio +//| from board import * +//| from adafruit_bus_device.i2c_device import I2CDevice +//| with busio.I2C(SCL, SDA) as i2c: +//| device = I2CDevice(i2c, 0x70) +//| bytes_read = bytearray(4) +//| with device: +//| device.readinto(bytes_read) +//| # A second transaction +//| with device: +//| device.write(bytes_read)""" +//| ... +//| +STATIC mp_obj_t adafruit_bus_device_i2cdevice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + adafruit_bus_device_i2cdevice_obj_t *self = m_new_obj(adafruit_bus_device_i2cdevice_obj_t); + self->base.type = &adafruit_bus_device_i2cdevice_type; + enum { ARG_i2c, ARG_device_address, ARG_probe }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_i2c, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_device_address, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_probe, MP_ARG_BOOL, {.u_bool = true} }, + }; + 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_i2c_obj_t* i2c = args[ARG_i2c].u_obj; + + common_hal_adafruit_bus_device_i2cdevice_construct(MP_OBJ_TO_PTR(self), i2c, args[ARG_device_address].u_int); + if (args[ARG_probe].u_bool == true) { + common_hal_adafruit_bus_device_i2cdevice_probe_for_device(self); + } + + return (mp_obj_t)self; +} + +//| def __enter__(self) -> I2C: +//| """Context manager entry to lock bus.""" +//| ... +//| +STATIC mp_obj_t adafruit_bus_device_i2cdevice_obj___enter__(mp_obj_t self_in) { + adafruit_bus_device_i2cdevice_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_adafruit_bus_device_i2cdevice_lock(self); + return self; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adafruit_bus_device_i2cdevice___enter___obj, adafruit_bus_device_i2cdevice_obj___enter__); + +//| def __exit__(self) -> None: +//| """Automatically unlocks the bus on exit.""" +//| ... +//| +STATIC mp_obj_t adafruit_bus_device_i2cdevice_obj___exit__(size_t n_args, const mp_obj_t *args) { + common_hal_adafruit_bus_device_i2cdevice_unlock(MP_OBJ_TO_PTR(args[0])); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(adafruit_bus_device_i2cdevice___exit___obj, 4, 4, adafruit_bus_device_i2cdevice_obj___exit__); + +//| def readinto(self, buf, *, start=0, end=None) -> None: +//| """ +//| Read into ``buf`` from the device. The number of bytes read will be the +//| length of ``buf``. +//| If ``start`` or ``end`` is provided, then the buffer will be sliced +//| as if ``buf[start:end]``. This will not cause an allocation like +//| ``buf[start:end]`` will so it saves memory. +//| :param bytearray buffer: buffer to write into +//| :param int start: Index to start writing at +//| :param int end: Index to write up to but not include; if None, use ``len(buf)``""" +//| ... +//| +STATIC void readinto(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_WRITE); + + size_t length = bufinfo.len; + normalize_buffer_bounds(&start, end, &length); + if (length == 0) { + mp_raise_ValueError(translate("Buffer must be at least length 1")); + } + + uint8_t status = common_hal_adafruit_bus_device_i2cdevice_readinto(MP_OBJ_TO_PTR(self), ((uint8_t*)bufinfo.buf) + start, length); + if (status != 0) { + mp_raise_OSError(status); + } +} + +STATIC mp_obj_t adafruit_bus_device_i2cdevice_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + + adafruit_bus_device_i2cdevice_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); + + readinto(self, args[ARG_buffer].u_obj, args[ARG_start].u_int, args[ARG_end].u_int); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adafruit_bus_device_i2cdevice_readinto_obj, 2, adafruit_bus_device_i2cdevice_readinto); + +//| def write(self, buf, *, start=0, end=None) -> None: +//| """ +//| Write the bytes from ``buffer`` to the device, then transmit a stop bit. +//| If ``start`` or ``end`` is provided, then the buffer will be sliced +//| as if ``buffer[start:end]``. This will not cause an allocation like +//| ``buffer[start:end]`` will so it saves memory. +//| :param bytearray buffer: buffer containing the bytes to write +//| :param int start: Index to start writing from +//| :param int end: Index to read up to but not include; if None, use ``len(buf)`` +//| """ +//| ... +//| +STATIC void write(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); + + size_t length = bufinfo.len; + normalize_buffer_bounds(&start, end, &length); + if (length == 0) { + mp_raise_ValueError(translate("Buffer must be at least length 1")); + } + + uint8_t status = common_hal_adafruit_bus_device_i2cdevice_write(MP_OBJ_TO_PTR(self), ((uint8_t*)bufinfo.buf) + start, length); + if (status != 0) { + mp_raise_OSError(status); + } +} + +STATIC mp_obj_t adafruit_bus_device_i2cdevice_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + adafruit_bus_device_i2cdevice_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); + + write(self, args[ARG_buffer].u_obj, args[ARG_start].u_int, args[ARG_end].u_int); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(adafruit_bus_device_i2cdevice_write_obj, 2, adafruit_bus_device_i2cdevice_write); + + +//| def write_then_readinto(self, out_buffer, in_buffer, *, out_start=0, out_end=None, in_start=0, in_end=None) -> None: +//| """ +//| Write the bytes from ``out_buffer`` to the device, then immediately +//| reads into ``in_buffer`` from the device. The number of bytes read +//| will be the length of ``in_buffer``. +//| If ``out_start`` or ``out_end`` is provided, then the output buffer +//| will be sliced as if ``out_buffer[out_start:out_end]``. This will +//| not cause an allocation like ``buffer[out_start:out_end]`` will so +//| it saves memory. +//| If ``in_start`` or ``in_end`` is provided, then the input buffer +//| will be sliced as if ``in_buffer[in_start:in_end]``. This will not +//| cause an allocation like ``in_buffer[in_start:in_end]`` will so +//| it saves memory. +//| :param bytearray out_buffer: buffer containing the bytes to write +//| :param bytearray in_buffer: buffer containing the bytes to read into +//| :param int out_start: Index to start writing from +//| :param int out_end: Index to read up to but not include; if None, use ``len(out_buffer)`` +//| :param int in_start: Index to start writing at +//| :param int in_end: Index to write up to but not include; if None, use ``len(in_buffer)`` +//| """ +//| ... +//| +STATIC mp_obj_t adafruit_bus_device_i2cdevice_write_then_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + adafruit_bus_device_i2cdevice_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); + + write(self, args[ARG_out_buffer].u_obj, args[ARG_out_start].u_int, args[ARG_out_end].u_int); + + readinto(self, args[ARG_in_buffer].u_obj, args[ARG_in_start].u_int, args[ARG_in_end].u_int); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(adafruit_bus_device_i2cdevice_write_then_readinto_obj, 3, adafruit_bus_device_i2cdevice_write_then_readinto); + +STATIC const mp_rom_map_elem_t adafruit_bus_device_i2cdevice_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&adafruit_bus_device_i2cdevice___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&adafruit_bus_device_i2cdevice___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&adafruit_bus_device_i2cdevice_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&adafruit_bus_device_i2cdevice_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_then_readinto), MP_ROM_PTR(&adafruit_bus_device_i2cdevice_write_then_readinto_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_i2cdevice_locals_dict, adafruit_bus_device_i2cdevice_locals_dict_table); + +const mp_obj_type_t adafruit_bus_device_i2cdevice_type = { + { &mp_type_type }, + .name = MP_QSTR_I2CDevice, + .make_new = adafruit_bus_device_i2cdevice_make_new, + .locals_dict = (mp_obj_dict_t*)&adafruit_bus_device_i2cdevice_locals_dict, +}; diff --git a/shared-bindings/adafruit_bus_device/I2CDevice.h b/shared-bindings/adafruit_bus_device/I2CDevice.h new file mode 100644 index 000000000..7b2182ff0 --- /dev/null +++ b/shared-bindings/adafruit_bus_device/I2CDevice.h @@ -0,0 +1,53 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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. + */ + +// Machine is the HAL for low-level, hardware accelerated functions. It is not +// meant to simplify APIs, its only meant to unify them so that other modules +// do not require port specific logic. +// +// This file includes externs for all functions a port should implement to +// support the machine module. + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H + +#include "py/obj.h" + +#include "shared-module/adafruit_bus_device/I2CDevice.h" +//#include "shared-bindings/busio/I2C.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t adafruit_bus_device_i2cdevice_type; + +// Initializes the hardware peripheral. +extern void common_hal_adafruit_bus_device_i2cdevice_construct(adafruit_bus_device_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address); +extern uint8_t common_hal_adafruit_bus_device_i2cdevice_readinto(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); +extern uint8_t common_hal_adafruit_bus_device_i2cdevice_write(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); +extern void common_hal_adafruit_bus_device_i2cdevice_lock(adafruit_bus_device_i2cdevice_obj_t *self); +extern void common_hal_adafruit_bus_device_i2cdevice_unlock(adafruit_bus_device_i2cdevice_obj_t *self); +extern void common_hal_adafruit_bus_device_i2cdevice_probe_for_device(adafruit_bus_device_i2cdevice_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H diff --git a/shared-bindings/adafruit_bus_device/SPIDevice.c b/shared-bindings/adafruit_bus_device/SPIDevice.c new file mode 100644 index 000000000..e127e39b8 --- /dev/null +++ b/shared-bindings/adafruit_bus_device/SPIDevice.c @@ -0,0 +1,128 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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/adafruit_bus_device/SPIDevice.h" +#include "shared-bindings/util.h" +#include "shared-module/adafruit_bus_device/SPIDevice.h" +#include "common-hal/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOut.h" + + +#include "lib/utils/buffer_helper.h" +#include "lib/utils/context_manager_helpers.h" +#include "py/runtime.h" +#include "supervisor/shared/translate.h" + + +//| class SPIDevice: +//| """SPI Device Manager""" +//| +//| def __init__(self, spi: busio.SPI, chip_select: microcontroller.Pin, *, baudrate: int = 100000, polarity: int = 0, phase: int = 0, extra_clocks : int = 0) -> None: +//| +//| """ +//| Represents a single SPI device and manages locking the bus and the device address. +//| :param ~busio.SPI spi: The SPI bus the device is on +//| :param ~digitalio.DigitalInOut chip_select: The chip select pin object that implements the DigitalInOut API. +//| :param int extra_clocks: The minimum number of clock cycles to cycle the bus after CS is high. (Used for SD cards.) +//| +//| Example:: +//| +//| import busio +//| import digitalio +//| from board import * +//| from adafruit_bus_device.spi_device import SPIDevice +//| with busio.SPI(SCK, MOSI, MISO) as spi_bus: +//| cs = digitalio.DigitalInOut(D10) +//| device = SPIDevice(spi_bus, cs) +//| bytes_read = bytearray(4) +//| # The object assigned to spi in the with statements below +//| # is the original spi_bus object. We are using the busio.SPI +//| # operations busio.SPI.readinto() and busio.SPI.write(). +//| with device as spi: +//| spi.readinto(bytes_read) +//| # A second transaction +//| with device as spi: +//| spi.write(bytes_read)""" +//| ... +//| +STATIC mp_obj_t adafruit_bus_device_spidevice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + adafruit_bus_device_spidevice_obj_t *self = m_new_obj(adafruit_bus_device_spidevice_obj_t); + self->base.type = &adafruit_bus_device_spidevice_type; + enum { ARG_spi, ARG_chip_select, ARG_baudrate, ARG_polarity, ARG_phase, ARG_extra_clocks }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_spi, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_chip_select, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_extra_clocks, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + 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 = args[ARG_spi].u_obj; + + common_hal_adafruit_bus_device_spidevice_construct(MP_OBJ_TO_PTR(self), spi, args[ARG_chip_select].u_obj, args[ARG_baudrate].u_int, args[ARG_polarity].u_int, + args[ARG_phase].u_int, args[ARG_extra_clocks].u_int); + + if (args[ARG_chip_select].u_obj != MP_OBJ_NULL) { + digitalinout_result_t result = common_hal_digitalio_digitalinout_switch_to_output(MP_OBJ_TO_PTR(args[ARG_chip_select].u_obj), + true, DRIVE_MODE_PUSH_PULL); + if (result == DIGITALINOUT_INPUT_ONLY) { + mp_raise_NotImplementedError(translate("Pin is input only")); + } + } + + return (mp_obj_t)self; +} + +STATIC mp_obj_t adafruit_bus_device_spidevice_obj___enter__(mp_obj_t self_in) { + adafruit_bus_device_spidevice_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_adafruit_bus_device_spidevice_enter(self); + return self->spi; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(adafruit_bus_device_spidevice___enter___obj, adafruit_bus_device_spidevice_obj___enter__); + +STATIC mp_obj_t adafruit_bus_device_spidevice_obj___exit__(size_t n_args, const mp_obj_t *args) { + common_hal_adafruit_bus_device_spidevice_exit(MP_OBJ_TO_PTR(args[0])); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(adafruit_bus_device_spidevice___exit___obj, 4, 4, adafruit_bus_device_spidevice_obj___exit__); + +STATIC const mp_rom_map_elem_t adafruit_bus_device_spidevice_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&adafruit_bus_device_spidevice___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&adafruit_bus_device_spidevice___exit___obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_spidevice_locals_dict, adafruit_bus_device_spidevice_locals_dict_table); + +const mp_obj_type_t adafruit_bus_device_spidevice_type = { + { &mp_type_type }, + .name = MP_QSTR_SPIDevice, + .make_new = adafruit_bus_device_spidevice_make_new, + .locals_dict = (mp_obj_dict_t*)&adafruit_bus_device_spidevice_locals_dict, +}; diff --git a/shared-bindings/adafruit_bus_device/SPIDevice.h b/shared-bindings/adafruit_bus_device/SPIDevice.h new file mode 100644 index 000000000..5596b157f --- /dev/null +++ b/shared-bindings/adafruit_bus_device/SPIDevice.h @@ -0,0 +1,50 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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. + */ + +// Machine is the HAL for low-level, hardware accelerated functions. It is not +// meant to simplify APIs, its only meant to unify them so that other modules +// do not require port specific logic. +// +// This file includes externs for all functions a port should implement to +// support the machine module. + +#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H + +#include "py/obj.h" + +#include "shared-module/adafruit_bus_device/SPIDevice.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t adafruit_bus_device_spidevice_type; + +// Initializes the hardware peripheral. +extern void common_hal_adafruit_bus_device_spidevice_construct(adafruit_bus_device_spidevice_obj_t *self, busio_spi_obj_t *spi, digitalio_digitalinout_obj_t *cs, + uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t extra_clocks); +extern void common_hal_adafruit_bus_device_spidevice_enter(adafruit_bus_device_spidevice_obj_t *self); +extern void common_hal_adafruit_bus_device_spidevice_exit(adafruit_bus_device_spidevice_obj_t *self); + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H diff --git a/shared-bindings/adafruit_bus_device/__init__.c b/shared-bindings/adafruit_bus_device/__init__.c new file mode 100644 index 000000000..e01abcab3 --- /dev/null +++ b/shared-bindings/adafruit_bus_device/__init__.c @@ -0,0 +1,78 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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 "py/mphal.h" +#include "py/objproperty.h" + +#include "shared-bindings/adafruit_bus_device/__init__.h" +#include "shared-bindings/adafruit_bus_device/I2CDevice.h" +#include "shared-bindings/adafruit_bus_device/SPIDevice.h" + +STATIC const mp_rom_map_elem_t adafruit_bus_device_i2c_device_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_i2c_device) }, + { MP_ROM_QSTR(MP_QSTR_I2CDevice), MP_ROM_PTR(&adafruit_bus_device_i2cdevice_type) }, +}; +STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_i2c_device_globals, adafruit_bus_device_i2c_device_globals_table); + +const mp_obj_module_t adafruit_bus_device_i2c_device_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&adafruit_bus_device_i2c_device_globals, +}; + +STATIC const mp_rom_map_elem_t adafruit_bus_device_spi_device_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_spi_device) }, + { MP_ROM_QSTR(MP_QSTR_SPIDevice), MP_ROM_PTR(&adafruit_bus_device_spidevice_type) }, +}; +STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_spi_device_globals, adafruit_bus_device_spi_device_globals_table); + +const mp_obj_module_t adafruit_bus_device_spi_device_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&adafruit_bus_device_spi_device_globals, +}; + +//| """Hardware accelerated external bus access +//| +//| The I2CDevice and SPIDevice helper classes make managing transaction state on a bus easy. +//| For example, they manage locking the bus to prevent other concurrent access. For SPI +//| devices, it manages the chip select and protocol changes such as mode. For I2C, it +//| manages the device address.""" +//| +STATIC const mp_rom_map_elem_t adafruit_bus_device_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_adafruit_bus_device) }, + { MP_ROM_QSTR(MP_QSTR_i2c_device), MP_ROM_PTR(&adafruit_bus_device_i2c_device_module) }, + { MP_ROM_QSTR(MP_QSTR_spi_device), MP_ROM_PTR(&adafruit_bus_device_spi_device_module) }, +}; + +STATIC MP_DEFINE_CONST_DICT(adafruit_bus_device_module_globals, adafruit_bus_device_module_globals_table); + +const mp_obj_module_t adafruit_bus_device_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&adafruit_bus_device_module_globals, +}; diff --git a/shared-bindings/adafruit_bus_device/__init__.h b/shared-bindings/adafruit_bus_device/__init__.h new file mode 100644 index 000000000..4a669807b --- /dev/null +++ b/shared-bindings/adafruit_bus_device/__init__.h @@ -0,0 +1,32 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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_BUSDEVICE___INIT___H +#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE___INIT___H + +// Nothing now. + +#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE___INIT___H diff --git a/shared-bindings/busdevice/I2CDevice.c b/shared-bindings/busdevice/I2CDevice.c deleted file mode 100644 index 43996138b..000000000 --- a/shared-bindings/busdevice/I2CDevice.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Mark Komus - * - * 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 -// busio.I2C class. - -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/busdevice/I2CDevice.h" -#include "shared-bindings/util.h" -#include "shared-module/busdevice/I2CDevice.h" - -#include "lib/utils/buffer_helper.h" -#include "lib/utils/context_manager_helpers.h" -#include "py/runtime.h" -#include "supervisor/shared/translate.h" - - -//| class I2CDevice: -//| """I2C Device Manager""" -//| -//| def __init__(self, i2c: busio.I2C, device_address: int, probe: bool = True) -> None: -//| -//| """Represents a single I2C device and manages locking the bus and the device -//| address. -//| :param ~busio.I2C i2c: The I2C bus the device is on -//| :param int device_address: The 7 bit device address -//| :param bool probe: Probe for the device upon object creation, default is true -//| -//| Example:: -//| -//| import busio -//| from board import * -//| from adafruit_bus_device.i2c_device import I2CDevice -//| with busio.I2C(SCL, SDA) as i2c: -//| device = I2CDevice(i2c, 0x70) -//| bytes_read = bytearray(4) -//| with device: -//| device.readinto(bytes_read) -//| # A second transaction -//| with device: -//| device.write(bytes_read)""" -//| ... -//| -STATIC mp_obj_t busdevice_i2cdevice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - busdevice_i2cdevice_obj_t *self = m_new_obj(busdevice_i2cdevice_obj_t); - self->base.type = &busdevice_i2cdevice_type; - enum { ARG_i2c, ARG_device_address, ARG_probe }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_i2c, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_device_address, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_probe, MP_ARG_BOOL, {.u_bool = true} }, - }; - 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_i2c_obj_t* i2c = args[ARG_i2c].u_obj; - - common_hal_busdevice_i2cdevice_construct(MP_OBJ_TO_PTR(self), i2c, args[ARG_device_address].u_int); - if (args[ARG_probe].u_bool == true) { - common_hal_busdevice_i2cdevice_probe_for_device(self); - } - - return (mp_obj_t)self; -} - -//| def __enter__(self) -> I2C: -//| """Context manager entry to lock bus.""" -//| ... -//| -STATIC mp_obj_t busdevice_i2cdevice_obj___enter__(mp_obj_t self_in) { - busdevice_i2cdevice_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_busdevice_i2cdevice_lock(self); - return self; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(busdevice_i2cdevice___enter___obj, busdevice_i2cdevice_obj___enter__); - -//| def __exit__(self) -> None: -//| """Automatically unlocks the bus on exit.""" -//| ... -//| -STATIC mp_obj_t busdevice_i2cdevice_obj___exit__(size_t n_args, const mp_obj_t *args) { - common_hal_busdevice_i2cdevice_unlock(MP_OBJ_TO_PTR(args[0])); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busdevice_i2cdevice___exit___obj, 4, 4, busdevice_i2cdevice_obj___exit__); - -//| def readinto(self, buf, *, start=0, end=None) -> None: -//| """ -//| Read into ``buf`` from the device. The number of bytes read will be the -//| length of ``buf``. -//| If ``start`` or ``end`` is provided, then the buffer will be sliced -//| as if ``buf[start:end]``. This will not cause an allocation like -//| ``buf[start:end]`` will so it saves memory. -//| :param bytearray buffer: buffer to write into -//| :param int start: Index to start writing at -//| :param int end: Index to write up to but not include; if None, use ``len(buf)``""" -//| ... -//| -STATIC void readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_WRITE); - - size_t length = bufinfo.len; - normalize_buffer_bounds(&start, end, &length); - if (length == 0) { - mp_raise_ValueError(translate("Buffer must be at least length 1")); - } - - uint8_t status = common_hal_busdevice_i2cdevice_readinto(MP_OBJ_TO_PTR(self), ((uint8_t*)bufinfo.buf) + start, length); - if (status != 0) { - mp_raise_OSError(status); - } -} - -STATIC mp_obj_t busdevice_i2cdevice_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_buffer, ARG_start, ARG_end }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, - }; - - busdevice_i2cdevice_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); - - readinto(self, args[ARG_buffer].u_obj, args[ARG_start].u_int, args[ARG_end].u_int); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_readinto_obj, 2, busdevice_i2cdevice_readinto); - -//| def write(self, buf, *, start=0, end=None) -> None: -//| """ -//| Write the bytes from ``buffer`` to the device, then transmit a stop bit. -//| If ``start`` or ``end`` is provided, then the buffer will be sliced -//| as if ``buffer[start:end]``. This will not cause an allocation like -//| ``buffer[start:end]`` will so it saves memory. -//| :param bytearray buffer: buffer containing the bytes to write -//| :param int start: Index to start writing from -//| :param int end: Index to read up to but not include; if None, use ``len(buf)`` -//| """ -//| ... -//| -STATIC void write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); - - size_t length = bufinfo.len; - normalize_buffer_bounds(&start, end, &length); - if (length == 0) { - mp_raise_ValueError(translate("Buffer must be at least length 1")); - } - - uint8_t status = common_hal_busdevice_i2cdevice_write(MP_OBJ_TO_PTR(self), ((uint8_t*)bufinfo.buf) + start, length); - if (status != 0) { - mp_raise_OSError(status); - } -} - -STATIC mp_obj_t busdevice_i2cdevice_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_buffer, ARG_start, ARG_end }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, - }; - busdevice_i2cdevice_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); - - write(self, args[ARG_buffer].u_obj, args[ARG_start].u_int, args[ARG_end].u_int); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_write_obj, 2, busdevice_i2cdevice_write); - - -//| def write_then_readinto(self, out_buffer, in_buffer, *, out_start=0, out_end=None, in_start=0, in_end=None) -> None: -//| """ -//| Write the bytes from ``out_buffer`` to the device, then immediately -//| reads into ``in_buffer`` from the device. The number of bytes read -//| will be the length of ``in_buffer``. -//| If ``out_start`` or ``out_end`` is provided, then the output buffer -//| will be sliced as if ``out_buffer[out_start:out_end]``. This will -//| not cause an allocation like ``buffer[out_start:out_end]`` will so -//| it saves memory. -//| If ``in_start`` or ``in_end`` is provided, then the input buffer -//| will be sliced as if ``in_buffer[in_start:in_end]``. This will not -//| cause an allocation like ``in_buffer[in_start:in_end]`` will so -//| it saves memory. -//| :param bytearray out_buffer: buffer containing the bytes to write -//| :param bytearray in_buffer: buffer containing the bytes to read into -//| :param int out_start: Index to start writing from -//| :param int out_end: Index to read up to but not include; if None, use ``len(out_buffer)`` -//| :param int in_start: Index to start writing at -//| :param int in_end: Index to write up to but not include; if None, use ``len(in_buffer)`` -//| """ -//| ... -//| -STATIC mp_obj_t busdevice_i2cdevice_write_then_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, - { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, - }; - busdevice_i2cdevice_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); - - write(self, args[ARG_out_buffer].u_obj, args[ARG_out_start].u_int, args[ARG_out_end].u_int); - - readinto(self, args[ARG_in_buffer].u_obj, args[ARG_in_start].u_int, args[ARG_in_end].u_int); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(busdevice_i2cdevice_write_then_readinto_obj, 3, busdevice_i2cdevice_write_then_readinto); - -STATIC const mp_rom_map_elem_t busdevice_i2cdevice_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&busdevice_i2cdevice___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busdevice_i2cdevice___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&busdevice_i2cdevice_readinto_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&busdevice_i2cdevice_write_obj) }, - { MP_ROM_QSTR(MP_QSTR_write_then_readinto), MP_ROM_PTR(&busdevice_i2cdevice_write_then_readinto_obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(busdevice_i2cdevice_locals_dict, busdevice_i2cdevice_locals_dict_table); - -const mp_obj_type_t busdevice_i2cdevice_type = { - { &mp_type_type }, - .name = MP_QSTR_I2CDevice, - .make_new = busdevice_i2cdevice_make_new, - .locals_dict = (mp_obj_dict_t*)&busdevice_i2cdevice_locals_dict, -}; diff --git a/shared-bindings/busdevice/I2CDevice.h b/shared-bindings/busdevice/I2CDevice.h deleted file mode 100644 index a1f869c45..000000000 --- a/shared-bindings/busdevice/I2CDevice.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Mark Komus - * - * 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. - */ - -// Machine is the HAL for low-level, hardware accelerated functions. It is not -// meant to simplify APIs, its only meant to unify them so that other modules -// do not require port specific logic. -// -// This file includes externs for all functions a port should implement to -// support the machine module. - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H - -#include "py/obj.h" - -#include "shared-module/busdevice/I2CDevice.h" -//#include "shared-bindings/busio/I2C.h" - -// Type object used in Python. Should be shared between ports. -extern const mp_obj_type_t busdevice_i2cdevice_type; - -// Initializes the hardware peripheral. -extern void common_hal_busdevice_i2cdevice_construct(busdevice_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address); -extern uint8_t common_hal_busdevice_i2cdevice_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); -extern uint8_t common_hal_busdevice_i2cdevice_write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); -extern void common_hal_busdevice_i2cdevice_lock(busdevice_i2cdevice_obj_t *self); -extern void common_hal_busdevice_i2cdevice_unlock(busdevice_i2cdevice_obj_t *self); -extern void common_hal_busdevice_i2cdevice_probe_for_device(busdevice_i2cdevice_obj_t *self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_I2CDEVICE_H diff --git a/shared-bindings/busdevice/SPIDevice.c b/shared-bindings/busdevice/SPIDevice.c deleted file mode 100644 index 631d0eec4..000000000 --- a/shared-bindings/busdevice/SPIDevice.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Mark Komus - * - * 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/busdevice/SPIDevice.h" -#include "shared-bindings/util.h" -#include "shared-module/busdevice/SPIDevice.h" -#include "common-hal/digitalio/DigitalInOut.h" -#include "shared-bindings/digitalio/DigitalInOut.h" - - -#include "lib/utils/buffer_helper.h" -#include "lib/utils/context_manager_helpers.h" -#include "py/runtime.h" -#include "supervisor/shared/translate.h" - - -//| class SPIDevice: -//| """SPI Device Manager""" -//| -//| def __init__(self, spi: busio.SPI, chip_select: microcontroller.Pin, *, baudrate: int = 100000, polarity: int = 0, phase: int = 0, extra_clocks : int = 0) -> None: -//| -//| """ -//| Represents a single SPI device and manages locking the bus and the device address. -//| :param ~busio.SPI spi: The SPI bus the device is on -//| :param ~digitalio.DigitalInOut chip_select: The chip select pin object that implements the DigitalInOut API. -//| :param int extra_clocks: The minimum number of clock cycles to cycle the bus after CS is high. (Used for SD cards.) -//| -//| Example:: -//| -//| import busio -//| import digitalio -//| from board import * -//| from adafruit_bus_device.spi_device import SPIDevice -//| with busio.SPI(SCK, MOSI, MISO) as spi_bus: -//| cs = digitalio.DigitalInOut(D10) -//| device = SPIDevice(spi_bus, cs) -//| bytes_read = bytearray(4) -//| # The object assigned to spi in the with statements below -//| # is the original spi_bus object. We are using the busio.SPI -//| # operations busio.SPI.readinto() and busio.SPI.write(). -//| with device as spi: -//| spi.readinto(bytes_read) -//| # A second transaction -//| with device as spi: -//| spi.write(bytes_read)""" -//| ... -//| -STATIC mp_obj_t busdevice_spidevice_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - busdevice_spidevice_obj_t *self = m_new_obj(busdevice_spidevice_obj_t); - self->base.type = &busdevice_spidevice_type; - enum { ARG_spi, ARG_chip_select, ARG_baudrate, ARG_polarity, ARG_phase, ARG_extra_clocks }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_spi, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_chip_select, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} }, - { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_extra_clocks, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - }; - 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 = args[ARG_spi].u_obj; - - common_hal_busdevice_spidevice_construct(MP_OBJ_TO_PTR(self), spi, args[ARG_chip_select].u_obj, args[ARG_baudrate].u_int, args[ARG_polarity].u_int, - args[ARG_phase].u_int, args[ARG_extra_clocks].u_int); - - if (args[ARG_chip_select].u_obj != MP_OBJ_NULL) { - digitalinout_result_t result = common_hal_digitalio_digitalinout_switch_to_output(MP_OBJ_TO_PTR(args[ARG_chip_select].u_obj), - true, DRIVE_MODE_PUSH_PULL); - if (result == DIGITALINOUT_INPUT_ONLY) { - mp_raise_NotImplementedError(translate("Pin is input only")); - } - } - - return (mp_obj_t)self; -} - -STATIC mp_obj_t busdevice_spidevice_obj___enter__(mp_obj_t self_in) { - busdevice_spidevice_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_busdevice_spidevice_enter(self); - return self->spi; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_1(busdevice_spidevice___enter___obj, busdevice_spidevice_obj___enter__); - -STATIC mp_obj_t busdevice_spidevice_obj___exit__(size_t n_args, const mp_obj_t *args) { - common_hal_busdevice_spidevice_exit(MP_OBJ_TO_PTR(args[0])); - return mp_const_none; -} -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(busdevice_spidevice___exit___obj, 4, 4, busdevice_spidevice_obj___exit__); - -STATIC const mp_rom_map_elem_t busdevice_spidevice_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&busdevice_spidevice___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&busdevice_spidevice___exit___obj) }, -}; - -STATIC MP_DEFINE_CONST_DICT(busdevice_spidevice_locals_dict, busdevice_spidevice_locals_dict_table); - -const mp_obj_type_t busdevice_spidevice_type = { - { &mp_type_type }, - .name = MP_QSTR_SPIDevice, - .make_new = busdevice_spidevice_make_new, - .locals_dict = (mp_obj_dict_t*)&busdevice_spidevice_locals_dict, -}; diff --git a/shared-bindings/busdevice/SPIDevice.h b/shared-bindings/busdevice/SPIDevice.h deleted file mode 100644 index 040f98548..000000000 --- a/shared-bindings/busdevice/SPIDevice.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Mark Komus - * - * 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. - */ - -// Machine is the HAL for low-level, hardware accelerated functions. It is not -// meant to simplify APIs, its only meant to unify them so that other modules -// do not require port specific logic. -// -// This file includes externs for all functions a port should implement to -// support the machine module. - -#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H - -#include "py/obj.h" - -#include "shared-module/busdevice/SPIDevice.h" - -// Type object used in Python. Should be shared between ports. -extern const mp_obj_type_t busdevice_spidevice_type; - -// Initializes the hardware peripheral. -extern void common_hal_busdevice_spidevice_construct(busdevice_spidevice_obj_t *self, busio_spi_obj_t *spi, digitalio_digitalinout_obj_t *cs, - uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t extra_clocks); -extern void common_hal_busdevice_spidevice_enter(busdevice_spidevice_obj_t *self); -extern void common_hal_busdevice_spidevice_exit(busdevice_spidevice_obj_t *self); - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE_SPIDEVICE_H diff --git a/shared-bindings/busdevice/__init__.c b/shared-bindings/busdevice/__init__.c deleted file mode 100644 index a9a1a83a3..000000000 --- a/shared-bindings/busdevice/__init__.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Mark Komus - * - * 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 "py/mphal.h" -#include "py/objproperty.h" - -#include "shared-bindings/busdevice/__init__.h" -#include "shared-bindings/busdevice/I2CDevice.h" -#include "shared-bindings/busdevice/SPIDevice.h" - -STATIC const mp_rom_map_elem_t busdevice_i2c_device_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_i2c_device) }, - { MP_ROM_QSTR(MP_QSTR_I2CDevice), MP_ROM_PTR(&busdevice_i2cdevice_type) }, -}; -STATIC MP_DEFINE_CONST_DICT(busdevice_i2c_device_globals, busdevice_i2c_device_globals_table); - -const mp_obj_module_t busdevice_i2c_device_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&busdevice_i2c_device_globals, -}; - -STATIC const mp_rom_map_elem_t busdevice_spi_device_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_spi_device) }, - { MP_ROM_QSTR(MP_QSTR_SPIDevice), MP_ROM_PTR(&busdevice_spidevice_type) }, -}; -STATIC MP_DEFINE_CONST_DICT(busdevice_spi_device_globals, busdevice_spi_device_globals_table); - -const mp_obj_module_t busdevice_spi_device_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&busdevice_spi_device_globals, -}; - -//| """Hardware accelerated external bus access -//| -//| The I2CDevice and SPIDevice helper classes make managing transaction state on a bus easy. -//| For example, they manage locking the bus to prevent other concurrent access. For SPI -//| devices, it manages the chip select and protocol changes such as mode. For I2C, it -//| manages the device address.""" -//| -STATIC const mp_rom_map_elem_t busdevice_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_busdevice) }, - { MP_ROM_QSTR(MP_QSTR_i2c_device), MP_ROM_PTR(&busdevice_i2c_device_module) }, - { MP_ROM_QSTR(MP_QSTR_spi_device), MP_ROM_PTR(&busdevice_spi_device_module) }, -}; - -STATIC MP_DEFINE_CONST_DICT(busdevice_module_globals, busdevice_module_globals_table); - -const mp_obj_module_t busdevice_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t*)&busdevice_module_globals, -}; diff --git a/shared-bindings/busdevice/__init__.h b/shared-bindings/busdevice/__init__.h deleted file mode 100644 index 4a669807b..000000000 --- a/shared-bindings/busdevice/__init__.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Mark Komus - * - * 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_BUSDEVICE___INIT___H -#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE___INIT___H - -// Nothing now. - -#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSDEVICE___INIT___H diff --git a/shared-module/adafruit_bus_device/I2CDevice.c b/shared-module/adafruit_bus_device/I2CDevice.c new file mode 100644 index 000000000..d790ff53a --- /dev/null +++ b/shared-module/adafruit_bus_device/I2CDevice.c @@ -0,0 +1,74 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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/adafruit_bus_device/I2CDevice.h" +#include "shared-bindings/busio/I2C.h" +#include "py/mperrno.h" +#include "py/nlr.h" +#include "py/runtime.h" + +void common_hal_adafruit_bus_device_i2cdevice_construct(adafruit_bus_device_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address) { + self->i2c = i2c; + self->device_address = device_address; +} + +void common_hal_adafruit_bus_device_i2cdevice_lock(adafruit_bus_device_i2cdevice_obj_t *self) { + bool success = false; + while (!success) { + success = common_hal_busio_i2c_try_lock(self->i2c); + //RUN_BACKGROUND_TASKS; + //mp_handle_pending(); + } +} + +void common_hal_adafruit_bus_device_i2cdevice_unlock(adafruit_bus_device_i2cdevice_obj_t *self) { + common_hal_busio_i2c_unlock(self->i2c); +} + +uint8_t common_hal_adafruit_bus_device_i2cdevice_readinto(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length) { + return common_hal_busio_i2c_read(self->i2c, self->device_address, buffer, length); +} + +uint8_t common_hal_adafruit_bus_device_i2cdevice_write(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length) { + return common_hal_busio_i2c_write(self->i2c, self->device_address, buffer, length, true); +} + +void common_hal_adafruit_bus_device_i2cdevice_probe_for_device(adafruit_bus_device_i2cdevice_obj_t *self) { + common_hal_adafruit_bus_device_i2cdevice_lock(self); + + mp_buffer_info_t bufinfo; + mp_obj_t buffer = mp_obj_new_bytearray_of_zeros(1); + + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_WRITE); + + uint8_t status = common_hal_adafruit_bus_device_i2cdevice_readinto(self, (uint8_t*)bufinfo.buf, 1); + if (status != 0) { + common_hal_adafruit_bus_device_i2cdevice_unlock(self); + mp_raise_ValueError_varg(translate("No I2C device at address: %x"), self->device_address); + } + + common_hal_adafruit_bus_device_i2cdevice_unlock(self); +} diff --git a/shared-module/adafruit_bus_device/I2CDevice.h b/shared-module/adafruit_bus_device/I2CDevice.h new file mode 100644 index 000000000..d06adb9f5 --- /dev/null +++ b/shared-module/adafruit_bus_device/I2CDevice.h @@ -0,0 +1,39 @@ +/* + * 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_SHARED_MODULE_BUSDEVICE_I2CDEVICE_H +#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_I2CDEVICE_H + +#include "py/obj.h" +#include "common-hal/busio/I2C.h" + +typedef struct { + mp_obj_base_t base; + busio_i2c_obj_t *i2c; + uint8_t device_address; +} adafruit_bus_device_i2cdevice_obj_t; + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_I2CDEVICE_H diff --git a/shared-module/adafruit_bus_device/SPIDevice.c b/shared-module/adafruit_bus_device/SPIDevice.c new file mode 100644 index 000000000..e489fc7c0 --- /dev/null +++ b/shared-module/adafruit_bus_device/SPIDevice.c @@ -0,0 +1,85 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Mark Komus + * + * 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/adafruit_bus_device/SPIDevice.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "py/mperrno.h" +#include "py/nlr.h" +#include "py/runtime.h" + +void common_hal_adafruit_bus_device_spidevice_construct(adafruit_bus_device_spidevice_obj_t *self, busio_spi_obj_t *spi, digitalio_digitalinout_obj_t *cs, + uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t extra_clocks) { + self->spi = spi; + self->baudrate = baudrate; + self->polarity = polarity; + self->phase = phase; + self->extra_clocks = extra_clocks; + self->chip_select = cs; +} + +void common_hal_adafruit_bus_device_spidevice_enter(adafruit_bus_device_spidevice_obj_t *self) { + bool success = false; + while (!success) { + success = common_hal_busio_spi_try_lock(self->spi); + RUN_BACKGROUND_TASKS; + mp_handle_pending(); + } + + common_hal_busio_spi_configure(self->spi, self->baudrate, self->polarity, self->phase, 8); + + if (self->chip_select != MP_OBJ_NULL) { + common_hal_digitalio_digitalinout_set_value(MP_OBJ_TO_PTR(self->chip_select), false); + } +} + +void common_hal_adafruit_bus_device_spidevice_exit(adafruit_bus_device_spidevice_obj_t *self) { + if (self->chip_select != MP_OBJ_NULL) { + common_hal_digitalio_digitalinout_set_value(MP_OBJ_TO_PTR(self->chip_select), true); + } + + if (self->extra_clocks > 0) { + + mp_buffer_info_t bufinfo; + mp_obj_t buffer = mp_obj_new_bytearray_of_zeros(1); + + mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); + ((uint8_t*)bufinfo.buf)[0] = 0xFF; + + uint8_t clocks = self->extra_clocks / 8; + if ((self->extra_clocks % 8) != 0) + clocks += 1; + + while (clocks > 0) { + if (!common_hal_busio_spi_write(self->spi, ((uint8_t*)bufinfo.buf), 1)) { + mp_raise_OSError(MP_EIO); + } + clocks--; + } + } + + common_hal_busio_spi_unlock(self->spi); +} diff --git a/shared-module/adafruit_bus_device/SPIDevice.h b/shared-module/adafruit_bus_device/SPIDevice.h new file mode 100644 index 000000000..1a7c70fa7 --- /dev/null +++ b/shared-module/adafruit_bus_device/SPIDevice.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_SHARED_MODULE_BUSDEVICE_SPIDEVICE_H +#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_SPIDEVICE_H + +#include "py/obj.h" +#include "common-hal/busio/SPI.h" +#include "common-hal/digitalio/DigitalInOut.h" + +typedef struct { + mp_obj_base_t base; + busio_spi_obj_t *spi; + uint32_t baudrate; + uint8_t polarity; + uint8_t phase; + uint8_t extra_clocks; + digitalio_digitalinout_obj_t *chip_select; +} adafruit_bus_device_spidevice_obj_t; + +#endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_SPIDEVICE_H diff --git a/shared-module/adafruit_bus_device/__init__.c b/shared-module/adafruit_bus_device/__init__.c new file mode 100644 index 000000000..e69de29bb diff --git a/shared-module/busdevice/I2CDevice.c b/shared-module/busdevice/I2CDevice.c deleted file mode 100644 index b9f8ee25c..000000000 --- a/shared-module/busdevice/I2CDevice.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Mark Komus - * - * 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/busdevice/I2CDevice.h" -#include "shared-bindings/busio/I2C.h" -#include "py/mperrno.h" -#include "py/nlr.h" -#include "py/runtime.h" - -void common_hal_busdevice_i2cdevice_construct(busdevice_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address) { - self->i2c = i2c; - self->device_address = device_address; -} - -void common_hal_busdevice_i2cdevice_lock(busdevice_i2cdevice_obj_t *self) { - bool success = false; - while (!success) { - success = common_hal_busio_i2c_try_lock(self->i2c); - //RUN_BACKGROUND_TASKS; - //mp_handle_pending(); - } -} - -void common_hal_busdevice_i2cdevice_unlock(busdevice_i2cdevice_obj_t *self) { - common_hal_busio_i2c_unlock(self->i2c); -} - -uint8_t common_hal_busdevice_i2cdevice_readinto(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length) { - return common_hal_busio_i2c_read(self->i2c, self->device_address, buffer, length); -} - -uint8_t common_hal_busdevice_i2cdevice_write(busdevice_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length) { - return common_hal_busio_i2c_write(self->i2c, self->device_address, buffer, length, true); -} - -void common_hal_busdevice_i2cdevice_probe_for_device(busdevice_i2cdevice_obj_t *self) { - common_hal_busdevice_i2cdevice_lock(self); - - mp_buffer_info_t bufinfo; - mp_obj_t buffer = mp_obj_new_bytearray_of_zeros(1); - - mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_WRITE); - - uint8_t status = common_hal_busdevice_i2cdevice_readinto(self, (uint8_t*)bufinfo.buf, 1); - if (status != 0) { - common_hal_busdevice_i2cdevice_unlock(self); - mp_raise_ValueError_varg(translate("No I2C device at address: %x"), self->device_address); - } - - common_hal_busdevice_i2cdevice_unlock(self); -} diff --git a/shared-module/busdevice/I2CDevice.h b/shared-module/busdevice/I2CDevice.h deleted file mode 100644 index 918dc7719..000000000 --- a/shared-module/busdevice/I2CDevice.h +++ /dev/null @@ -1,39 +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_SHARED_MODULE_BUSDEVICE_I2CDEVICE_H -#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_I2CDEVICE_H - -#include "py/obj.h" -#include "common-hal/busio/I2C.h" - -typedef struct { - mp_obj_base_t base; - busio_i2c_obj_t *i2c; - uint8_t device_address; -} busdevice_i2cdevice_obj_t; - -#endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_I2CDEVICE_H diff --git a/shared-module/busdevice/SPIDevice.c b/shared-module/busdevice/SPIDevice.c deleted file mode 100644 index d9b63a007..000000000 --- a/shared-module/busdevice/SPIDevice.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2020 Mark Komus - * - * 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/busdevice/SPIDevice.h" -#include "shared-bindings/busio/SPI.h" -#include "shared-bindings/digitalio/DigitalInOut.h" -#include "py/mperrno.h" -#include "py/nlr.h" -#include "py/runtime.h" - -void common_hal_busdevice_spidevice_construct(busdevice_spidevice_obj_t *self, busio_spi_obj_t *spi, digitalio_digitalinout_obj_t *cs, - uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t extra_clocks) { - self->spi = spi; - self->baudrate = baudrate; - self->polarity = polarity; - self->phase = phase; - self->extra_clocks = extra_clocks; - self->chip_select = cs; -} - -void common_hal_busdevice_spidevice_enter(busdevice_spidevice_obj_t *self) { - bool success = false; - while (!success) { - success = common_hal_busio_spi_try_lock(self->spi); - RUN_BACKGROUND_TASKS; - mp_handle_pending(); - } - - common_hal_busio_spi_configure(self->spi, self->baudrate, self->polarity, self->phase, 8); - - if (self->chip_select != MP_OBJ_NULL) { - common_hal_digitalio_digitalinout_set_value(MP_OBJ_TO_PTR(self->chip_select), false); - } -} - -void common_hal_busdevice_spidevice_exit(busdevice_spidevice_obj_t *self) { - if (self->chip_select != MP_OBJ_NULL) { - common_hal_digitalio_digitalinout_set_value(MP_OBJ_TO_PTR(self->chip_select), true); - } - - if (self->extra_clocks > 0) { - - mp_buffer_info_t bufinfo; - mp_obj_t buffer = mp_obj_new_bytearray_of_zeros(1); - - mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); - ((uint8_t*)bufinfo.buf)[0] = 0xFF; - - uint8_t clocks = self->extra_clocks / 8; - if ((self->extra_clocks % 8) != 0) - clocks += 1; - - while (clocks > 0) { - if (!common_hal_busio_spi_write(self->spi, ((uint8_t*)bufinfo.buf), 1)) { - mp_raise_OSError(MP_EIO); - } - clocks--; - } - } - - common_hal_busio_spi_unlock(self->spi); -} diff --git a/shared-module/busdevice/SPIDevice.h b/shared-module/busdevice/SPIDevice.h deleted file mode 100644 index ffabf79df..000000000 --- a/shared-module/busdevice/SPIDevice.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_SHARED_MODULE_BUSDEVICE_SPIDEVICE_H -#define MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_SPIDEVICE_H - -#include "py/obj.h" -#include "common-hal/busio/SPI.h" -#include "common-hal/digitalio/DigitalInOut.h" - -typedef struct { - mp_obj_base_t base; - busio_spi_obj_t *spi; - uint32_t baudrate; - uint8_t polarity; - uint8_t phase; - uint8_t extra_clocks; - digitalio_digitalinout_obj_t *chip_select; -} busdevice_spidevice_obj_t; - -#endif // MICROPY_INCLUDED_ATMEL_SAMD_SHARED_MODULE_BUSDEVICE_SPIDEVICE_H diff --git a/shared-module/busdevice/__init__.c b/shared-module/busdevice/__init__.c deleted file mode 100644 index e69de29bb..000000000 -- cgit v1.2.3 From 9adb77a2d0179f89c7402451f6b25be74629ffbd Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sun, 8 Nov 2020 19:28:46 -0600 Subject: set moved true when unhiding tilegrid --- shared-module/displayio/TileGrid.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'shared-module') diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index e3642107f..e8050a539 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -83,10 +83,16 @@ bool common_hal_displayio_tilegrid_get_hidden(displayio_tilegrid_t* self) { void common_hal_displayio_tilegrid_set_hidden(displayio_tilegrid_t* self, bool hidden) { self->hidden = hidden; + if(!hidden){ + self->moved = true; + } } void displayio_tilegrid_set_hidden_by_parent(displayio_tilegrid_t *self, bool hidden) { self->hidden_by_parent = hidden; + if(!hidden){ + self->moved = true; + } } bool displayio_tilegrid_get_previous_area(displayio_tilegrid_t *self, displayio_area_t* area) { -- cgit v1.2.3 From 46c9b28dd880d4e2e2764ab67f64356b175f5f98 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 9 Nov 2020 18:14:31 -0600 Subject: use full_change instead of moved --- shared-module/displayio/TileGrid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index e8050a539..19ea10e55 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -84,14 +84,14 @@ bool common_hal_displayio_tilegrid_get_hidden(displayio_tilegrid_t* self) { void common_hal_displayio_tilegrid_set_hidden(displayio_tilegrid_t* self, bool hidden) { self->hidden = hidden; if(!hidden){ - self->moved = true; + self->full_change = true; } } void displayio_tilegrid_set_hidden_by_parent(displayio_tilegrid_t *self, bool hidden) { self->hidden_by_parent = hidden; if(!hidden){ - self->moved = true; + self->full_change = true; } } -- cgit v1.2.3 From 03b110b44c8e8fed1feb43b7c14b03bbfddf4f2c Mon Sep 17 00:00:00 2001 From: gamblor21 Date: Wed, 11 Nov 2020 09:58:08 -0600 Subject: Add abort check in I2C lock --- shared-module/adafruit_bus_device/I2CDevice.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'shared-module') diff --git a/shared-module/adafruit_bus_device/I2CDevice.c b/shared-module/adafruit_bus_device/I2CDevice.c index d790ff53a..ee4b4fa55 100644 --- a/shared-module/adafruit_bus_device/I2CDevice.c +++ b/shared-module/adafruit_bus_device/I2CDevice.c @@ -29,6 +29,7 @@ #include "py/mperrno.h" #include "py/nlr.h" #include "py/runtime.h" +#include "lib/utils/interrupt_char.h" void common_hal_adafruit_bus_device_i2cdevice_construct(adafruit_bus_device_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address) { self->i2c = i2c; @@ -36,11 +37,15 @@ void common_hal_adafruit_bus_device_i2cdevice_construct(adafruit_bus_device_i2cd } void common_hal_adafruit_bus_device_i2cdevice_lock(adafruit_bus_device_i2cdevice_obj_t *self) { - bool success = false; + bool success = common_hal_busio_i2c_try_lock(self->i2c); + while (!success) { + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + break; + } + success = common_hal_busio_i2c_try_lock(self->i2c); - //RUN_BACKGROUND_TASKS; - //mp_handle_pending(); } } -- cgit v1.2.3 From 8d4296f96430795936a22769da35732e5342b25c Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 10 Nov 2020 18:02:16 -0800 Subject: Add board.DISPLAY to MagTag. Fix luma computation * Initialize the EPaper display on the MagTag at start. * Tweak the display send to take a const buffer. * Correct Luma math * Multiply the blue component, not add. * Add all of the components together before dividing. This reduces the impact of truncated division. --- .../boards/adafruit_magtag_2.9_grayscale/board.c | 122 +++++++++++++++++++++ .../boards/adafruit_magtag_2.9_grayscale/pins.c | 4 + ports/esp32s2/common-hal/displayio/ParallelBus.c | 3 +- shared-bindings/displayio/EPaperDisplay.h | 2 +- shared-bindings/displayio/FourWire.h | 3 +- shared-bindings/displayio/I2CDisplay.h | 3 +- shared-bindings/displayio/ParallelBus.h | 3 +- shared-bindings/displayio/__init__.h | 3 +- shared-module/displayio/ColorConverter.c | 2 +- shared-module/displayio/EPaperDisplay.c | 14 ++- shared-module/displayio/EPaperDisplay.h | 4 +- shared-module/displayio/FourWire.c | 3 +- shared-module/displayio/I2CDisplay.c | 3 +- 13 files changed, 152 insertions(+), 17 deletions(-) (limited to 'shared-module') diff --git a/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/board.c b/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/board.c index 9f708874b..ecd44e423 100644 --- a/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/board.c +++ b/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/board.c @@ -26,7 +26,83 @@ #include "boards/board.h" #include "mpconfigboard.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/displayio/FourWire.h" #include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/board.h" + +#define DELAY 0x80 + +// This is an ILO373 control chip. The display is a 2.9" grayscale EInk. + +const uint8_t display_start_sequence[] = { + 0x01, 5, 0x03, 0x00, 0x2b, 0x2b, 0x13, // power setting + 0x06, 3, 0x17, 0x17, 0x17, // booster soft start + 0x04, DELAY, 200, // power on and wait 200 ms + 0x00, 1, 0x7f, // panel setting + 0x50, 1, 0x97, // CDI setting + 0x30, 1, 0x3c, // PLL set to 50 Hx (M = 7, N = 4) + 0x61, 3, 0x80, 0x01, 0x28, // Resolution + 0x82, DELAY | 1, 0x12, 50, // VCM DC and delay 50ms + + // Look up tables for voltage sequence for pixel transition + // Common voltage + 0x20, 0x2a, + 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, + 0x60, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x13, 0x0a, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + // White to white + 0x21, 0x2a, + 0x40, 0x0a, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x10, 0x14, 0x0a, 0x00, 0x00, 0x01, + 0xa0, 0x13, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + // Black to white + 0x22, 0x2a, + 0x40, 0x0a, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x00, 0x14, 0x0a, 0x00, 0x00, 0x01, + 0x99, 0x0c, 0x01, 0x03, 0x04, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + // White to black + 0x23, 0x2a, + 0x40, 0x0a, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x00, 0x14, 0x0a, 0x00, 0x00, 0x01, + 0x99, 0x0b, 0x04, 0x04, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + // Black to black + 0x24, 0x2a, + 0x80, 0x0a, 0x00, 0x00, 0x00, 0x01, + 0x90, 0x14, 0x14, 0x00, 0x00, 0x01, + 0x20, 0x14, 0x0a, 0x00, 0x00, 0x01, + 0x50, 0x13, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const uint8_t display_stop_sequence[] = { + 0x50, 0x01, 0x17, // CDI Setting + 0x82, 0x01, 0x00, // VCM DC to -0.1V + 0x02, 0x00 // Power off +}; void board_init(void) { // USB @@ -36,6 +112,52 @@ void board_init(void) { // Debug UART common_hal_never_reset_pin(&pin_GPIO43); common_hal_never_reset_pin(&pin_GPIO44); + + busio_spi_obj_t* spi = &displays[0].fourwire_bus.inline_bus; + common_hal_busio_spi_construct(spi, &pin_GPIO36, &pin_GPIO35, NULL); + common_hal_busio_spi_never_reset(spi); + + displayio_fourwire_obj_t* bus = &displays[0].fourwire_bus; + bus->base.type = &displayio_fourwire_type; + common_hal_displayio_fourwire_construct(bus, + spi, + &pin_GPIO7, // EPD_DC Command or data + &pin_GPIO8, // EPD_CS Chip select + &pin_GPIO6, // EPD_RST Reset + 4000000, // Baudrate + 0, // Polarity + 0); // Phase + + displayio_epaperdisplay_obj_t* display = &displays[0].epaper_display; + display->base.type = &displayio_epaperdisplay_type; + common_hal_displayio_epaperdisplay_construct( + display, + bus, + display_start_sequence, sizeof(display_start_sequence), + display_stop_sequence, sizeof(display_stop_sequence), + 296, // width + 128, // height + 160, // ram_width + 296, // ram_height + 0, // colstart + 0, // rowstart + 270, // rotation + NO_COMMAND, // set_column_window_command + NO_COMMAND, // set_row_window_command + NO_COMMAND, // set_current_column_command + NO_COMMAND, // set_current_row_command + 0x10, // write_black_ram_command + false, // black_bits_inverted + 0x13, // write_color_ram_command + false, // color_bits_inverted + 0x000000, // highlight_color + 0x12, // refresh_display_command + 1.0, // refresh_time + &pin_GPIO5, // busy_pin + false, // busy_state + 5.0, // seconds_per_frame + false, // always_toggle_chip_select + true); // grayscale } bool board_requests_safe_mode(void) { diff --git a/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/pins.c b/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/pins.c index 65bc3fb53..40c9e91e4 100644 --- a/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/pins.c +++ b/ports/esp32s2/boards/adafruit_magtag_2.9_grayscale/pins.c @@ -1,5 +1,7 @@ #include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, { MP_ROM_QSTR(MP_QSTR_AD1), MP_ROM_PTR(&pin_GPIO18) }, @@ -37,5 +39,7 @@ STATIC const mp_rom_map_elem_t board_global_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].epaper_display)} }; MP_DEFINE_CONST_DICT(board_module_globals, board_global_dict_table); diff --git a/ports/esp32s2/common-hal/displayio/ParallelBus.c b/ports/esp32s2/common-hal/displayio/ParallelBus.c index 314b72ff7..d0c98f361 100644 --- a/ports/esp32s2/common-hal/displayio/ParallelBus.c +++ b/ports/esp32s2/common-hal/displayio/ParallelBus.c @@ -57,7 +57,8 @@ bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t obj) { return false; } -void common_hal_displayio_parallelbus_send(mp_obj_t obj, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length) { +void common_hal_displayio_parallelbus_send(mp_obj_t obj, display_byte_type_t byte_type, + display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length) { } diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index 352de899a..9a2d93bac 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -39,7 +39,7 @@ extern const mp_obj_type_t displayio_epaperdisplay_type; #define NO_COMMAND 0x100 void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self, - mp_obj_t bus, uint8_t* start_sequence, uint16_t start_sequence_len, uint8_t* stop_sequence, uint16_t stop_sequence_len, + mp_obj_t bus, const uint8_t* start_sequence, uint16_t start_sequence_len, const uint8_t* stop_sequence, uint16_t stop_sequence_len, uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t set_column_window_command, uint16_t set_row_window_command, uint16_t set_current_column_command, uint16_t set_current_row_command, diff --git a/shared-bindings/displayio/FourWire.h b/shared-bindings/displayio/FourWire.h index ac186d2c3..6f6b528e7 100644 --- a/shared-bindings/displayio/FourWire.h +++ b/shared-bindings/displayio/FourWire.h @@ -48,7 +48,8 @@ bool common_hal_displayio_fourwire_bus_free(mp_obj_t self); bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t self); -void common_hal_displayio_fourwire_send(mp_obj_t self, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length); +void common_hal_displayio_fourwire_send(mp_obj_t self, display_byte_type_t byte_type, + display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length); void common_hal_displayio_fourwire_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/I2CDisplay.h b/shared-bindings/displayio/I2CDisplay.h index bae53c491..37520202e 100644 --- a/shared-bindings/displayio/I2CDisplay.h +++ b/shared-bindings/displayio/I2CDisplay.h @@ -44,7 +44,8 @@ bool common_hal_displayio_i2cdisplay_bus_free(mp_obj_t self); bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t self); -void common_hal_displayio_i2cdisplay_send(mp_obj_t self, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length); +void common_hal_displayio_i2cdisplay_send(mp_obj_t self, display_byte_type_t byte_type, + display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length); void common_hal_displayio_i2cdisplay_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/ParallelBus.h b/shared-bindings/displayio/ParallelBus.h index be2aef7d4..1e74e3a0a 100644 --- a/shared-bindings/displayio/ParallelBus.h +++ b/shared-bindings/displayio/ParallelBus.h @@ -46,7 +46,8 @@ bool common_hal_displayio_parallelbus_bus_free(mp_obj_t self); bool common_hal_displayio_parallelbus_begin_transaction(mp_obj_t self); -void common_hal_displayio_parallelbus_send(mp_obj_t self, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length); +void common_hal_displayio_parallelbus_send(mp_obj_t self, display_byte_type_t byte_type, + display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length); void common_hal_displayio_parallelbus_end_transaction(mp_obj_t self); diff --git a/shared-bindings/displayio/__init__.h b/shared-bindings/displayio/__init__.h index a7748d029..4fc666c59 100644 --- a/shared-bindings/displayio/__init__.h +++ b/shared-bindings/displayio/__init__.h @@ -42,7 +42,8 @@ typedef enum { typedef bool (*display_bus_bus_reset)(mp_obj_t bus); typedef bool (*display_bus_bus_free)(mp_obj_t bus); typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); -typedef void (*display_bus_send)(mp_obj_t bus, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length); +typedef void (*display_bus_send)(mp_obj_t bus, display_byte_type_t byte_type, + display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length); typedef void (*display_bus_end_transaction)(mp_obj_t bus); void common_hal_displayio_release_displays(void); diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 03ec99ceb..80558d037 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -55,7 +55,7 @@ uint8_t displayio_colorconverter_compute_luma(uint32_t color_rgb888) { uint32_t r8 = (color_rgb888 >> 16); uint32_t g8 = (color_rgb888 >> 8) & 0xff; uint32_t b8 = color_rgb888 & 0xff; - return (r8 * 19) / 255 + (g8 * 182) / 255 + (b8 + 54) / 255; + return (r8 * 19 + g8 * 182 + b8 * 54) / 255; } uint8_t displayio_colorconverter_compute_chroma(uint32_t color_rgb888) { diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 514b99a13..acca92ac1 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -43,7 +43,8 @@ #include void common_hal_displayio_epaperdisplay_construct(displayio_epaperdisplay_obj_t* self, - mp_obj_t bus, uint8_t* start_sequence, uint16_t start_sequence_len, uint8_t* stop_sequence, uint16_t stop_sequence_len, + mp_obj_t bus, const uint8_t* start_sequence, uint16_t start_sequence_len, + const uint8_t* stop_sequence, uint16_t stop_sequence_len, uint16_t width, uint16_t height, uint16_t ram_width, uint16_t ram_height, int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t set_column_window_command, uint16_t set_row_window_command, @@ -133,14 +134,15 @@ STATIC void wait_for_busy(displayio_epaperdisplay_obj_t* self) { } } -STATIC void send_command_sequence(displayio_epaperdisplay_obj_t* self, bool should_wait_for_busy, uint8_t* sequence, uint32_t sequence_len) { +STATIC void send_command_sequence(displayio_epaperdisplay_obj_t* self, + bool should_wait_for_busy, const uint8_t* sequence, uint32_t sequence_len) { uint32_t i = 0; while (i < sequence_len) { - uint8_t *cmd = sequence + i; + const uint8_t *cmd = sequence + i; uint8_t data_size = *(cmd + 1); bool delay = (data_size & DELAY) != 0; data_size &= ~DELAY; - uint8_t *data = cmd + 2; + const uint8_t *data = cmd + 2; displayio_display_core_begin_transaction(&self->core); self->core.send(self->core.bus, DISPLAY_COMMAND, self->chip_select, cmd, 1); self->core.send(self->core.bus, DISPLAY_DATA, self->chip_select, data, data_size); @@ -375,8 +377,8 @@ void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { void displayio_epaperdisplay_collect_ptrs(displayio_epaperdisplay_obj_t* self) { displayio_display_core_collect_ptrs(&self->core); - gc_collect_ptr(self->start_sequence); - gc_collect_ptr(self->stop_sequence); + gc_collect_ptr((void *) self->start_sequence); + gc_collect_ptr((void *) self->stop_sequence); } bool maybe_refresh_epaperdisplay(void) { diff --git a/shared-module/displayio/EPaperDisplay.h b/shared-module/displayio/EPaperDisplay.h index 4103fe5fc..d0668ff44 100644 --- a/shared-module/displayio/EPaperDisplay.h +++ b/shared-module/displayio/EPaperDisplay.h @@ -38,9 +38,9 @@ typedef struct { displayio_display_core_t core; digitalio_digitalinout_obj_t busy; uint32_t milliseconds_per_frame; - uint8_t* start_sequence; + const uint8_t* start_sequence; uint32_t start_sequence_len; - uint8_t* stop_sequence; + const uint8_t* stop_sequence; uint32_t stop_sequence_len; uint16_t refresh_time; uint16_t set_column_window_command; diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c index 8c56d7ab6..06f8a84e3 100644 --- a/shared-module/displayio/FourWire.c +++ b/shared-module/displayio/FourWire.c @@ -113,7 +113,8 @@ bool common_hal_displayio_fourwire_begin_transaction(mp_obj_t obj) { return true; } -void common_hal_displayio_fourwire_send(mp_obj_t obj, display_byte_type_t data_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length) { +void common_hal_displayio_fourwire_send(mp_obj_t obj, display_byte_type_t data_type, + display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length) { displayio_fourwire_obj_t* self = MP_OBJ_TO_PTR(obj); common_hal_digitalio_digitalinout_set_value(&self->command, data_type == DISPLAY_DATA); if (chip_select == CHIP_SELECT_TOGGLE_EVERY_BYTE) { diff --git a/shared-module/displayio/I2CDisplay.c b/shared-module/displayio/I2CDisplay.c index 5bd03dcd6..cc811e83d 100644 --- a/shared-module/displayio/I2CDisplay.c +++ b/shared-module/displayio/I2CDisplay.c @@ -103,7 +103,8 @@ bool common_hal_displayio_i2cdisplay_begin_transaction(mp_obj_t obj) { return common_hal_busio_i2c_try_lock(self->bus); } -void common_hal_displayio_i2cdisplay_send(mp_obj_t obj, display_byte_type_t data_type, display_chip_select_behavior_t chip_select, uint8_t *data, uint32_t data_length) { +void common_hal_displayio_i2cdisplay_send(mp_obj_t obj, display_byte_type_t data_type, + display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length) { displayio_i2cdisplay_obj_t* self = MP_OBJ_TO_PTR(obj); if (data_type == DISPLAY_COMMAND) { uint8_t command_bytes[2 * data_length]; -- cgit v1.2.3 From 78ccac930fbcb3dddd3a1a79809a2ec371d34c6a Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 11 Nov 2020 16:53:45 -0800 Subject: Add .busy property to EPaperDisplay --- shared-bindings/displayio/EPaperDisplay.c | 18 ++++++++++++++++++ shared-bindings/displayio/EPaperDisplay.h | 1 + shared-module/displayio/EPaperDisplay.c | 5 +++++ 3 files changed, 24 insertions(+) (limited to 'shared-module') diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index 8518e3714..ebff64008 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -245,6 +245,23 @@ const mp_obj_property_t displayio_epaperdisplay_time_to_refresh_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| busy: bool +//| """True when the display is refreshing. This uses the ``busy_pin`` when available or the +//| ``refresh_time`` otherwise.""" +//| +STATIC mp_obj_t displayio_epaperdisplay_obj_get_busy(mp_obj_t self_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); + return mp_obj_new_bool(common_hal_displayio_epaperdisplay_get_busy(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_busy_obj, displayio_epaperdisplay_obj_get_busy); + +const mp_obj_property_t displayio_epaperdisplay_busy_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_busy_obj, + (mp_obj_t)&mp_const_none_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + //| width: int //| """Gets the width of the display in pixels""" //| @@ -301,6 +318,7 @@ STATIC const mp_rom_map_elem_t displayio_epaperdisplay_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_epaperdisplay_width_obj) }, { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_epaperdisplay_height_obj) }, { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_epaperdisplay_bus_obj) }, + { MP_ROM_QSTR(MP_QSTR_busy), MP_ROM_PTR(&displayio_epaperdisplay_busy_obj) }, { MP_ROM_QSTR(MP_QSTR_time_to_refresh), MP_ROM_PTR(&displayio_epaperdisplay_time_to_refresh_obj) }, }; STATIC MP_DEFINE_CONST_DICT(displayio_epaperdisplay_locals_dict, displayio_epaperdisplay_locals_dict_table); diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index 9a2d93bac..f785203a4 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -52,6 +52,7 @@ bool common_hal_displayio_epaperdisplay_show(displayio_epaperdisplay_obj_t* self // Returns time in milliseconds. uint32_t common_hal_displayio_epaperdisplay_get_time_to_refresh(displayio_epaperdisplay_obj_t* self); +bool common_hal_displayio_epaperdisplay_get_busy(displayio_epaperdisplay_obj_t* self); uint16_t common_hal_displayio_epaperdisplay_get_width(displayio_epaperdisplay_obj_t* self); uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_obj_t* self); diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index acca92ac1..1b285b4b1 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -360,6 +360,11 @@ void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t* self) { } } +bool common_hal_displayio_epaperdisplay_get_busy(displayio_epaperdisplay_obj_t* self) { + displayio_epaperdisplay_background(self); + return self->refreshing; +} + void release_epaperdisplay(displayio_epaperdisplay_obj_t* self) { if (self->refreshing) { wait_for_busy(self); -- cgit v1.2.3 From f61f8f999b5eeb8a545f5cea13b30ac5b3aeb04a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 18 Nov 2020 18:06:31 -0600 Subject: EPaperDisplay: add rotation property untested, because I don't want to mess my magtag demo up :) but it builds --- shared-bindings/displayio/EPaperDisplay.c | 24 ++++++++++++++++++++++++ shared-bindings/displayio/EPaperDisplay.h | 2 ++ shared-module/displayio/EPaperDisplay.c | 23 +++++++++++++++++++++++ 3 files changed, 49 insertions(+) (limited to 'shared-module') diff --git a/shared-bindings/displayio/EPaperDisplay.c b/shared-bindings/displayio/EPaperDisplay.c index ebff64008..4f5c47aca 100644 --- a/shared-bindings/displayio/EPaperDisplay.c +++ b/shared-bindings/displayio/EPaperDisplay.c @@ -294,6 +294,29 @@ const mp_obj_property_t displayio_epaperdisplay_height_obj = { (mp_obj_t)&mp_const_none_obj}, }; +//| rotation: int +//| """The rotation of the display as an int in degrees.""" +//| +STATIC mp_obj_t displayio_epaperdisplay_obj_get_rotation(mp_obj_t self_in) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_displayio_epaperdisplay_get_rotation(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(displayio_epaperdisplay_get_rotation_obj, displayio_epaperdisplay_obj_get_rotation); +STATIC mp_obj_t displayio_epaperdisplay_obj_set_rotation(mp_obj_t self_in, mp_obj_t value) { + displayio_epaperdisplay_obj_t *self = native_display(self_in); + common_hal_displayio_epaperdisplay_set_rotation(self, mp_obj_get_int(value)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(displayio_epaperdisplay_set_rotation_obj, displayio_epaperdisplay_obj_set_rotation); + + +const mp_obj_property_t displayio_epaperdisplay_rotation_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&displayio_epaperdisplay_get_rotation_obj, + (mp_obj_t)&displayio_epaperdisplay_set_rotation_obj, + (mp_obj_t)&mp_const_none_obj}, +}; + //| bus: _DisplayBus //| """The bus being used by the display""" //| @@ -317,6 +340,7 @@ STATIC const mp_rom_map_elem_t displayio_epaperdisplay_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&displayio_epaperdisplay_width_obj) }, { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&displayio_epaperdisplay_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&displayio_epaperdisplay_rotation_obj) }, { MP_ROM_QSTR(MP_QSTR_bus), MP_ROM_PTR(&displayio_epaperdisplay_bus_obj) }, { MP_ROM_QSTR(MP_QSTR_busy), MP_ROM_PTR(&displayio_epaperdisplay_busy_obj) }, { MP_ROM_QSTR(MP_QSTR_time_to_refresh), MP_ROM_PTR(&displayio_epaperdisplay_time_to_refresh_obj) }, diff --git a/shared-bindings/displayio/EPaperDisplay.h b/shared-bindings/displayio/EPaperDisplay.h index f785203a4..14d4f6aa9 100644 --- a/shared-bindings/displayio/EPaperDisplay.h +++ b/shared-bindings/displayio/EPaperDisplay.h @@ -56,6 +56,8 @@ bool common_hal_displayio_epaperdisplay_get_busy(displayio_epaperdisplay_obj_t* uint16_t common_hal_displayio_epaperdisplay_get_width(displayio_epaperdisplay_obj_t* self); uint16_t common_hal_displayio_epaperdisplay_get_height(displayio_epaperdisplay_obj_t* self); +uint16_t common_hal_displayio_epaperdisplay_get_rotation(displayio_epaperdisplay_obj_t* self); +void common_hal_displayio_epaperdisplay_set_rotation(displayio_epaperdisplay_obj_t* self, int rotation); mp_obj_t common_hal_displayio_epaperdisplay_get_bus(displayio_epaperdisplay_obj_t* self); diff --git a/shared-module/displayio/EPaperDisplay.c b/shared-module/displayio/EPaperDisplay.c index 1b285b4b1..3fb37ff21 100644 --- a/shared-module/displayio/EPaperDisplay.c +++ b/shared-module/displayio/EPaperDisplay.c @@ -198,6 +198,29 @@ mp_obj_t common_hal_displayio_epaperdisplay_get_bus(displayio_epaperdisplay_obj_ return self->core.bus; } +void common_hal_displayio_epaperdisplay_set_rotation(displayio_epaperdisplay_obj_t* self, int rotation){ + bool transposed = (self->core.rotation == 90 || self->core.rotation == 270); + bool will_transposed = (rotation == 90 || rotation == 270); + if(transposed != will_transposed) { + int tmp = self->core.width; + self->core.width = self->core.height; + self->core.height = tmp; + } + displayio_display_core_set_rotation(&self->core, rotation); + if (self == &displays[0].epaper_display) { + supervisor_stop_terminal(); + supervisor_start_terminal(self->core.width, self->core.height); + } + if (self->core.current_group != NULL) { + displayio_group_update_transform(self->core.current_group, &self->core.transform); + } +} + +uint16_t common_hal_displayio_epaperdisplay_get_rotation(displayio_epaperdisplay_obj_t* self){ + return self->core.rotation; +} + + bool displayio_epaperdisplay_refresh_area(displayio_epaperdisplay_obj_t* self, const displayio_area_t* area) { uint16_t buffer_size = 128; // In uint32_ts -- cgit v1.2.3 From 2463a6d6ac3fb53fa471c77bc585c8ef350d2b96 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 18 Nov 2020 16:28:21 -0800 Subject: Fix Palette grayscale for EInk. It needs to do the bitmasking that was only added to ColorConverter in #3611 --- shared-module/displayio/Palette.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/Palette.c b/shared-module/displayio/Palette.c index facb1fa73..ba5ff665c 100644 --- a/shared-module/displayio/Palette.c +++ b/shared-module/displayio/Palette.c @@ -83,7 +83,8 @@ bool displayio_palette_get_color(displayio_palette_t *self, const _displayio_col uint8_t pixel_hue = self->colors[palette_index].hue; displayio_colorconverter_compute_tricolor(colorspace, pixel_hue, luma, color); } else if (colorspace->grayscale) { - *color = self->colors[palette_index].luma >> (8 - colorspace->depth); + size_t bitmask = (1 << colorspace->depth) - 1; + *color = (self->colors[palette_index].luma >> colorspace->grayscale_bit) & bitmask; } else { uint16_t packed = self->colors[palette_index].rgb565; if (colorspace->reverse_bytes_in_word) { -- cgit v1.2.3 From fc344bc818f8172ff36ee646459d7d060a51289a Mon Sep 17 00:00:00 2001 From: James Bowman Date: Tue, 24 Nov 2020 17:26:39 -0800 Subject: Fix opcode typo in VertexFormat() --- shared-module/_eve/__init__.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'shared-module') diff --git a/shared-module/_eve/__init__.c b/shared-module/_eve/__init__.c index 0f1e12d9f..d95c777dc 100644 --- a/shared-module/_eve/__init__.c +++ b/shared-module/_eve/__init__.c @@ -70,8 +70,8 @@ void common_hal__eve_Vertex2f(common_hal__eve_t *eve, mp_float_t x, mp_float_t y void common_hal__eve_VertexFormat(common_hal__eve_t *eve, uint32_t frac) { - C4(eve, ((27 << 24) | ((frac & 7)))); - eve->vscale = 1 << eve->vscale; + C4(eve, ((39 << 24) | ((frac & 7)))); + eve->vscale = 1 << frac; } -- cgit v1.2.3 From c7404a3ff89c738c002ec63448a58d56330dfcc3 Mon Sep 17 00:00:00 2001 From: Christian Walther Date: Sun, 11 Oct 2020 14:59:33 +0200 Subject: Add movable allocation system. This allows calls to `allocate_memory()` while the VM is running, it will then allocate from the GC heap (unless there is a suitable hole among the supervisor allocations), and when the VM exits and the GC heap is freed, the allocation will be moved to the bottom of the former GC heap and transformed into a proper supervisor allocation. Existing movable allocations will also be moved to defragment the supervisor heap and ensure that the next VM run gets as much memory as possible for the GC heap. By itself this breaks terminalio because it violates the assumption that supervisor_display_move_memory() still has access to an undisturbed heap to copy the tilegrid from. It will work in many cases, but if you're unlucky you will get garbled terminal contents after exiting from the vm run that created the display. This will be fixed in the following commit, which is separate to simplify review. --- main.c | 13 +- ports/atmel-samd/supervisor/port.c | 4 +- ports/cxd56/supervisor/port.c | 8 +- ports/esp32s2/supervisor/port.c | 8 +- ports/litex/supervisor/port.c | 4 +- ports/mimxrt10xx/supervisor/port.c | 7 +- ports/nrf/supervisor/port.c | 4 +- ports/stm/supervisor/port.c | 4 +- py/circuitpy_mpconfig.h | 4 + shared-module/rgbmatrix/RGBMatrix.c | 2 +- .../sharpdisplay/SharpMemoryFramebuffer.c | 2 +- shared-module/usb_midi/__init__.c | 2 +- supervisor/memory.h | 26 +- supervisor/port.h | 5 +- supervisor/shared/display.c | 4 +- supervisor/shared/external_flash/external_flash.c | 2 +- supervisor/shared/memory.c | 277 +++++++++++++++------ supervisor/shared/stack.c | 38 ++- supervisor/shared/stack.h | 6 +- 19 files changed, 283 insertions(+), 137 deletions(-) (limited to 'shared-module') diff --git a/main.c b/main.c index 80b163f60..1389f524b 100755 --- a/main.c +++ b/main.c @@ -123,15 +123,15 @@ void start_mp(supervisor_allocation* heap) { // to recover from limit hit. (Limit is measured in bytes.) mp_stack_ctrl_init(); - if (stack_alloc != NULL) { - mp_stack_set_limit(stack_alloc->length - 1024); + if (stack_get_bottom() != NULL) { + mp_stack_set_limit(stack_get_length() - 1024); } #if MICROPY_MAX_STACK_USAGE // _ezero (same as _ebss) is an int, so start 4 bytes above it. - if (stack_alloc != NULL) { - mp_stack_set_bottom(stack_alloc->ptr); + if (stack_get_bottom() != NULL) { + mp_stack_set_bottom(stack_get_bottom()); mp_stack_fill_with_sentinel(); } #endif @@ -148,7 +148,7 @@ void start_mp(supervisor_allocation* heap) { #endif #if MICROPY_ENABLE_GC - gc_init(heap->ptr, heap->ptr + heap->length / 4); + gc_init(heap->ptr, heap->ptr + get_allocation_length(heap) / 4); #endif mp_init(); mp_obj_list_init(mp_sys_path, 0); @@ -451,9 +451,6 @@ int __attribute__((used)) main(void) { // initialise the cpu and peripherals safe_mode_t safe_mode = port_init(); - // Init memory after the port in case the port needs to set aside memory. - memory_init(); - // Turn on LEDs init_status_leds(); rgb_led_status_init(); diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index d65d09825..fc1d1198e 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -390,8 +390,8 @@ void reset_cpu(void) { reset(); } -supervisor_allocation* port_fixed_stack(void) { - return NULL; +bool port_has_fixed_stack(void) { + return false; } uint32_t *port_stack_get_limit(void) { diff --git a/ports/cxd56/supervisor/port.c b/ports/cxd56/supervisor/port.c index 086c2d198..d69f35779 100644 --- a/ports/cxd56/supervisor/port.c +++ b/ports/cxd56/supervisor/port.c @@ -98,12 +98,8 @@ void reset_to_bootloader(void) { } } -supervisor_allocation _fixed_stack; - -supervisor_allocation* port_fixed_stack(void) { - _fixed_stack.ptr = port_stack_get_limit(); - _fixed_stack.length = (port_stack_get_top() - port_stack_get_limit()) * sizeof(uint32_t); - return &_fixed_stack; +bool port_has_fixed_stack(void) { + return true; } uint32_t *port_stack_get_limit(void) { diff --git a/ports/esp32s2/supervisor/port.c b/ports/esp32s2/supervisor/port.c index aff7dbda4..264bdee97 100644 --- a/ports/esp32s2/supervisor/port.c +++ b/ports/esp32s2/supervisor/port.c @@ -193,12 +193,8 @@ uint32_t *port_stack_get_top(void) { return port_stack_get_limit() + ESP_TASK_MAIN_STACK / (sizeof(uint32_t) / sizeof(StackType_t)); } -supervisor_allocation _fixed_stack; - -supervisor_allocation* port_fixed_stack(void) { - _fixed_stack.ptr = port_stack_get_limit(); - _fixed_stack.length = (port_stack_get_top() - port_stack_get_limit()) * sizeof(uint32_t); - return &_fixed_stack; +bool port_has_fixed_stack(void) { + return true; } // Place the word to save just after our BSS section that gets blanked. diff --git a/ports/litex/supervisor/port.c b/ports/litex/supervisor/port.c index 02617b9af..f5c362ea6 100644 --- a/ports/litex/supervisor/port.c +++ b/ports/litex/supervisor/port.c @@ -98,8 +98,8 @@ void reset_cpu(void) { for(;;) {} } -supervisor_allocation* port_fixed_stack(void) { - return NULL; +bool port_has_fixed_stack(void) { + return false; } uint32_t *port_heap_get_bottom(void) { diff --git a/ports/mimxrt10xx/supervisor/port.c b/ports/mimxrt10xx/supervisor/port.c index e3fef373f..1be2b1039 100644 --- a/ports/mimxrt10xx/supervisor/port.c +++ b/ports/mimxrt10xx/supervisor/port.c @@ -334,11 +334,8 @@ uint32_t *port_stack_get_top(void) { return &_ld_stack_top; } -supervisor_allocation _fixed_stack; -supervisor_allocation* port_fixed_stack(void) { - _fixed_stack.ptr = port_stack_get_limit(); - _fixed_stack.length = (port_stack_get_top() - port_stack_get_limit()) * sizeof(uint32_t); - return &_fixed_stack; +bool port_has_fixed_stack(void) { + return true; } uint32_t *port_heap_get_bottom(void) { diff --git a/ports/nrf/supervisor/port.c b/ports/nrf/supervisor/port.c index 493de43e0..5f1c9f1ba 100644 --- a/ports/nrf/supervisor/port.c +++ b/ports/nrf/supervisor/port.c @@ -251,8 +251,8 @@ uint32_t *port_heap_get_top(void) { return port_stack_get_top(); } -supervisor_allocation* port_fixed_stack(void) { - return NULL; +bool port_has_fixed_stack(void) { + return false; } uint32_t *port_stack_get_limit(void) { diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index a8aab00ff..dba1cf21e 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -267,8 +267,8 @@ uint32_t *port_heap_get_top(void) { return &_ld_heap_end; } -supervisor_allocation* port_fixed_stack(void) { - return NULL; +bool port_has_fixed_stack(void) { + return false; } uint32_t *port_stack_get_limit(void) { diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 28fd4095c..28fd6e9b0 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -858,6 +858,9 @@ extern const struct _mp_obj_module_t wifi_module; #include "supervisor/flash_root_pointers.h" +// From supervisor/memory.c +struct _supervisor_allocation_node; + #define CIRCUITPY_COMMON_ROOT_POINTERS \ const char *readline_hist[8]; \ vstr_t *repl_line; \ @@ -869,6 +872,7 @@ extern const struct _mp_obj_module_t wifi_module; FLASH_ROOT_POINTERS \ MEMORYMONITOR_ROOT_POINTERS \ NETWORK_ROOT_POINTERS \ + struct _supervisor_allocation_node* first_embedded_allocation; \ void supervisor_run_background_tasks_if_tick(void); #define RUN_BACKGROUND_TASKS (supervisor_run_background_tasks_if_tick()) diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index 94c3eda27..1f144aedb 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -220,7 +220,7 @@ 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); + supervisor_allocation *allocation = allocate_memory(align32_size(sz), false, false); return allocation ? allocation->ptr : NULL; } } diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c index b199e98d6..aefb6b18d 100644 --- a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c @@ -40,7 +40,7 @@ #define SHARPMEM_BIT_VCOM_LSB (0x40) static void *hybrid_alloc(size_t sz) { - supervisor_allocation *allocation = allocate_memory(align32_size(sz), false); + supervisor_allocation *allocation = allocate_memory(align32_size(sz), false, false); if (allocation) { memset(allocation->ptr, 0, sz); return allocation->ptr; diff --git a/shared-module/usb_midi/__init__.c b/shared-module/usb_midi/__init__.c index 73a314b99..5afdd1821 100644 --- a/shared-module/usb_midi/__init__.c +++ b/shared-module/usb_midi/__init__.c @@ -45,7 +45,7 @@ void usb_midi_init(void) { uint16_t portout_size = align32_size(sizeof(usb_midi_portout_obj_t)); // For each embedded MIDI Jack in the descriptor we create a Port - usb_midi_allocation = allocate_memory(tuple_size + portin_size + portout_size, false); + usb_midi_allocation = allocate_memory(tuple_size + portin_size + portout_size, false, false); mp_obj_tuple_t *ports = (mp_obj_tuple_t *) usb_midi_allocation->ptr; ports->base.type = &mp_type_tuple; diff --git a/supervisor/memory.h b/supervisor/memory.h index f4359ca46..4307e3f21 100755 --- a/supervisor/memory.h +++ b/supervisor/memory.h @@ -33,23 +33,36 @@ #include #include +#include typedef struct { uint32_t* ptr; - uint32_t length; // in bytes } supervisor_allocation; -void memory_init(void); void free_memory(supervisor_allocation* allocation); + +// Find the allocation with the given ptr, NULL if not found. When called from the context of a +// supervisor_move_memory() callback, finds the allocation that had that ptr *before* the move, but +// the returned allocation already contains the ptr after the move. +// When called with NULL, may return either NULL or an unused allocation whose ptr is NULL (this is +// a feature used internally in allocate_memory to save code size). Passing the return value to +// free_memory() is a permissible no-op in either case. supervisor_allocation* allocation_from_ptr(void *ptr); + supervisor_allocation* allocate_remaining_memory(void); // Allocate a piece of a given length in bytes. If high_address is true then it should be allocated // at a lower address from the top of the stack. Otherwise, addresses will increase starting after -// statically allocated memory. -supervisor_allocation* allocate_memory(uint32_t length, bool high_address); +// statically allocated memory. If movable is false, memory will be taken from outside the GC heap +// and will stay stationary until freed. While the VM is running, this will fail unless a previous +// allocation of exactly matching length has recently been freed. If movable is true, memory will be +// taken from either outside or inside the GC heap, and when the VM exits, will be moved outside. +// The ptr of the returned supervisor_allocation will change at that point. If you need to be +// notified of that, add your own callback function at the designated place near the end of +// supervisor_move_memory(). +supervisor_allocation* allocate_memory(uint32_t length, bool high_address, bool movable); static inline uint16_t align32_size(uint16_t size) { if (size % 4 != 0) { @@ -58,7 +71,10 @@ static inline uint16_t align32_size(uint16_t size) { return size; } -// Called after the heap is freed in case the supervisor wants to save some values. +size_t get_allocation_length(supervisor_allocation* allocation); + +// Called after the GC heap is freed, transfers movable allocations from the GC heap to the +// supervisor heap and compacts the supervisor heap. void supervisor_move_memory(void); #endif // MICROPY_INCLUDED_SUPERVISOR_MEMORY_H diff --git a/supervisor/port.h b/supervisor/port.h index f5b3c15d1..5bc06bc4e 100644 --- a/supervisor/port.h +++ b/supervisor/port.h @@ -61,7 +61,8 @@ uint32_t *port_stack_get_limit(void); // Get stack top address uint32_t *port_stack_get_top(void); -supervisor_allocation* port_fixed_stack(void); +// True if stack is not located inside heap (at the top) +bool port_has_fixed_stack(void); // Get heap bottom address uint32_t *port_heap_get_bottom(void); @@ -69,8 +70,6 @@ uint32_t *port_heap_get_bottom(void); // Get heap top address uint32_t *port_heap_get_top(void); -supervisor_allocation* port_fixed_heap(void); - // Save and retrieve a word from memory that is preserved over reset. Used for safe mode. void port_set_saved_word(uint32_t); uint32_t port_get_saved_word(void); diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index a9ae25884..de45e2672 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -82,7 +82,7 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) { uint16_t total_tiles = width_in_tiles * height_in_tiles; // First try to allocate outside the heap. This will fail when the VM is running. - tilegrid_tiles = allocate_memory(align32_size(total_tiles), false); + tilegrid_tiles = allocate_memory(align32_size(total_tiles), false, false); uint8_t* tiles; if (tilegrid_tiles == NULL) { tiles = m_malloc(total_tiles, true); @@ -133,7 +133,7 @@ void supervisor_display_move_memory(void) { grid->tiles == MP_STATE_VM(terminal_tilegrid_tiles)) { uint16_t total_tiles = grid->width_in_tiles * grid->height_in_tiles; - tilegrid_tiles = allocate_memory(align32_size(total_tiles), false); + tilegrid_tiles = allocate_memory(align32_size(total_tiles), false, false); if (tilegrid_tiles != NULL) { memcpy(tilegrid_tiles->ptr, grid->tiles, total_tiles); grid->tiles = (uint8_t*) tilegrid_tiles->ptr; diff --git a/supervisor/shared/external_flash/external_flash.c b/supervisor/shared/external_flash/external_flash.c index 5bde7fd48..e2d767235 100644 --- a/supervisor/shared/external_flash/external_flash.c +++ b/supervisor/shared/external_flash/external_flash.c @@ -338,7 +338,7 @@ static bool allocate_ram_cache(void) { uint32_t table_size = blocks_per_sector * pages_per_block * sizeof(uint32_t); // Attempt to allocate outside the heap first. - supervisor_cache = allocate_memory(table_size + SPI_FLASH_ERASE_SIZE, false); + supervisor_cache = allocate_memory(table_size + SPI_FLASH_ERASE_SIZE, false, false); if (supervisor_cache != NULL) { MP_STATE_VM(flash_ram_cache) = (uint8_t **) supervisor_cache->ptr; uint8_t* page_start = (uint8_t *) supervisor_cache->ptr + table_size; diff --git a/supervisor/shared/memory.c b/supervisor/shared/memory.c index 0f96ae273..2be3b42d6 100755 --- a/supervisor/shared/memory.c +++ b/supervisor/shared/memory.c @@ -27,78 +27,81 @@ #include "supervisor/memory.h" #include "supervisor/port.h" -#include +#include +#include "py/gc.h" #include "supervisor/shared/display.h" #define CIRCUITPY_SUPERVISOR_ALLOC_COUNT (12) -// Using a zero length to mark an unused allocation makes the code a bit shorter (but makes it -// impossible to support zero-length allocations). -#define FREE 0 - // The lowest two bits of a valid length are always zero, so we can use them to mark an allocation -// as freed by the client but not yet reclaimed into the FREE middle. +// as a hole (freed by the client but not yet reclaimed into the free middle) and as movable. +#define FLAGS 3 #define HOLE 1 +#define MOVABLE 2 static supervisor_allocation allocations[CIRCUITPY_SUPERVISOR_ALLOC_COUNT]; -// We use uint32_t* to ensure word (4 byte) alignment. -uint32_t* low_address; -uint32_t* high_address; +supervisor_allocation* old_allocations; -void memory_init(void) { - low_address = port_heap_get_bottom(); - high_address = port_heap_get_top(); -} +typedef struct _supervisor_allocation_node { + struct _supervisor_allocation_node* next; + size_t length; + // We use uint32_t to ensure word (4 byte) alignment. + uint32_t data[]; +} supervisor_allocation_node; + +supervisor_allocation_node* low_head; +supervisor_allocation_node* high_head; + +// Intermediate (void*) is to suppress -Wcast-align warning. Alignment will always be correct +// because this only reverses how (alloc)->ptr was obtained as &(node->data[0]). +#define ALLOCATION_NODE(alloc) ((supervisor_allocation_node*)(void*)((char*)((alloc)->ptr) - sizeof(supervisor_allocation_node))) void free_memory(supervisor_allocation* allocation) { - if (allocation == NULL) { + if (allocation == NULL || allocation->ptr == NULL) { return; } - int32_t index = 0; - bool found = false; - for (index = 0; index < CIRCUITPY_SUPERVISOR_ALLOC_COUNT; index++) { - found = allocation == &allocations[index]; - if (found) { - break; - } + supervisor_allocation_node* node = ALLOCATION_NODE(allocation); + if (node == low_head) { + do { + low_head = low_head->next; + } while (low_head != NULL && (low_head->length & HOLE)); } - if (!found) { - // Bad! - // TODO(tannewt): Add a way to escape into safe mode on error. + else if (node == high_head) { + do { + high_head = high_head->next; + } while (high_head != NULL && (high_head->length & HOLE)); } - if (allocation->ptr == high_address) { - high_address += allocation->length / 4; - allocation->length = FREE; - for (index++; index < CIRCUITPY_SUPERVISOR_ALLOC_COUNT; index++) { - if (!(allocations[index].length & HOLE)) { - break; - } - // Division automatically shifts out the HOLE bit. - high_address += allocations[index].length / 4; - allocations[index].length = FREE; - } - } else if (allocation->ptr + allocation->length / 4 == low_address) { - low_address = allocation->ptr; - allocation->length = FREE; - for (index--; index >= 0; index--) { - if (!(allocations[index].length & HOLE)) { - break; + else { + // Check if it's in the list of embedded allocations. + supervisor_allocation_node** emb = &MP_STATE_VM(first_embedded_allocation); + while (*emb != NULL) { + if (*emb == node) { + // Found, remove it from the list. + *emb = node->next; + m_free(node +#if MICROPY_MALLOC_USES_ALLOCATED_SIZE + , sizeof(supervisor_allocation_node) + (node->length & ~FLAGS) +#endif + ); + goto done; } - low_address -= allocations[index].length / 4; - allocations[index].length = FREE; + emb = &((*emb)->next); } - } else { - // Freed memory isn't in the middle so skip updating bounds. The memory will be added to the - // middle when the memory to the inside is freed. We still need its length, but setting - // only the lowest bit is nondestructive. - allocation->length |= HOLE; + // Else it must be within the low or high ranges and becomes a hole. + node->length = ((node->length & ~FLAGS) | HOLE); } +done: + allocation->ptr = NULL; } supervisor_allocation* allocation_from_ptr(void *ptr) { + // When called from the context of supervisor_move_memory() (old_allocations != NULL), search + // by old pointer to give clients a way of mapping from old to new pointer. But not if + // ptr == NULL, then the caller wants an allocation whose current ptr is NULL. + supervisor_allocation* list = (old_allocations && ptr) ? old_allocations : &allocations[0]; for (size_t index = 0; index < CIRCUITPY_SUPERVISOR_ALLOC_COUNT; index++) { - if (allocations[index].ptr == ptr) { + if (list[index].ptr == ptr) { return &allocations[index]; } } @@ -106,50 +109,172 @@ supervisor_allocation* allocation_from_ptr(void *ptr) { } supervisor_allocation* allocate_remaining_memory(void) { - if (low_address == high_address) { - return NULL; + uint32_t* low_address = low_head ? low_head->data + low_head->length / 4 : port_heap_get_bottom(); + uint32_t* high_address = high_head ? (uint32_t*)high_head : port_heap_get_top(); + return allocate_memory((high_address - low_address) * 4 - sizeof(supervisor_allocation_node), false, false); +} + +static supervisor_allocation_node* find_hole(supervisor_allocation_node* node, size_t length) { + for (; node != NULL; node = node->next) { + if (node->length == (length | HOLE)) { + break; + } } - return allocate_memory((high_address - low_address) * 4, false); + return node; } -supervisor_allocation* allocate_memory(uint32_t length, bool high) { +static supervisor_allocation_node* allocate_memory_node(uint32_t length, bool high, bool movable) { + // supervisor_move_memory() currently does not support movable allocations on the high side, it + // must be extended first if this is ever needed. + assert(!(high && movable)); if (length == 0 || length % 4 != 0) { return NULL; } - uint8_t index = 0; - int8_t direction = 1; - if (high) { - index = CIRCUITPY_SUPERVISOR_ALLOC_COUNT - 1; - direction = -1; - } - supervisor_allocation* alloc; - for (; index < CIRCUITPY_SUPERVISOR_ALLOC_COUNT; index += direction) { - alloc = &allocations[index]; - if (alloc->length == FREE && (high_address - low_address) * 4 >= (int32_t) length) { - break; + // 1. Matching hole on the requested side? + supervisor_allocation_node* node = find_hole(high ? high_head : low_head, length); + if (!node) { + // 2. Enough free space in the middle? + uint32_t* low_address = low_head ? low_head->data + low_head->length / 4 : port_heap_get_bottom(); + uint32_t* high_address = high_head ? (uint32_t*)high_head : port_heap_get_top(); + if ((high_address - low_address) * 4 >= (int32_t)(sizeof(supervisor_allocation_node) + length)) { + if (high) { + high_address -= (sizeof(supervisor_allocation_node) + length) / 4; + node = (supervisor_allocation_node*)high_address; + node->next = high_head; + high_head = node; + } + else { + node = (supervisor_allocation_node*)low_address; + node->next = low_head; + low_head = node; + } } - // If a hole matches in length exactly, we can reuse it. - if (alloc->length == (length | HOLE)) { - alloc->length = length; - return alloc; + else { + // 3. Matching hole on the other side? + node = find_hole(high ? low_head : high_head, length); + if (!node) { + // 4. GC allocation? + if (movable && gc_alloc_possible()) { + node = m_malloc_maybe(sizeof(supervisor_allocation_node) + length, true); + if (node) { + node->next = MP_STATE_VM(first_embedded_allocation); + MP_STATE_VM(first_embedded_allocation) = node; + } + } + if (!node) { + // 5. Give up. + return NULL; + } + } } } - if (index >= CIRCUITPY_SUPERVISOR_ALLOC_COUNT) { + node->length = length; + if (movable) { + node->length |= MOVABLE; + } + return node; +} + +supervisor_allocation* allocate_memory(uint32_t length, bool high, bool movable) { + supervisor_allocation_node* node = allocate_memory_node(length, high, movable); + if (!node) { return NULL; } - if (high) { - high_address -= length / 4; - alloc->ptr = high_address; - } else { - alloc->ptr = low_address; - low_address += length / 4; + // Find the first free allocation. + supervisor_allocation* alloc = allocation_from_ptr(NULL); + if (!alloc) { + // We should free node again to avoid leaking, but something is wrong anyway if clients try + // to make more allocations than available, so don't bother. + return NULL; } - alloc->length = length; + alloc->ptr = &(node->data[0]); return alloc; } +size_t get_allocation_length(supervisor_allocation* allocation) { + return ALLOCATION_NODE(allocation)->length & ~FLAGS; +} + void supervisor_move_memory(void) { + // This must be called exactly after freeing the heap, so that the embedded allocations, if any, + // are now in the free region. + assert(MP_STATE_VM(first_embedded_allocation) == NULL || (low_head < MP_STATE_VM(first_embedded_allocation) && MP_STATE_VM(first_embedded_allocation) < high_head)); + + // Save the old pointers for allocation_from_ptr(). + supervisor_allocation old_allocations_array[CIRCUITPY_SUPERVISOR_ALLOC_COUNT]; + memcpy(old_allocations_array, allocations, sizeof(allocations)); + + // Compact the low side. Traverse the list repeatedly, finding movable allocations preceded by a + // hole and swapping them, until no more are found. This is not the most runtime-efficient way, + // but probably the shortest and simplest code. + bool acted; + do { + acted = false; + supervisor_allocation_node** nodep = &low_head; + while (*nodep != NULL && (*nodep)->next != NULL) { + if (((*nodep)->length & MOVABLE) && ((*nodep)->next->length & HOLE)) { + supervisor_allocation_node* oldnode = *nodep; + supervisor_allocation_node* start = oldnode->next; + supervisor_allocation* alloc = allocation_from_ptr(&(oldnode->data[0])); + assert(alloc != NULL); + alloc->ptr = &(start->data[0]); + oldnode->next = start->next; + size_t holelength = start->length; + size_t size = sizeof(supervisor_allocation_node) + (oldnode->length & ~FLAGS); + memmove(start, oldnode, size); + supervisor_allocation_node* newhole = (supervisor_allocation_node*)(void*)((char*)start + size); + newhole->next = start; + newhole->length = holelength; + *nodep = newhole; + acted = true; + } + nodep = &((*nodep)->next); + } + } while (acted); + // Any holes bubbled to the top can be absorbed into the free middle. + while (low_head != NULL && (low_head->length & HOLE)) { + low_head = low_head->next; + }; + + // Don't bother compacting the high side, there are no movable allocations and no holes there in + // current usage. + + // Promote the embedded allocations to top-level ones, compacting them at the beginning of the + // now free region (or possibly in matching holes). + // The linked list is unordered, but allocations must be processed in order to avoid risking + // overwriting each other. To that end, repeatedly find the lowest element of the list, remove + // it from the list, and process it. This ad-hoc selection sort results in substantially shorter + // code than using the qsort() function from the C library. + while (MP_STATE_VM(first_embedded_allocation)) { + // First element is first candidate. + supervisor_allocation_node** pminnode = &MP_STATE_VM(first_embedded_allocation); + // Iterate from second element (if any) on. + for (supervisor_allocation_node** pnode = &(MP_STATE_VM(first_embedded_allocation)->next); *pnode != NULL; pnode = &(*pnode)->next) { + if (*pnode < *pminnode) { + pminnode = pnode; + } + } + // Remove from list. + supervisor_allocation_node* node = *pminnode; + *pminnode = node->next; + // Process. + size_t length = (node->length & ~FLAGS); + supervisor_allocation* alloc = allocation_from_ptr(&(node->data[0])); + assert(alloc != NULL); + // This may overwrite the header of node if it happened to be there already, but not the + // data. + supervisor_allocation_node* new_node = allocate_memory_node(length, false, true); + // There must be enough free space. + assert(new_node != NULL); + memmove(&(new_node->data[0]), &(node->data[0]), length); + alloc->ptr = &(new_node->data[0]); + } + + // Notify clients that their movable allocations may have moved. + old_allocations = &old_allocations_array[0]; #if CIRCUITPY_DISPLAYIO supervisor_display_move_memory(); #endif + // Add calls to further clients here. + old_allocations = NULL; } diff --git a/supervisor/shared/stack.c b/supervisor/shared/stack.c index e7aa956b0..afea20401 100755 --- a/supervisor/shared/stack.c +++ b/supervisor/shared/stack.c @@ -34,36 +34,42 @@ extern uint32_t _estack; +// Requested size. static uint32_t next_stack_size = CIRCUITPY_DEFAULT_STACK_SIZE; static uint32_t current_stack_size = 0; -supervisor_allocation* stack_alloc = NULL; +// Actual location and size, may be larger than requested. +static uint32_t* stack_limit = NULL; +static size_t stack_length = 0; #define EXCEPTION_STACK_SIZE 1024 void allocate_stack(void) { - if (port_fixed_stack() != NULL) { - stack_alloc = port_fixed_stack(); - current_stack_size = stack_alloc->length; + if (port_has_fixed_stack()) { + stack_limit = port_stack_get_limit(); + stack_length = (port_stack_get_top() - stack_limit)*sizeof(uint32_t); + current_stack_size = stack_length; } else { mp_uint_t regs[10]; mp_uint_t sp = cpu_get_regs_and_sp(regs); mp_uint_t c_size = (uint32_t) port_stack_get_top() - sp; - stack_alloc = allocate_memory(c_size + next_stack_size + EXCEPTION_STACK_SIZE, true); + supervisor_allocation* stack_alloc = allocate_memory(c_size + next_stack_size + EXCEPTION_STACK_SIZE, true, false); if (stack_alloc == NULL) { - stack_alloc = allocate_memory(c_size + CIRCUITPY_DEFAULT_STACK_SIZE + EXCEPTION_STACK_SIZE, true); + stack_alloc = allocate_memory(c_size + CIRCUITPY_DEFAULT_STACK_SIZE + EXCEPTION_STACK_SIZE, true, false); current_stack_size = CIRCUITPY_DEFAULT_STACK_SIZE; } else { current_stack_size = next_stack_size; } + stack_limit = stack_alloc->ptr; + stack_length = get_allocation_length(stack_alloc); } - *stack_alloc->ptr = STACK_CANARY_VALUE; + *stack_limit = STACK_CANARY_VALUE; } inline bool stack_ok(void) { - return stack_alloc == NULL || *stack_alloc->ptr == STACK_CANARY_VALUE; + return stack_limit == NULL || *stack_limit == STACK_CANARY_VALUE; } inline void assert_heap_ok(void) { @@ -77,18 +83,26 @@ void stack_init(void) { } void stack_resize(void) { - if (stack_alloc == NULL) { + if (stack_limit == NULL) { return; } if (next_stack_size == current_stack_size) { - *stack_alloc->ptr = STACK_CANARY_VALUE; + *stack_limit = STACK_CANARY_VALUE; return; } - free_memory(stack_alloc); - stack_alloc = NULL; + free_memory(allocation_from_ptr(stack_limit)); + stack_limit = NULL; allocate_stack(); } +uint32_t* stack_get_bottom(void) { + return stack_limit; +} + +size_t stack_get_length(void) { + return stack_length; +} + void set_next_stack_size(uint32_t size) { next_stack_size = size; } diff --git a/supervisor/shared/stack.h b/supervisor/shared/stack.h index 7096f0b3e..1c75de5f7 100755 --- a/supervisor/shared/stack.h +++ b/supervisor/shared/stack.h @@ -31,10 +31,12 @@ #include "supervisor/memory.h" -extern supervisor_allocation* stack_alloc; - void stack_init(void); void stack_resize(void); +// Actual stack location and size, may be larger than requested. +uint32_t* stack_get_bottom(void); +size_t stack_get_length(void); +// Next/current requested stack size. void set_next_stack_size(uint32_t size); uint32_t get_current_stack_size(void); bool stack_ok(void); -- cgit v1.2.3 From ac91220361e402bbf6ebb741a9b6ea258a05da99 Mon Sep 17 00:00:00 2001 From: Christian Walther Date: Fri, 16 Oct 2020 23:08:29 +0200 Subject: Use movable allocation system for Sharp display framebuffer. Hybrid allocation is now part of the infrastructure. Moving memory contents would not be necessary because displayio can recreate them, but does not hurt. --- .../sharpdisplay/SharpMemoryFramebuffer.c | 57 ++++++---------------- .../sharpdisplay/SharpMemoryFramebuffer.h | 1 - 2 files changed, 14 insertions(+), 44 deletions(-) (limited to 'shared-module') diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c index aefb6b18d..4b92bd637 100644 --- a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c @@ -34,32 +34,10 @@ #include "shared-module/sharpdisplay/SharpMemoryFramebuffer.h" #include "supervisor/memory.h" -#include "supervisor/shared/safe_mode.h" #define SHARPMEM_BIT_WRITECMD_LSB (0x80) #define SHARPMEM_BIT_VCOM_LSB (0x40) -static void *hybrid_alloc(size_t sz) { - supervisor_allocation *allocation = allocate_memory(align32_size(sz), false, false); - if (allocation) { - memset(allocation->ptr, 0, sz); - return allocation->ptr; - } - if (gc_alloc_possible()) { - return m_malloc(sz, true); - } - reset_into_safe_mode(MEM_MANAGE); - return NULL; // unreached -} - -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); @@ -102,9 +80,9 @@ void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *s } void common_hal_sharpdisplay_framebuffer_reconstruct(sharpdisplay_framebuffer_obj_t *self) { - if (!allocation_from_ptr(self->bufinfo.buf)) { - self->bufinfo.buf = NULL; - } + // Look up the allocation by the old pointer and get the new pointer from it. + supervisor_allocation* alloc = allocation_from_ptr(self->bufinfo.buf); + self->bufinfo.buf = alloc ? alloc->ptr : NULL; } void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_obj_t *self, mp_buffer_info_t *bufinfo) { @@ -112,7 +90,12 @@ void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_ob 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); + supervisor_allocation* alloc = allocate_memory(align32_size(self->bufinfo.len), false, true); + if (alloc == NULL) { + m_malloc_fail(self->bufinfo.len); + } + self->bufinfo.buf = alloc->ptr; + memset(alloc->ptr, 0, self->bufinfo.len); uint8_t *data = self->bufinfo.buf; *data++ = SHARPMEM_BIT_WRITECMD_LSB; @@ -123,7 +106,9 @@ void common_hal_sharpdisplay_framebuffer_get_bufinfo(sharpdisplay_framebuffer_ob } self->full_refresh = true; } - *bufinfo = self->bufinfo; + if (bufinfo) { + *bufinfo = self->bufinfo; + } } void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t *self) { @@ -137,7 +122,7 @@ void common_hal_sharpdisplay_framebuffer_deinit(sharpdisplay_framebuffer_obj_t * common_hal_reset_pin(self->chip_select.pin); - hybrid_free(self->bufinfo.buf); + free_memory(allocation_from_ptr(self->bufinfo.buf)); memset(self, 0, sizeof(*self)); } @@ -154,19 +139,7 @@ void common_hal_sharpdisplay_framebuffer_construct(sharpdisplay_framebuffer_obj_ self->height = height; self->baudrate = baudrate; - int row_stride = common_hal_sharpdisplay_framebuffer_get_row_stride(self); - self->bufinfo.len = row_stride * height + 2; - // re-use a supervisor allocation if possible - self->bufinfo.buf = hybrid_alloc(self->bufinfo.len); - - 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; + common_hal_sharpdisplay_framebuffer_get_bufinfo(self, NULL); } void common_hal_sharpdisplay_framebuffer_swapbuffers(sharpdisplay_framebuffer_obj_t *self, uint8_t *dirty_row_bitmask) { @@ -271,7 +244,5 @@ const framebuffer_p_t sharpdisplay_framebuffer_proto = { }; 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 index 8acacc94e..08966a89c 100644 --- a/shared-module/sharpdisplay/SharpMemoryFramebuffer.h +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.h @@ -33,7 +33,6 @@ 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; -- cgit v1.2.3 From a4b84cf0e118f06cc3b563866d5c594b94b9b3fb Mon Sep 17 00:00:00 2001 From: Christian Walther Date: Sat, 17 Oct 2020 13:49:10 +0200 Subject: Use movable allocation system for RGBMatrix allocations. Hybrid allocation is now part of the infrastructure. Moving memory contents would not be necessary because displayio can recreate them, but does not hurt. --- shared-module/rgbmatrix/RGBMatrix.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'shared-module') diff --git a/shared-module/rgbmatrix/RGBMatrix.c b/shared-module/rgbmatrix/RGBMatrix.c index 1f144aedb..a09767b62 100644 --- a/shared-module/rgbmatrix/RGBMatrix.c +++ b/shared-module/rgbmatrix/RGBMatrix.c @@ -78,10 +78,10 @@ void common_hal_rgbmatrix_rgbmatrix_reconstruct(rgbmatrix_rgbmatrix_obj_t* self, // verify that the matrix is big enough 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->protomatter.rgbPins); - _PM_free(self->protomatter.addr); - _PM_free(self->protomatter.screenData); + common_hal_rgbmatrix_free_impl(self->bufinfo.buf); + common_hal_rgbmatrix_free_impl(self->protomatter.rgbPins); + common_hal_rgbmatrix_free_impl(self->protomatter.addr); + common_hal_rgbmatrix_free_impl(self->protomatter.screenData); self->framebuffer = NULL; self->bufinfo.buf = common_hal_rgbmatrix_allocator_impl(self->bufsize); @@ -180,9 +180,6 @@ 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->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) { @@ -217,18 +214,10 @@ int common_hal_rgbmatrix_rgbmatrix_get_height(rgbmatrix_rgbmatrix_obj_t* self) { } 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, false); - return allocation ? allocation->ptr : NULL; - } + supervisor_allocation *allocation = allocate_memory(align32_size(sz), false, true); + 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); - } + free_memory(allocation_from_ptr(ptr_in)); } -- cgit v1.2.3 From 7ca36d45a4ffe40c70814d62cb970007b7f40fee Mon Sep 17 00:00:00 2001 From: Christian Walther Date: Fri, 23 Oct 2020 22:35:56 +0200 Subject: Fix align32_size(). It not only caused crashes with requests larger than 64K (can happen with RGBMatrix), but also generated a lot longer code than necessary. --- shared-module/usb_midi/__init__.c | 6 +++--- supervisor/memory.h | 7 ++----- 2 files changed, 5 insertions(+), 8 deletions(-) (limited to 'shared-module') diff --git a/shared-module/usb_midi/__init__.c b/shared-module/usb_midi/__init__.c index 5afdd1821..3fb3f836c 100644 --- a/shared-module/usb_midi/__init__.c +++ b/shared-module/usb_midi/__init__.c @@ -40,9 +40,9 @@ supervisor_allocation* usb_midi_allocation; void usb_midi_init(void) { // TODO(tannewt): Make this dynamic. - uint16_t tuple_size = align32_size(sizeof(mp_obj_tuple_t) + sizeof(mp_obj_t*) * 2); - uint16_t portin_size = align32_size(sizeof(usb_midi_portin_obj_t)); - uint16_t portout_size = align32_size(sizeof(usb_midi_portout_obj_t)); + size_t tuple_size = align32_size(sizeof(mp_obj_tuple_t) + sizeof(mp_obj_t*) * 2); + size_t portin_size = align32_size(sizeof(usb_midi_portin_obj_t)); + size_t portout_size = align32_size(sizeof(usb_midi_portout_obj_t)); // For each embedded MIDI Jack in the descriptor we create a Port usb_midi_allocation = allocate_memory(tuple_size + portin_size + portout_size, false, false); diff --git a/supervisor/memory.h b/supervisor/memory.h index 4307e3f21..0f820eac1 100755 --- a/supervisor/memory.h +++ b/supervisor/memory.h @@ -64,11 +64,8 @@ supervisor_allocation* allocate_remaining_memory(void); // supervisor_move_memory(). supervisor_allocation* allocate_memory(uint32_t length, bool high_address, bool movable); -static inline uint16_t align32_size(uint16_t size) { - if (size % 4 != 0) { - return (size & 0xfffc) + 0x4; - } - return size; +static inline size_t align32_size(size_t size) { + return (size + 3) & ~3; } size_t get_allocation_length(supervisor_allocation* allocation); -- cgit v1.2.3 From 28bd29eb42d61d0a7116b6c4295e166fcfbe7145 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 16 Dec 2020 13:48:07 -0600 Subject: displayio: ColorConverter: fix logic errors about transparent pixels The transparent_color field was never initialized. I _think_ this means its value was always set to 0, or the blackest of blacks. Instead, initialize it to the sentinel value, newly given the name NO_TRANSPARENT_COLOR. This exposed a second problem: The test for whether there was an existing transparent color was wrong (backwards). I am guessing that this was not found due to the first bug; since the converter had a transparent color, the correct test would have led to always getting the error "Only one color can be transparent at a time". Closes #3723 --- shared-module/displayio/ColorConverter.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'shared-module') diff --git a/shared-module/displayio/ColorConverter.c b/shared-module/displayio/ColorConverter.c index 80558d037..40dcd9d16 100644 --- a/shared-module/displayio/ColorConverter.c +++ b/shared-module/displayio/ColorConverter.c @@ -29,6 +29,8 @@ #include "py/misc.h" #include "py/runtime.h" +#define NO_TRANSPARENT_COLOR (0x1000000) + uint32_t displayio_colorconverter_dither_noise_1 (uint32_t n) { n = (n >> 13) ^ n; @@ -42,6 +44,7 @@ uint32_t displayio_colorconverter_dither_noise_2(uint32_t x, uint32_t y) { void common_hal_displayio_colorconverter_construct(displayio_colorconverter_t* self, bool dither) { self->dither = dither; + self->transparent_color = NO_TRANSPARENT_COLOR; } uint16_t displayio_colorconverter_compute_rgb565(uint32_t color_rgb888) { @@ -130,7 +133,7 @@ bool common_hal_displayio_colorconverter_get_dither(displayio_colorconverter_t* } void common_hal_displayio_colorconverter_make_transparent(displayio_colorconverter_t* self, uint32_t transparent_color) { - if (self->transparent_color >= 0x1000000) { + if (self->transparent_color != NO_TRANSPARENT_COLOR) { mp_raise_RuntimeError(translate("Only one color can be transparent at a time")); } self->transparent_color = transparent_color; @@ -138,8 +141,8 @@ void common_hal_displayio_colorconverter_make_transparent(displayio_colorconvert void common_hal_displayio_colorconverter_make_opaque(displayio_colorconverter_t* self, uint32_t transparent_color) { (void) transparent_color; - // 0x1000000 will never equal a valid color - self->transparent_color = 0x1000000; + // NO_TRANSPARENT_COLOR will never equal a valid color + self->transparent_color = NO_TRANSPARENT_COLOR; } void displayio_colorconverter_convert(displayio_colorconverter_t *self, const _displayio_colorspace_t* colorspace, const displayio_input_pixel_t *input_pixel, displayio_output_pixel_t *output_color) { -- cgit v1.2.3 From f224ed18488b1e92b6d13b09b696769a2ac380ce Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Thu, 17 Dec 2020 10:54:37 -0600 Subject: OnDiskBitmap: Correct handling of "0 color palette" images Microsoft documentation says: > If biCompression equals BI_RGB and the bitmap uses 8 bpp or less, the bitmap has a color table immediatelly following the BITMAPINFOHEADER structure. The color table consists of an array of RGBQUAD values. The size of the array is given by the biClrUsed member. If biClrUsed is zero, the array contains the maximum number of colors for the given bitdepth; that is, 2^biBitCount colors. Formerly, we treated 0 colors as "no image palette" during construction, but then during common_hal_displayio_ondiskbitmap_get_pixel indexed into the palette anyway. This could have unpredictable results. On a pygamer, it gave an image that was blue and black. On magtag, it gave a crash. --- shared-module/displayio/OnDiskBitmap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'shared-module') diff --git a/shared-module/displayio/OnDiskBitmap.c b/shared-module/displayio/OnDiskBitmap.c index 993fc03de..c1a0ddeb7 100644 --- a/shared-module/displayio/OnDiskBitmap.c +++ b/shared-module/displayio/OnDiskBitmap.c @@ -57,7 +57,7 @@ void common_hal_displayio_ondiskbitmap_construct(displayio_ondiskbitmap_t *self, uint32_t compression = read_word(bmp_header, 15); uint32_t number_of_colors = read_word(bmp_header, 23); - bool indexed = ((bits_per_pixel <= 8) && (number_of_colors != 0)); + bool indexed = bits_per_pixel <= 8; self->bitfield_compressed = (compression == 3); self->bits_per_pixel = bits_per_pixel; self->width = read_word(bmp_header, 9); @@ -75,6 +75,9 @@ void common_hal_displayio_ondiskbitmap_construct(displayio_ondiskbitmap_t *self, self->b_bitmask = 0x1f; } } else if (indexed && self->bits_per_pixel != 1) { + if (number_of_colors == 0) { + number_of_colors = 1 << bits_per_pixel; + } uint16_t palette_size = number_of_colors * sizeof(uint32_t); uint16_t palette_offset = 0xe + header_size; -- cgit v1.2.3 From 6c4df5a8b45c6b20e00b5499c5db1d4f5da444a2 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Fri, 18 Dec 2020 11:13:28 -0600 Subject: adafruit_bus_device: Don't transmit STOP condition in write_then_readinto Closes #3795 --- shared-bindings/adafruit_bus_device/I2CDevice.c | 8 ++++---- shared-bindings/adafruit_bus_device/I2CDevice.h | 2 +- shared-module/adafruit_bus_device/I2CDevice.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'shared-module') diff --git a/shared-bindings/adafruit_bus_device/I2CDevice.c b/shared-bindings/adafruit_bus_device/I2CDevice.c index 4c9086162..a4c04e198 100644 --- a/shared-bindings/adafruit_bus_device/I2CDevice.c +++ b/shared-bindings/adafruit_bus_device/I2CDevice.c @@ -163,7 +163,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(adafruit_bus_device_i2cdevice_readinto_obj, 2, //| """ //| ... //| -STATIC void write(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end) { +STATIC void write(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, int32_t start, mp_int_t end, bool transmit_stop_bit) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_READ); @@ -173,7 +173,7 @@ STATIC void write(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, in mp_raise_ValueError(translate("Buffer must be at least length 1")); } - uint8_t status = common_hal_adafruit_bus_device_i2cdevice_write(MP_OBJ_TO_PTR(self), ((uint8_t*)bufinfo.buf) + start, length); + uint8_t status = common_hal_adafruit_bus_device_i2cdevice_write(MP_OBJ_TO_PTR(self), ((uint8_t*)bufinfo.buf) + start, length, transmit_stop_bit); if (status != 0) { mp_raise_OSError(status); } @@ -191,7 +191,7 @@ STATIC mp_obj_t adafruit_bus_device_i2cdevice_write(size_t n_args, const mp_obj_ 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); - write(self, args[ARG_buffer].u_obj, args[ARG_start].u_int, args[ARG_end].u_int); + write(self, args[ARG_buffer].u_obj, args[ARG_start].u_int, args[ARG_end].u_int, true); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_KW(adafruit_bus_device_i2cdevice_write_obj, 2, adafruit_bus_device_i2cdevice_write); @@ -233,7 +233,7 @@ STATIC mp_obj_t adafruit_bus_device_i2cdevice_write_then_readinto(size_t n_args, 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); - write(self, args[ARG_out_buffer].u_obj, args[ARG_out_start].u_int, args[ARG_out_end].u_int); + write(self, args[ARG_out_buffer].u_obj, args[ARG_out_start].u_int, args[ARG_out_end].u_int, false); readinto(self, args[ARG_in_buffer].u_obj, args[ARG_in_start].u_int, args[ARG_in_end].u_int); diff --git a/shared-bindings/adafruit_bus_device/I2CDevice.h b/shared-bindings/adafruit_bus_device/I2CDevice.h index 7b2182ff0..cf7b1321a 100644 --- a/shared-bindings/adafruit_bus_device/I2CDevice.h +++ b/shared-bindings/adafruit_bus_device/I2CDevice.h @@ -45,7 +45,7 @@ extern const mp_obj_type_t adafruit_bus_device_i2cdevice_type; // Initializes the hardware peripheral. extern void common_hal_adafruit_bus_device_i2cdevice_construct(adafruit_bus_device_i2cdevice_obj_t *self, busio_i2c_obj_t *i2c, uint8_t device_address); extern uint8_t common_hal_adafruit_bus_device_i2cdevice_readinto(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); -extern uint8_t common_hal_adafruit_bus_device_i2cdevice_write(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length); +extern uint8_t common_hal_adafruit_bus_device_i2cdevice_write(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length, bool transmit_stop_bit); extern void common_hal_adafruit_bus_device_i2cdevice_lock(adafruit_bus_device_i2cdevice_obj_t *self); extern void common_hal_adafruit_bus_device_i2cdevice_unlock(adafruit_bus_device_i2cdevice_obj_t *self); extern void common_hal_adafruit_bus_device_i2cdevice_probe_for_device(adafruit_bus_device_i2cdevice_obj_t *self); diff --git a/shared-module/adafruit_bus_device/I2CDevice.c b/shared-module/adafruit_bus_device/I2CDevice.c index ee4b4fa55..83abe80d6 100644 --- a/shared-module/adafruit_bus_device/I2CDevice.c +++ b/shared-module/adafruit_bus_device/I2CDevice.c @@ -57,8 +57,8 @@ uint8_t common_hal_adafruit_bus_device_i2cdevice_readinto(adafruit_bus_device_i2 return common_hal_busio_i2c_read(self->i2c, self->device_address, buffer, length); } -uint8_t common_hal_adafruit_bus_device_i2cdevice_write(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length) { - return common_hal_busio_i2c_write(self->i2c, self->device_address, buffer, length, true); +uint8_t common_hal_adafruit_bus_device_i2cdevice_write(adafruit_bus_device_i2cdevice_obj_t *self, mp_obj_t buffer, size_t length, bool transmit_stop_bit) { + return common_hal_busio_i2c_write(self->i2c, self->device_address, buffer, length, transmit_stop_bit); } void common_hal_adafruit_bus_device_i2cdevice_probe_for_device(adafruit_bus_device_i2cdevice_obj_t *self) { -- cgit v1.2.3 From dc332baa87bf1fa3d777ffe31c7dc29b24a6a142 Mon Sep 17 00:00:00 2001 From: microDev <70126934+microDev1@users.noreply.github.com> Date: Mon, 28 Dec 2020 20:04:00 +0530 Subject: update common_hal_reset_pin() --- ports/atmel-samd/common-hal/microcontroller/Pin.c | 3 +++ ports/esp32s2/common-hal/busio/SPI.c | 8 ++------ ports/esp32s2/common-hal/microcontroller/Pin.c | 3 +++ ports/litex/common-hal/microcontroller/Pin.c | 3 +++ ports/mimxrt10xx/common-hal/busio/SPI.c | 9 +++------ ports/mimxrt10xx/common-hal/busio/UART.c | 10 ++++------ ports/mimxrt10xx/common-hal/microcontroller/Pin.c | 3 +++ ports/nrf/common-hal/microcontroller/Pin.c | 3 +++ ports/stm/common-hal/microcontroller/Pin.c | 3 +++ shared-module/displayio/FourWire.c | 4 +--- 10 files changed, 28 insertions(+), 21 deletions(-) (limited to 'shared-module') diff --git a/ports/atmel-samd/common-hal/microcontroller/Pin.c b/ports/atmel-samd/common-hal/microcontroller/Pin.c index 7dd87a3b2..564d037e0 100644 --- a/ports/atmel-samd/common-hal/microcontroller/Pin.c +++ b/ports/atmel-samd/common-hal/microcontroller/Pin.c @@ -169,6 +169,9 @@ void common_hal_never_reset_pin(const mcu_pin_obj_t* pin) { } void common_hal_reset_pin(const mcu_pin_obj_t* pin) { + if (pin == NULL) { + return; + } reset_pin_number(pin->number); } diff --git a/ports/esp32s2/common-hal/busio/SPI.c b/ports/esp32s2/common-hal/busio/SPI.c index 562881585..62f47999c 100644 --- a/ports/esp32s2/common-hal/busio/SPI.c +++ b/ports/esp32s2/common-hal/busio/SPI.c @@ -248,12 +248,8 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { spi_bus_free(self->host_id); common_hal_reset_pin(self->clock_pin); - if (self->MOSI_pin != NULL) { - common_hal_reset_pin(self->MOSI_pin); - } - if (self->MISO_pin != NULL) { - common_hal_reset_pin(self->MISO_pin); - } + common_hal_reset_pin(self->MOSI_pin); + common_hal_reset_pin(self->MISO_pin); self->clock_pin = NULL; self->MISO_pin = NULL; self->MOSI_pin = NULL; diff --git a/ports/esp32s2/common-hal/microcontroller/Pin.c b/ports/esp32s2/common-hal/microcontroller/Pin.c index 81dfa1308..26bd6c16b 100644 --- a/ports/esp32s2/common-hal/microcontroller/Pin.c +++ b/ports/esp32s2/common-hal/microcontroller/Pin.c @@ -89,6 +89,9 @@ void reset_pin_number(gpio_num_t pin_number) { } void common_hal_reset_pin(const mcu_pin_obj_t* pin) { + if (pin == NULL) { + return; + } reset_pin_number(pin->number); } diff --git a/ports/litex/common-hal/microcontroller/Pin.c b/ports/litex/common-hal/microcontroller/Pin.c index 38601e0d3..4d088a076 100644 --- a/ports/litex/common-hal/microcontroller/Pin.c +++ b/ports/litex/common-hal/microcontroller/Pin.c @@ -42,6 +42,9 @@ void reset_pin_number(uint8_t pin_port, uint8_t pin_number) { } void common_hal_reset_pin(const mcu_pin_obj_t* pin) { + if (pin == NULL) { + return; + } reset_pin_number(0, pin->number); } diff --git a/ports/mimxrt10xx/common-hal/busio/SPI.c b/ports/mimxrt10xx/common-hal/busio/SPI.c index 8fe1b799d..ce7cbea7e 100644 --- a/ports/mimxrt10xx/common-hal/busio/SPI.c +++ b/ports/mimxrt10xx/common-hal/busio/SPI.c @@ -220,12 +220,9 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { never_reset_spi[self->clock->bank_idx - 1] = false; common_hal_reset_pin(self->clock->pin); - if (self->mosi != NULL) { - common_hal_reset_pin(self->mosi->pin); - } - if (self->miso != NULL) { - common_hal_reset_pin(self->miso->pin); - } + common_hal_reset_pin(self->mosi->pin); + common_hal_reset_pin(self->miso->pin); + self->clock = NULL; self->mosi = NULL; self->miso = NULL; diff --git a/ports/mimxrt10xx/common-hal/busio/UART.c b/ports/mimxrt10xx/common-hal/busio/UART.c index db5582d15..03a6e8f3e 100644 --- a/ports/mimxrt10xx/common-hal/busio/UART.c +++ b/ports/mimxrt10xx/common-hal/busio/UART.c @@ -295,12 +295,10 @@ void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { LPUART_Deinit(self->uart); gc_free(self->ringbuf); - if (self->rx) { - common_hal_reset_pin(self->rx->pin); - } - if (self->tx) { - common_hal_reset_pin(self->tx->pin); - } + + common_hal_reset_pin(self->rx->pin); + common_hal_reset_pin(self->tx->pin); + self->rx = NULL; self->tx = NULL; diff --git a/ports/mimxrt10xx/common-hal/microcontroller/Pin.c b/ports/mimxrt10xx/common-hal/microcontroller/Pin.c index a005924e2..50970f8e2 100644 --- a/ports/mimxrt10xx/common-hal/microcontroller/Pin.c +++ b/ports/mimxrt10xx/common-hal/microcontroller/Pin.c @@ -67,6 +67,9 @@ void reset_all_pins(void) { // Since i.MX pins need extra register and reset information to reset properly, // resetting pins by number alone has been removed. void common_hal_reset_pin(const mcu_pin_obj_t* pin) { + if (pin == NULL) { + return; + } never_reset_pins[pin->mux_idx] = false; claimed_pins[pin->mux_idx] = false; *(uint32_t*)pin->mux_reg = pin->mux_reset; diff --git a/ports/nrf/common-hal/microcontroller/Pin.c b/ports/nrf/common-hal/microcontroller/Pin.c index bc7ff831a..23d6e23bf 100644 --- a/ports/nrf/common-hal/microcontroller/Pin.c +++ b/ports/nrf/common-hal/microcontroller/Pin.c @@ -134,6 +134,9 @@ void common_hal_never_reset_pin(const mcu_pin_obj_t* pin) { } void common_hal_reset_pin(const mcu_pin_obj_t* pin) { + if (pin == NULL) { + return; + } reset_pin_number(pin->number); } diff --git a/ports/stm/common-hal/microcontroller/Pin.c b/ports/stm/common-hal/microcontroller/Pin.c index 0e333c71c..37c202d86 100644 --- a/ports/stm/common-hal/microcontroller/Pin.c +++ b/ports/stm/common-hal/microcontroller/Pin.c @@ -125,6 +125,9 @@ void common_hal_never_reset_pin(const mcu_pin_obj_t* pin) { } void common_hal_reset_pin(const mcu_pin_obj_t* pin) { + if (pin == NULL) { + return; + } reset_pin_number(pin->port, pin->number); } diff --git a/shared-module/displayio/FourWire.c b/shared-module/displayio/FourWire.c index 06f8a84e3..e993f2480 100644 --- a/shared-module/displayio/FourWire.c +++ b/shared-module/displayio/FourWire.c @@ -76,9 +76,7 @@ void common_hal_displayio_fourwire_deinit(displayio_fourwire_obj_t* self) { common_hal_reset_pin(self->command.pin); common_hal_reset_pin(self->chip_select.pin); - if (self->reset.pin) { - common_hal_reset_pin(self->reset.pin); - } + common_hal_reset_pin(self->reset.pin); } bool common_hal_displayio_fourwire_reset(mp_obj_t obj) { -- cgit v1.2.3