Compare commits
19 Commits
master
...
v1.22-rele
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8cd15829e2 | ||
![]() |
ee3c9ccb54 | ||
![]() |
e72d03855e | ||
![]() |
02df2b09d4 | ||
![]() |
e7ff724a87 | ||
![]() |
cc7cfc7e8d | ||
![]() |
b979c5a92a | ||
![]() |
f53ee9f12b | ||
![]() |
2531a15200 | ||
![]() |
8b6e89a8ca | ||
![]() |
a2e9ab362b | ||
![]() |
1e8cc6c503 | ||
![]() |
4c7d955a62 | ||
![]() |
068aa28fc5 | ||
![]() |
d5f3fcd935 | ||
![]() |
9b8c64c9ce | ||
![]() |
ac5e0b9f62 | ||
![]() |
61b8361f5f | ||
![]() |
4b4f6011e8 |
2
LICENSE
2
LICENSE
@ -69,6 +69,8 @@ used during the build process and is not part of the compiled source code.
|
|||||||
/FreeRTOS (GPL-2.0 with FreeRTOS exception)
|
/FreeRTOS (GPL-2.0 with FreeRTOS exception)
|
||||||
/esp32
|
/esp32
|
||||||
/ppp_set_auth.* (Apache-2.0)
|
/ppp_set_auth.* (Apache-2.0)
|
||||||
|
/rp2
|
||||||
|
/mutex_extra.c (BSD-3-clause)
|
||||||
/stm32
|
/stm32
|
||||||
/usbd*.c (MCD-ST Liberty SW License Agreement V2)
|
/usbd*.c (MCD-ST Liberty SW License Agreement V2)
|
||||||
/stm32_it.* (MIT + BSD-3-clause)
|
/stm32_it.* (MIT + BSD-3-clause)
|
||||||
|
@ -219,6 +219,11 @@ def run_until_complete(main_task=None):
|
|||||||
elif t.state is None:
|
elif t.state is None:
|
||||||
# Task is already finished and nothing await'ed on the task,
|
# Task is already finished and nothing await'ed on the task,
|
||||||
# so call the exception handler.
|
# so call the exception handler.
|
||||||
|
|
||||||
|
# Save exception raised by the coro for later use.
|
||||||
|
t.data = exc
|
||||||
|
|
||||||
|
# Create exception context and call the exception handler.
|
||||||
_exc_context["exception"] = exc
|
_exc_context["exception"] = exc
|
||||||
_exc_context["future"] = t
|
_exc_context["future"] = t
|
||||||
Loop.call_exception_handler(_exc_context)
|
Loop.call_exception_handler(_exc_context)
|
||||||
|
@ -63,9 +63,6 @@ class _Remove:
|
|||||||
|
|
||||||
# async
|
# async
|
||||||
def gather(*aws, return_exceptions=False):
|
def gather(*aws, return_exceptions=False):
|
||||||
if not aws:
|
|
||||||
return []
|
|
||||||
|
|
||||||
def done(t, er):
|
def done(t, er):
|
||||||
# Sub-task "t" has finished, with exception "er".
|
# Sub-task "t" has finished, with exception "er".
|
||||||
nonlocal state
|
nonlocal state
|
||||||
@ -86,20 +83,33 @@ def gather(*aws, return_exceptions=False):
|
|||||||
# Gather waiting is done, schedule the main gather task.
|
# Gather waiting is done, schedule the main gather task.
|
||||||
core._task_queue.push(gather_task)
|
core._task_queue.push(gather_task)
|
||||||
|
|
||||||
|
# Prepare the sub-tasks for the gather.
|
||||||
|
# The `state` variable counts the number of tasks to wait for, and can be negative
|
||||||
|
# if the gather should not run at all (because a task already had an exception).
|
||||||
ts = [core._promote_to_task(aw) for aw in aws]
|
ts = [core._promote_to_task(aw) for aw in aws]
|
||||||
|
state = 0
|
||||||
for i in range(len(ts)):
|
for i in range(len(ts)):
|
||||||
if ts[i].state is not True:
|
if ts[i].state is True:
|
||||||
# Task is not running, gather not currently supported for this case.
|
# Task is running, register the callback to call when the task is done.
|
||||||
raise RuntimeError("can't gather")
|
|
||||||
# Register the callback to call when the task is done.
|
|
||||||
ts[i].state = done
|
ts[i].state = done
|
||||||
|
state += 1
|
||||||
|
elif not ts[i].state:
|
||||||
|
# Task finished already.
|
||||||
|
if not isinstance(ts[i].data, StopIteration):
|
||||||
|
# Task finished by raising an exception.
|
||||||
|
if not return_exceptions:
|
||||||
|
# Do not run this gather at all.
|
||||||
|
state = -len(ts)
|
||||||
|
else:
|
||||||
|
# Task being waited on, gather not currently supported for this case.
|
||||||
|
raise RuntimeError("can't gather")
|
||||||
|
|
||||||
# Set the state for execution of the gather.
|
# Set the state for execution of the gather.
|
||||||
gather_task = core.cur_task
|
gather_task = core.cur_task
|
||||||
state = len(ts)
|
|
||||||
cancel_all = False
|
cancel_all = False
|
||||||
|
|
||||||
# Wait for the a sub-task to need attention.
|
# Wait for a sub-task to need attention (if there are any to wait for).
|
||||||
|
if state > 0:
|
||||||
gather_task.data = _Remove
|
gather_task.data = _Remove
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
@ -118,8 +128,13 @@ def gather(*aws, return_exceptions=False):
|
|||||||
# Sub-task ran to completion, get its return value.
|
# Sub-task ran to completion, get its return value.
|
||||||
ts[i] = ts[i].data.value
|
ts[i] = ts[i].data.value
|
||||||
else:
|
else:
|
||||||
# Sub-task had an exception with return_exceptions==True, so get its exception.
|
# Sub-task had an exception.
|
||||||
|
if return_exceptions:
|
||||||
|
# Get the sub-task exception to return in the list of return values.
|
||||||
ts[i] = ts[i].data
|
ts[i] = ts[i].data
|
||||||
|
elif isinstance(state, int):
|
||||||
|
# Raise the sub-task exception, if there is not already an exception to raise.
|
||||||
|
state = ts[i].data
|
||||||
|
|
||||||
# Either this gather was cancelled, or one of the sub-tasks raised an exception with
|
# Either this gather was cancelled, or one of the sub-tasks raised an exception with
|
||||||
# return_exceptions==False, so reraise the exception here.
|
# return_exceptions==False, so reraise the exception here.
|
||||||
|
@ -462,8 +462,9 @@ STATIC void btstack_packet_handler_read(uint8_t packet_type, uint16_t channel, u
|
|||||||
if (!conn) {
|
if (!conn) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mp_bluetooth_gattc_on_read_write_status(MP_BLUETOOTH_IRQ_GATTC_READ_DONE, conn_handle, conn->pending_value_handle, status);
|
uint16_t value_handle = conn->pending_value_handle;
|
||||||
conn->pending_value_handle = 0xffff;
|
conn->pending_value_handle = 0xffff;
|
||||||
|
mp_bluetooth_gattc_on_read_write_status(MP_BLUETOOTH_IRQ_GATTC_READ_DONE, conn_handle, value_handle, status);
|
||||||
} else if (event_type == GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT) {
|
} else if (event_type == GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT) {
|
||||||
DEBUG_printf(" --> gatt characteristic value query result\n");
|
DEBUG_printf(" --> gatt characteristic value query result\n");
|
||||||
uint16_t conn_handle = gatt_event_characteristic_value_query_result_get_handle(packet);
|
uint16_t conn_handle = gatt_event_characteristic_value_query_result_get_handle(packet);
|
||||||
@ -490,11 +491,12 @@ STATIC void btstack_packet_handler_write_with_response(uint8_t packet_type, uint
|
|||||||
if (!conn) {
|
if (!conn) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mp_bluetooth_gattc_on_read_write_status(MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE, conn_handle, conn->pending_value_handle, status);
|
uint16_t value_handle = conn->pending_value_handle;
|
||||||
conn->pending_value_handle = 0xffff;
|
conn->pending_value_handle = 0xffff;
|
||||||
m_del(uint8_t, conn->pending_write_value, conn->pending_write_value_len);
|
m_del(uint8_t, conn->pending_write_value, conn->pending_write_value_len);
|
||||||
conn->pending_write_value = NULL;
|
conn->pending_write_value = NULL;
|
||||||
conn->pending_write_value_len = 0;
|
conn->pending_write_value_len = 0;
|
||||||
|
mp_bluetooth_gattc_on_read_write_status(MP_BLUETOOTH_IRQ_GATTC_WRITE_DONE, conn_handle, value_handle, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
|
#endif // MICROPY_PY_BLUETOOTH_ENABLE_GATT_CLIENT
|
||||||
|
@ -1274,7 +1274,7 @@ STATIC mp_obj_t invoke_irq_handler(uint16_t event,
|
|||||||
if (ts_orig == NULL) {
|
if (ts_orig == NULL) {
|
||||||
mp_thread_set_state(&ts);
|
mp_thread_set_state(&ts);
|
||||||
mp_stack_set_top(&ts + 1); // need to include ts in root-pointer scan
|
mp_stack_set_top(&ts + 1); // need to include ts in root-pointer scan
|
||||||
mp_stack_set_limit(MICROPY_PY_BLUETOOTH_SYNC_EVENT_STACK_SIZE - 1024);
|
mp_stack_set_limit(MICROPY_PY_BLUETOOTH_SYNC_EVENT_STACK_SIZE);
|
||||||
ts.gc_lock_depth = 0;
|
ts.gc_lock_depth = 0;
|
||||||
ts.nlr_jump_callback_top = NULL;
|
ts.nlr_jump_callback_top = NULL;
|
||||||
ts.mp_pending_exception = MP_OBJ_NULL;
|
ts.mp_pending_exception = MP_OBJ_NULL;
|
||||||
|
@ -311,10 +311,6 @@ STATIC mp_obj_t ssl_context_get_ciphers(mp_obj_t self_in) {
|
|||||||
for (const int *cipher_list = mbedtls_ssl_list_ciphersuites(); *cipher_list; ++cipher_list) {
|
for (const int *cipher_list = mbedtls_ssl_list_ciphersuites(); *cipher_list; ++cipher_list) {
|
||||||
const char *cipher_name = mbedtls_ssl_get_ciphersuite_name(*cipher_list);
|
const char *cipher_name = mbedtls_ssl_get_ciphersuite_name(*cipher_list);
|
||||||
mp_obj_list_append(list, MP_OBJ_FROM_PTR(mp_obj_new_str(cipher_name, strlen(cipher_name))));
|
mp_obj_list_append(list, MP_OBJ_FROM_PTR(mp_obj_new_str(cipher_name, strlen(cipher_name))));
|
||||||
cipher_list++;
|
|
||||||
if (!*cipher_list) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
@ -14,3 +14,7 @@ CONFIG_BT_NIMBLE_MAX_CONNECTIONS=4
|
|||||||
CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=n
|
CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=n
|
||||||
CONFIG_BT_NIMBLE_PINNED_TO_CORE_1=y
|
CONFIG_BT_NIMBLE_PINNED_TO_CORE_1=y
|
||||||
CONFIG_BT_NIMBLE_PINNED_TO_CORE=1
|
CONFIG_BT_NIMBLE_PINNED_TO_CORE=1
|
||||||
|
|
||||||
|
# Increase NimBLE task stack size from the default, because Python code
|
||||||
|
# (BLE IRQ handlers) will most likely run on this task.
|
||||||
|
CONFIG_BT_NIMBLE_TASK_STACK_SIZE=6144
|
||||||
|
@ -95,7 +95,7 @@
|
|||||||
#define MICROPY_PY_BLUETOOTH (1)
|
#define MICROPY_PY_BLUETOOTH (1)
|
||||||
#define MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS (1)
|
#define MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS (1)
|
||||||
#define MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS_WITH_INTERLOCK (1)
|
#define MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS_WITH_INTERLOCK (1)
|
||||||
#define MICROPY_PY_BLUETOOTH_SYNC_EVENT_STACK_SIZE (CONFIG_BT_NIMBLE_TASK_STACK_SIZE)
|
#define MICROPY_PY_BLUETOOTH_SYNC_EVENT_STACK_SIZE (CONFIG_BT_NIMBLE_TASK_STACK_SIZE - 2048)
|
||||||
#define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (1)
|
#define MICROPY_PY_BLUETOOTH_ENABLE_CENTRAL_MODE (1)
|
||||||
#define MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING (1)
|
#define MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING (1)
|
||||||
#define MICROPY_BLUETOOTH_NIMBLE (1)
|
#define MICROPY_BLUETOOTH_NIMBLE (1)
|
||||||
|
@ -63,6 +63,11 @@ void mp_bluetooth_nimble_port_start(void) {
|
|||||||
void mp_bluetooth_nimble_port_shutdown(void) {
|
void mp_bluetooth_nimble_port_shutdown(void) {
|
||||||
DEBUG_printf("mp_bluetooth_nimble_port_shutdown\n");
|
DEBUG_printf("mp_bluetooth_nimble_port_shutdown\n");
|
||||||
|
|
||||||
|
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS_WITH_INTERLOCK
|
||||||
|
// Release the GIL so any callbacks can run during the shutdown calls below.
|
||||||
|
MP_THREAD_GIL_EXIT();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Despite the name, these is an ESP32-specific (no other NimBLE ports have these functions).
|
// Despite the name, these is an ESP32-specific (no other NimBLE ports have these functions).
|
||||||
// Calls ble_hs_stop() and waits for stack shutdown.
|
// Calls ble_hs_stop() and waits for stack shutdown.
|
||||||
nimble_port_stop();
|
nimble_port_stop();
|
||||||
@ -70,6 +75,10 @@ void mp_bluetooth_nimble_port_shutdown(void) {
|
|||||||
// Shuts down the event queue.
|
// Shuts down the event queue.
|
||||||
nimble_port_deinit();
|
nimble_port_deinit();
|
||||||
|
|
||||||
|
#if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS_WITH_INTERLOCK
|
||||||
|
MP_THREAD_GIL_ENTER();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Mark stack as shutdown.
|
// Mark stack as shutdown.
|
||||||
mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF;
|
mp_bluetooth_nimble_ble_state = MP_BLUETOOTH_NIMBLE_BLE_STATE_OFF;
|
||||||
}
|
}
|
||||||
|
@ -139,10 +139,10 @@ NORETURN STATIC void mp_machine_deepsleep(size_t n_args, const mp_obj_t *args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MIMXRT117x_SERIES
|
#if defined(MIMXRT117x_SERIES)
|
||||||
machine_pin_config(pin_WAKEUP_DIG, PIN_MODE_IT_RISING, PIN_PULL_DISABLED, PIN_DRIVE_OFF, 0, PIN_AF_MODE_ALT5);
|
machine_pin_config(pin_WAKEUP_DIG, PIN_MODE_IT_RISING, PIN_PULL_DISABLED, PIN_DRIVE_OFF, 0, PIN_AF_MODE_ALT5);
|
||||||
GPC_CM_EnableIrqWakeup(GPC_CPU_MODE_CTRL_0, GPIO13_Combined_0_31_IRQn, true);
|
GPC_CM_EnableIrqWakeup(GPC_CPU_MODE_CTRL_0, GPIO13_Combined_0_31_IRQn, true);
|
||||||
#elif defined IOMUXC_SNVS_WAKEUP_GPIO5_IO00
|
#elif defined(pin_WAKEUP)
|
||||||
machine_pin_config(pin_WAKEUP, PIN_MODE_IT_RISING, PIN_PULL_DISABLED, PIN_DRIVE_OFF, 0, PIN_AF_MODE_ALT5);
|
machine_pin_config(pin_WAKEUP, PIN_MODE_IT_RISING, PIN_PULL_DISABLED, PIN_DRIVE_OFF, 0, PIN_AF_MODE_ALT5);
|
||||||
GPC_EnableIRQ(GPC, GPIO5_Combined_0_15_IRQn);
|
GPC_EnableIRQ(GPC, GPIO5_Combined_0_15_IRQn);
|
||||||
#endif
|
#endif
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
// peripheral config
|
// peripheral config
|
||||||
#define MICROPY_HW_ENABLE_RNG (1)
|
#define MICROPY_HW_ENABLE_RNG (1)
|
||||||
#define MICROPY_HW_ENABLE_RTC (1)
|
#define MICROPY_HW_ENABLE_RTC (1)
|
||||||
#define MICROPY_HW_RTC_SOURCE (1)
|
#define MICROPY_HW_RTC_SOURCE (0)
|
||||||
#define MICROPY_HW_ENABLE_ADC (1)
|
#define MICROPY_HW_ENABLE_ADC (1)
|
||||||
#define MICROPY_HW_HAS_FLASH (1)
|
#define MICROPY_HW_HAS_FLASH (1)
|
||||||
#define MICROPY_HW_ENABLE_USBDEV (1)
|
#define MICROPY_HW_ENABLE_USBDEV (1)
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#define RA_RA_CONFIG_H_
|
#define RA_RA_CONFIG_H_
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "py/mpconfig.h"
|
||||||
|
|
||||||
#if defined(RA4M1) | defined(RA4W1)
|
#if defined(RA4M1) | defined(RA4W1)
|
||||||
#define SCI_CH_MAX 10
|
#define SCI_CH_MAX 10
|
||||||
|
@ -426,7 +426,7 @@ void ra_i2c_init(R_IIC0_Type *i2c_inst, uint32_t scl, uint32_t sda, uint32_t bau
|
|||||||
i2c_inst->ICCR1_b.ICE = 1; // I2C enable
|
i2c_inst->ICCR1_b.ICE = 1; // I2C enable
|
||||||
ra_i2c_set_baudrate(i2c_inst, baudrate);
|
ra_i2c_set_baudrate(i2c_inst, baudrate);
|
||||||
i2c_inst->ICSER = 0x00; // I2C reset bus status enable register
|
i2c_inst->ICSER = 0x00; // I2C reset bus status enable register
|
||||||
i2c_inst->ICMR3_b.ACKWP = 0x01; // I2C allow to write ACKBT (transfer acknowledge bit)
|
i2c_inst->ICMR3_b.ACKWP = 0x00; // I2C not allow to write ACKBT (transfer acknowledge bit)
|
||||||
i2c_inst->ICIER = 0xFF; // Enable all interrupts
|
i2c_inst->ICIER = 0xFF; // Enable all interrupts
|
||||||
i2c_inst->ICCR1_b.IICRST = 0; // I2C internal reset
|
i2c_inst->ICCR1_b.IICRST = 0; // I2C internal reset
|
||||||
ra_i2c_irq_enable(i2c_inst);
|
ra_i2c_irq_enable(i2c_inst);
|
||||||
@ -480,6 +480,7 @@ void ra_i2c_xunit_read_byte(R_IIC0_Type *i2c_inst, xaction_unit_t *unit) {
|
|||||||
void ra_i2c_xunit_init(xaction_unit_t *unit, uint8_t *buf, uint32_t size, bool fread, void *next) {
|
void ra_i2c_xunit_init(xaction_unit_t *unit, uint8_t *buf, uint32_t size, bool fread, void *next) {
|
||||||
unit->m_bytes_transferred = 0;
|
unit->m_bytes_transferred = 0;
|
||||||
unit->m_bytes_transfer = size;
|
unit->m_bytes_transfer = size;
|
||||||
|
unit->m_bytes_total = size;
|
||||||
unit->m_fread = fread;
|
unit->m_fread = fread;
|
||||||
unit->buf = buf;
|
unit->buf = buf;
|
||||||
unit->next = (void *)next;
|
unit->next = (void *)next;
|
||||||
@ -531,6 +532,37 @@ static void ra_i2c_iceri_isr(R_IIC0_Type *i2c_inst) {
|
|||||||
static void ra_i2c_icrxi_isr(R_IIC0_Type *i2c_inst) {
|
static void ra_i2c_icrxi_isr(R_IIC0_Type *i2c_inst) {
|
||||||
xaction_unit_t *unit = current_xaction_unit;
|
xaction_unit_t *unit = current_xaction_unit;
|
||||||
xaction_t *action = current_xaction;
|
xaction_t *action = current_xaction;
|
||||||
|
// 1 byte or 2 bytes
|
||||||
|
if (unit->m_bytes_total <= 2) {
|
||||||
|
if (action->m_status == RA_I2C_STATUS_AddrWriteCompleted) {
|
||||||
|
action->m_status = RA_I2C_STATUS_FirstReceiveCompleted;
|
||||||
|
i2c_inst->ICMR3_b.WAIT = 1;
|
||||||
|
// need dummy read processes for 1 byte and 2 bytes receive
|
||||||
|
if (unit->m_bytes_total == 2) {
|
||||||
|
(void)i2c_inst->ICDRR; // dummy read for 2 bytes receive
|
||||||
|
} else { // m_bytes_total == 1
|
||||||
|
i2c_inst->ICMR3_b.ACKWP = 0x01; // enable write ACKBT (transfer acknowledge bit)
|
||||||
|
i2c_inst->ICMR3_b.ACKBT = 1;
|
||||||
|
i2c_inst->ICMR3_b.ACKWP = 0x00; // disable write ACKBT (transfer acknowledge bit)
|
||||||
|
(void)i2c_inst->ICDRR; // dummy read for 1 byte receive
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (unit->m_bytes_transfer == 2) { // last two data
|
||||||
|
i2c_inst->ICMR3_b.ACKWP = 0x01; // enable write ACKBT (transfer acknowledge bit)
|
||||||
|
i2c_inst->ICMR3_b.ACKBT = 1;
|
||||||
|
i2c_inst->ICMR3_b.ACKWP = 0x00; // disable write ACKBT (transfer acknowledge bit)
|
||||||
|
ra_i2c_xunit_read_byte(i2c_inst, unit);
|
||||||
|
} else { // last data
|
||||||
|
action->m_status = RA_I2C_STATUS_LastReceiveCompleted;
|
||||||
|
if (action->m_stop == true) {
|
||||||
|
i2c_inst->ICCR2_b.SP = 1; // request top condition
|
||||||
|
}
|
||||||
|
ra_i2c_xunit_read_byte(i2c_inst, unit);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 3 bytes or more
|
||||||
if (action->m_status == RA_I2C_STATUS_AddrWriteCompleted) {
|
if (action->m_status == RA_I2C_STATUS_AddrWriteCompleted) {
|
||||||
(void)i2c_inst->ICDRR; // dummy read
|
(void)i2c_inst->ICDRR; // dummy read
|
||||||
action->m_status = RA_I2C_STATUS_FirstReceiveCompleted;
|
action->m_status = RA_I2C_STATUS_FirstReceiveCompleted;
|
||||||
@ -542,7 +574,9 @@ static void ra_i2c_icrxi_isr(R_IIC0_Type *i2c_inst) {
|
|||||||
}
|
}
|
||||||
ra_i2c_xunit_read_byte(i2c_inst, unit);
|
ra_i2c_xunit_read_byte(i2c_inst, unit);
|
||||||
} else if (unit->m_bytes_transfer == 2) {
|
} else if (unit->m_bytes_transfer == 2) {
|
||||||
|
i2c_inst->ICMR3_b.ACKWP = 0x01; // enable write ACKBT (transfer acknowledge bit)
|
||||||
i2c_inst->ICMR3_b.ACKBT = 1;
|
i2c_inst->ICMR3_b.ACKBT = 1;
|
||||||
|
i2c_inst->ICMR3_b.ACKWP = 0x00; // disable write ACKBT (transfer acknowledge bit)
|
||||||
ra_i2c_xunit_read_byte(i2c_inst, unit);
|
ra_i2c_xunit_read_byte(i2c_inst, unit);
|
||||||
} else {
|
} else {
|
||||||
// last data
|
// last data
|
||||||
|
@ -47,9 +47,9 @@ typedef enum
|
|||||||
RA_I2C_STATUS_AddrWriteCompleted = 3,
|
RA_I2C_STATUS_AddrWriteCompleted = 3,
|
||||||
RA_I2C_STATUS_DataWriteCompleted = 4,
|
RA_I2C_STATUS_DataWriteCompleted = 4,
|
||||||
RA_I2C_STATUS_DataSendCompleted = 5,
|
RA_I2C_STATUS_DataSendCompleted = 5,
|
||||||
RA_I2C_STATUS_FirstReceiveCompleted = 5,
|
RA_I2C_STATUS_FirstReceiveCompleted = 6,
|
||||||
RA_I2C_STATUS_LastReceiveCompleted = 6,
|
RA_I2C_STATUS_LastReceiveCompleted = 7,
|
||||||
RA_I2C_STATUS_Stopped = 7,
|
RA_I2C_STATUS_Stopped = 8,
|
||||||
} xaction_status_t;
|
} xaction_status_t;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
@ -64,6 +64,7 @@ typedef enum
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
volatile uint32_t m_bytes_transferred;
|
volatile uint32_t m_bytes_transferred;
|
||||||
volatile uint32_t m_bytes_transfer;
|
volatile uint32_t m_bytes_transfer;
|
||||||
|
uint32_t m_bytes_total;
|
||||||
bool m_fread;
|
bool m_fread;
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
void *next;
|
void *next;
|
||||||
@ -75,7 +76,7 @@ typedef struct {
|
|||||||
uint32_t m_current;
|
uint32_t m_current;
|
||||||
uint32_t m_address;
|
uint32_t m_address;
|
||||||
volatile xaction_status_t m_status;
|
volatile xaction_status_t m_status;
|
||||||
xaction_error_t m_error;
|
volatile xaction_error_t m_error;
|
||||||
bool m_stop;
|
bool m_stop;
|
||||||
} xaction_t;
|
} xaction_t;
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
void ra_init(void) {
|
void ra_init(void) {
|
||||||
ra_int_init();
|
ra_int_init();
|
||||||
SysTick_Config(PCLK / 1000);
|
SysTick_Config(MICROPY_HW_MCU_SYSCLK / 1000);
|
||||||
internal_flash_init();
|
internal_flash_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,6 +129,7 @@ set(MICROPY_SOURCE_PORT
|
|||||||
mphalport.c
|
mphalport.c
|
||||||
mpnetworkport.c
|
mpnetworkport.c
|
||||||
mpthreadport.c
|
mpthreadport.c
|
||||||
|
mutex_extra.c
|
||||||
pendsv.c
|
pendsv.c
|
||||||
rp2_flash.c
|
rp2_flash.c
|
||||||
rp2_pio.c
|
rp2_pio.c
|
||||||
@ -473,6 +474,7 @@ target_compile_definitions(${MICROPY_TARGET} PRIVATE
|
|||||||
PICO_FLOAT_PROPAGATE_NANS=1
|
PICO_FLOAT_PROPAGATE_NANS=1
|
||||||
PICO_STACK_SIZE=0x2000
|
PICO_STACK_SIZE=0x2000
|
||||||
PICO_CORE1_STACK_SIZE=0
|
PICO_CORE1_STACK_SIZE=0
|
||||||
|
PICO_MAX_SHARED_IRQ_HANDLERS=8 # we need more than the default
|
||||||
PICO_PROGRAM_NAME="MicroPython"
|
PICO_PROGRAM_NAME="MicroPython"
|
||||||
PICO_NO_PROGRAM_VERSION_STRING=1 # do it ourselves in main.c
|
PICO_NO_PROGRAM_VERSION_STRING=1 # do it ourselves in main.c
|
||||||
MICROPY_BUILD_TYPE="${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION} ${CMAKE_BUILD_TYPE}"
|
MICROPY_BUILD_TYPE="${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION} ${CMAKE_BUILD_TYPE}"
|
||||||
|
@ -232,20 +232,18 @@ STATIC void feed_dma(machine_i2s_obj_t *self, uint8_t *dma_buffer_p) {
|
|||||||
|
|
||||||
STATIC void irq_configure(machine_i2s_obj_t *self) {
|
STATIC void irq_configure(machine_i2s_obj_t *self) {
|
||||||
if (self->i2s_id == 0) {
|
if (self->i2s_id == 0) {
|
||||||
irq_set_exclusive_handler(DMA_IRQ_0, dma_irq0_handler);
|
irq_add_shared_handler(DMA_IRQ_0, dma_irq0_handler, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
|
||||||
irq_set_enabled(DMA_IRQ_0, true);
|
irq_set_enabled(DMA_IRQ_0, true);
|
||||||
} else {
|
} else {
|
||||||
irq_set_exclusive_handler(DMA_IRQ_1, dma_irq1_handler);
|
irq_add_shared_handler(DMA_IRQ_1, dma_irq1_handler, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
|
||||||
irq_set_enabled(DMA_IRQ_1, true);
|
irq_set_enabled(DMA_IRQ_1, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
STATIC void irq_deinit(machine_i2s_obj_t *self) {
|
STATIC void irq_deinit(machine_i2s_obj_t *self) {
|
||||||
if (self->i2s_id == 0) {
|
if (self->i2s_id == 0) {
|
||||||
irq_set_enabled(DMA_IRQ_0, false);
|
|
||||||
irq_remove_handler(DMA_IRQ_0, dma_irq0_handler);
|
irq_remove_handler(DMA_IRQ_0, dma_irq0_handler);
|
||||||
} else {
|
} else {
|
||||||
irq_set_enabled(DMA_IRQ_1, false);
|
|
||||||
irq_remove_handler(DMA_IRQ_1, dma_irq1_handler);
|
irq_remove_handler(DMA_IRQ_1, dma_irq1_handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -483,7 +483,7 @@ STATIC mp_uint_t mp_machine_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mp_event_wait_ms(timeout - elapsed);
|
mp_event_handle_nowait();
|
||||||
}
|
}
|
||||||
*dest++ = ringbuf_get(&(self->read_buffer));
|
*dest++ = ringbuf_get(&(self->read_buffer));
|
||||||
start = mp_hal_ticks_ms(); // Inter-character timeout
|
start = mp_hal_ticks_ms(); // Inter-character timeout
|
||||||
@ -559,7 +559,7 @@ STATIC mp_uint_t mp_machine_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uint
|
|||||||
if (now >= timeout) {
|
if (now >= timeout) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mp_event_wait_ms((timeout - now) / 1000);
|
mp_event_handle_nowait();
|
||||||
}
|
}
|
||||||
*errcode = MP_ETIMEDOUT;
|
*errcode = MP_ETIMEDOUT;
|
||||||
ret = MP_STREAM_ERROR;
|
ret = MP_STREAM_ERROR;
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "py/mpthread.h"
|
#include "py/mpthread.h"
|
||||||
#include "pico/stdlib.h"
|
#include "pico/stdlib.h"
|
||||||
#include "pico/multicore.h"
|
#include "pico/multicore.h"
|
||||||
|
#include "mutex_extra.h"
|
||||||
|
|
||||||
#if MICROPY_PY_THREAD
|
#if MICROPY_PY_THREAD
|
||||||
|
|
||||||
@ -45,27 +46,23 @@ STATIC uint32_t *core1_stack = NULL;
|
|||||||
STATIC size_t core1_stack_num_words = 0;
|
STATIC size_t core1_stack_num_words = 0;
|
||||||
|
|
||||||
// Thread mutex.
|
// Thread mutex.
|
||||||
STATIC mp_thread_mutex_t atomic_mutex;
|
STATIC mutex_t atomic_mutex;
|
||||||
|
|
||||||
uint32_t mp_thread_begin_atomic_section(void) {
|
uint32_t mp_thread_begin_atomic_section(void) {
|
||||||
if (core1_entry) {
|
if (core1_entry) {
|
||||||
// When both cores are executing, we also need to provide
|
// When both cores are executing, we also need to provide
|
||||||
// full mutual exclusion.
|
// full mutual exclusion.
|
||||||
mp_thread_mutex_lock(&atomic_mutex, 1);
|
return mutex_enter_blocking_and_disable_interrupts(&atomic_mutex);
|
||||||
// In case this atomic section is for flash access, then
|
} else {
|
||||||
// suspend the other core.
|
|
||||||
multicore_lockout_start_blocking();
|
|
||||||
}
|
|
||||||
|
|
||||||
return save_and_disable_interrupts();
|
return save_and_disable_interrupts();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void mp_thread_end_atomic_section(uint32_t state) {
|
void mp_thread_end_atomic_section(uint32_t state) {
|
||||||
|
if (atomic_mutex.owner != LOCK_INVALID_OWNER_ID) {
|
||||||
|
mutex_exit_and_restore_interrupts(&atomic_mutex, state);
|
||||||
|
} else {
|
||||||
restore_interrupts(state);
|
restore_interrupts(state);
|
||||||
|
|
||||||
if (core1_entry) {
|
|
||||||
multicore_lockout_end_blocking();
|
|
||||||
mp_thread_mutex_unlock(&atomic_mutex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +70,7 @@ void mp_thread_end_atomic_section(uint32_t state) {
|
|||||||
void mp_thread_init(void) {
|
void mp_thread_init(void) {
|
||||||
assert(get_core_num() == 0);
|
assert(get_core_num() == 0);
|
||||||
|
|
||||||
mp_thread_mutex_init(&atomic_mutex);
|
mutex_init(&atomic_mutex);
|
||||||
|
|
||||||
// Allow MICROPY_BEGIN_ATOMIC_SECTION to be invoked from core1.
|
// Allow MICROPY_BEGIN_ATOMIC_SECTION to be invoked from core1.
|
||||||
multicore_lockout_victim_init();
|
multicore_lockout_victim_init();
|
||||||
|
30
ports/rp2/mutex_extra.c
Normal file
30
ports/rp2/mutex_extra.c
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mutex_extra.h"
|
||||||
|
|
||||||
|
// These functions are taken from lib/pico-sdk/src/common/pico_sync/mutex.c and modified
|
||||||
|
// so that they atomically obtain the mutex and disable interrupts.
|
||||||
|
|
||||||
|
uint32_t __time_critical_func(mutex_enter_blocking_and_disable_interrupts)(mutex_t * mtx) {
|
||||||
|
lock_owner_id_t caller = lock_get_caller_owner_id();
|
||||||
|
do {
|
||||||
|
uint32_t save = spin_lock_blocking(mtx->core.spin_lock);
|
||||||
|
if (!lock_is_owner_id_valid(mtx->owner)) {
|
||||||
|
mtx->owner = caller;
|
||||||
|
spin_unlock_unsafe(mtx->core.spin_lock);
|
||||||
|
return save;
|
||||||
|
}
|
||||||
|
lock_internal_spin_unlock_with_wait(&mtx->core, save);
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __time_critical_func(mutex_exit_and_restore_interrupts)(mutex_t * mtx, uint32_t save) {
|
||||||
|
spin_lock_unsafe_blocking(mtx->core.spin_lock);
|
||||||
|
assert(lock_is_owner_id_valid(mtx->owner));
|
||||||
|
mtx->owner = LOCK_INVALID_OWNER_ID;
|
||||||
|
lock_internal_spin_unlock_with_notify(&mtx->core, save);
|
||||||
|
}
|
34
ports/rp2/mutex_extra.h
Normal file
34
ports/rp2/mutex_extra.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the MicroPython project, http://micropython.org/
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 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_RP2_MUTEX_EXTRA_H
|
||||||
|
#define MICROPY_INCLUDED_RP2_MUTEX_EXTRA_H
|
||||||
|
|
||||||
|
#include "pico/mutex.h"
|
||||||
|
|
||||||
|
uint32_t mutex_enter_blocking_and_disable_interrupts(mutex_t *mtx);
|
||||||
|
void mutex_exit_and_restore_interrupts(mutex_t *mtx, uint32_t save);
|
||||||
|
|
||||||
|
#endif // MICROPY_INCLUDED_RP2_MUTEX_EXTRA_H
|
@ -86,7 +86,7 @@ STATIC const uint32_t rp2_dma_ctrl_field_count = MP_ARRAY_SIZE(rp2_dma_ctrl_fiel
|
|||||||
STATIC uint32_t rp2_dma_register_value_from_obj(mp_obj_t o, int reg_type) {
|
STATIC uint32_t rp2_dma_register_value_from_obj(mp_obj_t o, int reg_type) {
|
||||||
if (reg_type == REG_TYPE_ADDR_READ || reg_type == REG_TYPE_ADDR_WRITE) {
|
if (reg_type == REG_TYPE_ADDR_READ || reg_type == REG_TYPE_ADDR_WRITE) {
|
||||||
mp_buffer_info_t buf_info;
|
mp_buffer_info_t buf_info;
|
||||||
mp_uint_t flags = MP_BUFFER_READ;
|
mp_uint_t flags = (reg_type == REG_TYPE_ADDR_READ) ? MP_BUFFER_READ : MP_BUFFER_WRITE;
|
||||||
if (mp_get_buffer(o, &buf_info, flags)) {
|
if (mp_get_buffer(o, &buf_info, flags)) {
|
||||||
return (uint32_t)buf_info.buf;
|
return (uint32_t)buf_info.buf;
|
||||||
}
|
}
|
||||||
@ -98,18 +98,16 @@ STATIC uint32_t rp2_dma_register_value_from_obj(mp_obj_t o, int reg_type) {
|
|||||||
STATIC void rp2_dma_irq_handler(void) {
|
STATIC void rp2_dma_irq_handler(void) {
|
||||||
// Main IRQ handler
|
// Main IRQ handler
|
||||||
uint32_t irq_bits = dma_hw->ints0;
|
uint32_t irq_bits = dma_hw->ints0;
|
||||||
dma_hw->ints0 = 0xffff;
|
|
||||||
|
|
||||||
for (int i = 0; i < NUM_DMA_CHANNELS; i++) {
|
for (int i = 0; i < NUM_DMA_CHANNELS; i++) {
|
||||||
if (irq_bits & (1u << i)) {
|
if (irq_bits & (1u << i)) {
|
||||||
mp_irq_obj_t *handler = MP_STATE_PORT(rp2_dma_irq_obj[i]);
|
mp_irq_obj_t *handler = MP_STATE_PORT(rp2_dma_irq_obj[i]);
|
||||||
if (handler) {
|
if (handler) {
|
||||||
|
// An rp2.DMA IRQ handler is registered for this channel, so handle it.
|
||||||
|
dma_channel_acknowledge_irq0(i);
|
||||||
rp2_dma_obj_t *self = (rp2_dma_obj_t *)handler->parent;
|
rp2_dma_obj_t *self = (rp2_dma_obj_t *)handler->parent;
|
||||||
self->irq_flag = 1;
|
self->irq_flag = 1;
|
||||||
mp_irq_handler(handler);
|
mp_irq_handler(handler);
|
||||||
} else {
|
|
||||||
// We got an interrupt with no handler. Disable the channel
|
|
||||||
dma_channel_set_irq0_enabled(i, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -389,6 +387,9 @@ STATIC mp_obj_t rp2_dma_irq(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
|
|||||||
if (irq == NULL) {
|
if (irq == NULL) {
|
||||||
irq = mp_irq_new(&rp2_dma_irq_methods, MP_OBJ_FROM_PTR(self));
|
irq = mp_irq_new(&rp2_dma_irq_methods, MP_OBJ_FROM_PTR(self));
|
||||||
MP_STATE_PORT(rp2_dma_irq_obj[self->channel]) = irq;
|
MP_STATE_PORT(rp2_dma_irq_obj[self->channel]) = irq;
|
||||||
|
|
||||||
|
// Clear any existing IRQs on this DMA channel, they are not for us.
|
||||||
|
dma_channel_acknowledge_irq0(self->channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n_args > 1 || kw_args->used != 0) {
|
if (n_args > 1 || kw_args->used != 0) {
|
||||||
@ -457,12 +458,11 @@ MP_DEFINE_CONST_OBJ_TYPE(
|
|||||||
void rp2_dma_init(void) {
|
void rp2_dma_init(void) {
|
||||||
// Set up interrupts.
|
// Set up interrupts.
|
||||||
memset(MP_STATE_PORT(rp2_dma_irq_obj), 0, sizeof(MP_STATE_PORT(rp2_dma_irq_obj)));
|
memset(MP_STATE_PORT(rp2_dma_irq_obj), 0, sizeof(MP_STATE_PORT(rp2_dma_irq_obj)));
|
||||||
irq_set_exclusive_handler(DMA_IRQ_0, rp2_dma_irq_handler);
|
irq_add_shared_handler(DMA_IRQ_0, rp2_dma_irq_handler, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rp2_dma_deinit(void) {
|
void rp2_dma_deinit(void) {
|
||||||
// Disable and clear interrupts.
|
// Remove our interrupt handler.
|
||||||
irq_set_mask_enabled(1u << DMA_IRQ_0, false);
|
|
||||||
irq_remove_handler(DMA_IRQ_0, rp2_dma_irq_handler);
|
irq_remove_handler(DMA_IRQ_0, rp2_dma_irq_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,6 +70,22 @@ bi_decl(bi_block_device(
|
|||||||
BINARY_INFO_BLOCK_DEV_FLAG_WRITE |
|
BINARY_INFO_BLOCK_DEV_FLAG_WRITE |
|
||||||
BINARY_INFO_BLOCK_DEV_FLAG_PT_UNKNOWN));
|
BINARY_INFO_BLOCK_DEV_FLAG_PT_UNKNOWN));
|
||||||
|
|
||||||
|
// Flash erase and write must run with interrupts disabled and the other core suspended,
|
||||||
|
// because the XIP bit gets disabled.
|
||||||
|
static uint32_t begin_critical_flash_section(void) {
|
||||||
|
if (multicore_lockout_victim_is_initialized(1 - get_core_num())) {
|
||||||
|
multicore_lockout_start_blocking();
|
||||||
|
}
|
||||||
|
return save_and_disable_interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void end_critical_flash_section(uint32_t state) {
|
||||||
|
restore_interrupts(state);
|
||||||
|
if (multicore_lockout_victim_is_initialized(1 - get_core_num())) {
|
||||||
|
multicore_lockout_end_blocking();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
STATIC mp_obj_t rp2_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
STATIC mp_obj_t rp2_flash_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
|
||||||
// Parse arguments
|
// Parse arguments
|
||||||
enum { ARG_start, ARG_len };
|
enum { ARG_start, ARG_len };
|
||||||
@ -135,19 +151,17 @@ STATIC mp_obj_t rp2_flash_writeblocks(size_t n_args, const mp_obj_t *args) {
|
|||||||
mp_buffer_info_t bufinfo;
|
mp_buffer_info_t bufinfo;
|
||||||
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
|
mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ);
|
||||||
if (n_args == 3) {
|
if (n_args == 3) {
|
||||||
// Flash erase/program must run in an atomic section because the XIP bit gets disabled.
|
mp_uint_t atomic_state = begin_critical_flash_section();
|
||||||
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
|
|
||||||
flash_range_erase(self->flash_base + offset, bufinfo.len);
|
flash_range_erase(self->flash_base + offset, bufinfo.len);
|
||||||
MICROPY_END_ATOMIC_SECTION(atomic_state);
|
end_critical_flash_section(atomic_state);
|
||||||
mp_event_handle_nowait();
|
mp_event_handle_nowait();
|
||||||
// TODO check return value
|
// TODO check return value
|
||||||
} else {
|
} else {
|
||||||
offset += mp_obj_get_int(args[3]);
|
offset += mp_obj_get_int(args[3]);
|
||||||
}
|
}
|
||||||
// Flash erase/program must run in an atomic section because the XIP bit gets disabled.
|
mp_uint_t atomic_state = begin_critical_flash_section();
|
||||||
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
|
|
||||||
flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len);
|
flash_range_program(self->flash_base + offset, bufinfo.buf, bufinfo.len);
|
||||||
MICROPY_END_ATOMIC_SECTION(atomic_state);
|
end_critical_flash_section(atomic_state);
|
||||||
mp_event_handle_nowait();
|
mp_event_handle_nowait();
|
||||||
// TODO check return value
|
// TODO check return value
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
@ -170,10 +184,9 @@ STATIC mp_obj_t rp2_flash_ioctl(mp_obj_t self_in, mp_obj_t cmd_in, mp_obj_t arg_
|
|||||||
return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE_BYTES);
|
return MP_OBJ_NEW_SMALL_INT(BLOCK_SIZE_BYTES);
|
||||||
case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: {
|
case MP_BLOCKDEV_IOCTL_BLOCK_ERASE: {
|
||||||
uint32_t offset = mp_obj_get_int(arg_in) * BLOCK_SIZE_BYTES;
|
uint32_t offset = mp_obj_get_int(arg_in) * BLOCK_SIZE_BYTES;
|
||||||
// Flash erase/program must run in an atomic section because the XIP bit gets disabled.
|
mp_uint_t atomic_state = begin_critical_flash_section();
|
||||||
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
|
|
||||||
flash_range_erase(self->flash_base + offset, BLOCK_SIZE_BYTES);
|
flash_range_erase(self->flash_base + offset, BLOCK_SIZE_BYTES);
|
||||||
MICROPY_END_ATOMIC_SECTION(atomic_state);
|
end_critical_flash_section(atomic_state);
|
||||||
// TODO check return value
|
// TODO check return value
|
||||||
return MP_OBJ_NEW_SMALL_INT(0);
|
return MP_OBJ_NEW_SMALL_INT(0);
|
||||||
}
|
}
|
||||||
|
11
py/compile.c
11
py/compile.c
@ -1650,9 +1650,11 @@ STATIC void compile_try_except(compiler_t *comp, mp_parse_node_t pn_body, int n_
|
|||||||
if (qstr_exception_local != 0) {
|
if (qstr_exception_local != 0) {
|
||||||
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
|
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
|
||||||
EMIT_ARG(label_assign, l3);
|
EMIT_ARG(label_assign, l3);
|
||||||
|
EMIT_ARG(adjust_stack_size, 1); // stack adjust for possible return value
|
||||||
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
|
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
|
||||||
compile_store_id(comp, qstr_exception_local);
|
compile_store_id(comp, qstr_exception_local);
|
||||||
compile_delete_id(comp, qstr_exception_local);
|
compile_delete_id(comp, qstr_exception_local);
|
||||||
|
EMIT_ARG(adjust_stack_size, -1);
|
||||||
compile_decrease_except_level(comp);
|
compile_decrease_except_level(comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1682,9 +1684,18 @@ STATIC void compile_try_finally(compiler_t *comp, mp_parse_node_t pn_body, int n
|
|||||||
} else {
|
} else {
|
||||||
compile_try_except(comp, pn_body, n_except, pn_except, pn_else);
|
compile_try_except(comp, pn_body, n_except, pn_except, pn_else);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the code reaches this point then the try part of the try-finally exited normally.
|
||||||
|
// This is indicated to the runtime by None sitting on the stack.
|
||||||
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
|
EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
|
||||||
|
|
||||||
|
// Compile the finally block.
|
||||||
|
// The stack needs to be adjusted by 1 to account for the possibility that the finally is
|
||||||
|
// being executed as part of a return, and the return value is on the top of the stack.
|
||||||
EMIT_ARG(label_assign, l_finally_block);
|
EMIT_ARG(label_assign, l_finally_block);
|
||||||
|
EMIT_ARG(adjust_stack_size, 1);
|
||||||
compile_node(comp, pn_finally);
|
compile_node(comp, pn_finally);
|
||||||
|
EMIT_ARG(adjust_stack_size, -1);
|
||||||
|
|
||||||
compile_decrease_except_level(comp);
|
compile_decrease_except_level(comp);
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
// are unavailable.
|
// are unavailable.
|
||||||
#define MICROPY_VERSION_MAJOR 1
|
#define MICROPY_VERSION_MAJOR 1
|
||||||
#define MICROPY_VERSION_MINOR 22
|
#define MICROPY_VERSION_MINOR 22
|
||||||
#define MICROPY_VERSION_MICRO 0
|
#define MICROPY_VERSION_MICRO 2
|
||||||
#define MICROPY_VERSION_PRERELEASE 0
|
#define MICROPY_VERSION_PRERELEASE 0
|
||||||
|
|
||||||
// Combined version as a 32-bit number for convenience to allow version
|
// Combined version as a 32-bit number for convenience to allow version
|
||||||
|
@ -70,3 +70,13 @@ def f():
|
|||||||
finally:
|
finally:
|
||||||
print('finally 1')
|
print('finally 1')
|
||||||
print(f())
|
print(f())
|
||||||
|
|
||||||
|
# the finally block uses a lot of Python stack and then a local is accessed
|
||||||
|
# (tests that the use of the stack doesn't clobber the local)
|
||||||
|
def f(x):
|
||||||
|
try:
|
||||||
|
return x
|
||||||
|
finally:
|
||||||
|
print(2, 3, 4, 5, 6)
|
||||||
|
print(x)
|
||||||
|
print(f(1))
|
||||||
|
65
tests/extmod/asyncio_gather_finished_early.py
Normal file
65
tests/extmod/asyncio_gather_finished_early.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# Test asyncio.gather() when a task is already finished before the gather starts.
|
||||||
|
|
||||||
|
try:
|
||||||
|
import asyncio
|
||||||
|
except ImportError:
|
||||||
|
print("SKIP")
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
|
|
||||||
|
# CPython and MicroPython differ in when they signal (and print) that a task raised an
|
||||||
|
# uncaught exception. So define an empty custom_handler() to suppress this output.
|
||||||
|
def custom_handler(loop, context):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
async def task_that_finishes_early(id, event, fail):
|
||||||
|
print("task_that_finishes_early", id)
|
||||||
|
event.set()
|
||||||
|
if fail:
|
||||||
|
raise ValueError("intentional exception", id)
|
||||||
|
|
||||||
|
|
||||||
|
async def task_that_runs():
|
||||||
|
for i in range(5):
|
||||||
|
print("task_that_runs", i)
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
|
||||||
|
|
||||||
|
async def main(start_task_that_runs, task_fail, return_exceptions):
|
||||||
|
print("== start", start_task_that_runs, task_fail, return_exceptions)
|
||||||
|
|
||||||
|
# Set exception handler to suppress exception output.
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.set_exception_handler(custom_handler)
|
||||||
|
|
||||||
|
# Create tasks.
|
||||||
|
event_a = asyncio.Event()
|
||||||
|
event_b = asyncio.Event()
|
||||||
|
tasks = []
|
||||||
|
if start_task_that_runs:
|
||||||
|
tasks.append(asyncio.create_task(task_that_runs()))
|
||||||
|
tasks.append(asyncio.create_task(task_that_finishes_early("a", event_a, task_fail)))
|
||||||
|
tasks.append(asyncio.create_task(task_that_finishes_early("b", event_b, task_fail)))
|
||||||
|
|
||||||
|
# Make sure task_that_finishes_early() are both done, before calling gather().
|
||||||
|
await event_a.wait()
|
||||||
|
await event_b.wait()
|
||||||
|
|
||||||
|
# Gather the tasks.
|
||||||
|
try:
|
||||||
|
result = "complete", await asyncio.gather(*tasks, return_exceptions=return_exceptions)
|
||||||
|
except Exception as er:
|
||||||
|
result = "exception", er, start_task_that_runs and tasks[0].done()
|
||||||
|
|
||||||
|
# Wait for the final task to finish (if it was started).
|
||||||
|
if start_task_that_runs:
|
||||||
|
await tasks[0]
|
||||||
|
|
||||||
|
# Print results.
|
||||||
|
print(result)
|
||||||
|
|
||||||
|
|
||||||
|
# Run the test in the 8 different combinations of its arguments.
|
||||||
|
for i in range(8):
|
||||||
|
asyncio.run(main(bool(i & 4), bool(i & 2), bool(i & 1)))
|
@ -12,6 +12,8 @@ ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|||||||
ciphers = ctx.get_ciphers()
|
ciphers = ctx.get_ciphers()
|
||||||
|
|
||||||
for ci in ciphers:
|
for ci in ciphers:
|
||||||
|
# Only print those ciphers know to exist on all ports.
|
||||||
|
if ("TLS-ECDHE-ECDSA-WITH-AES" in ci or "TLS-RSA-WITH-AES" in ci) and "CBC" in ci:
|
||||||
print(ci)
|
print(ci)
|
||||||
|
|
||||||
ctx.set_ciphers(ciphers[:1])
|
ctx.set_ciphers(ciphers[:1])
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384
|
TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384
|
||||||
|
TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA
|
||||||
TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256
|
TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256
|
||||||
|
TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA
|
||||||
TLS-RSA-WITH-AES-256-CBC-SHA256
|
TLS-RSA-WITH-AES-256-CBC-SHA256
|
||||||
|
TLS-RSA-WITH-AES-256-CBC-SHA
|
||||||
TLS-RSA-WITH-AES-128-CBC-SHA256
|
TLS-RSA-WITH-AES-128-CBC-SHA256
|
||||||
|
TLS-RSA-WITH-AES-128-CBC-SHA
|
||||||
object 'str' isn't a tuple or list
|
object 'str' isn't a tuple or list
|
||||||
(-24192, 'MBEDTLS_ERR_SSL_BAD_CONFIG')
|
(-24192, 'MBEDTLS_ERR_SSL_BAD_CONFIG')
|
||||||
|
206
tests/multi_bluetooth/ble_irq_calls.py
Normal file
206
tests/multi_bluetooth/ble_irq_calls.py
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
# Test calling BLE methods from within the BLE.irq event handler.
|
||||||
|
|
||||||
|
from micropython import const
|
||||||
|
import struct
|
||||||
|
import time
|
||||||
|
import bluetooth
|
||||||
|
|
||||||
|
_IRQ_CENTRAL_CONNECT = const(1)
|
||||||
|
_IRQ_CENTRAL_DISCONNECT = const(2)
|
||||||
|
_IRQ_PERIPHERAL_CONNECT = const(7)
|
||||||
|
_IRQ_PERIPHERAL_DISCONNECT = const(8)
|
||||||
|
_IRQ_GATTC_SERVICE_RESULT = const(9)
|
||||||
|
_IRQ_GATTC_SERVICE_DONE = const(10)
|
||||||
|
_IRQ_GATTC_CHARACTERISTIC_RESULT = const(11)
|
||||||
|
_IRQ_GATTC_CHARACTERISTIC_DONE = const(12)
|
||||||
|
_IRQ_GATTC_DESCRIPTOR_RESULT = const(13)
|
||||||
|
_IRQ_GATTC_DESCRIPTOR_DONE = const(14)
|
||||||
|
_IRQ_GATTC_READ_RESULT = const(15)
|
||||||
|
_IRQ_GATTC_READ_DONE = const(16)
|
||||||
|
_IRQ_GATTC_WRITE_DONE = const(17)
|
||||||
|
_IRQ_MTU_EXCHANGED = const(21)
|
||||||
|
_IRQ_GET_SECRET = const(29)
|
||||||
|
_IRQ_SET_SECRET = const(30)
|
||||||
|
|
||||||
|
EVENT_NAMES = {
|
||||||
|
1: "_IRQ_CENTRAL_CONNECT",
|
||||||
|
2: "_IRQ_CENTRAL_DISCONNECT",
|
||||||
|
3: "_IRQ_GATTS_WRITE",
|
||||||
|
4: "_IRQ_GATTS_READ_REQUEST",
|
||||||
|
7: "_IRQ_PERIPHERAL_CONNECT",
|
||||||
|
8: "_IRQ_PERIPHERAL_DISCONNECT",
|
||||||
|
9: "_IRQ_GATTC_SERVICE_RESULT",
|
||||||
|
10: "_IRQ_GATTC_SERVICE_DONE",
|
||||||
|
11: "_IRQ_GATTC_CHARACTERISTIC_RESULT",
|
||||||
|
12: "_IRQ_GATTC_CHARACTERISTIC_DONE",
|
||||||
|
13: "_IRQ_GATTC_DESCRIPTOR_RESULT",
|
||||||
|
14: "_IRQ_GATTC_DESCRIPTOR_DONE",
|
||||||
|
15: "_IRQ_GATTC_READ_RESULT",
|
||||||
|
16: "_IRQ_GATTC_READ_DONE",
|
||||||
|
17: "_IRQ_GATTC_WRITE_DONE",
|
||||||
|
18: "_IRQ_GATTC_NOTIFY",
|
||||||
|
21: "_IRQ_MTU_EXCHANGED",
|
||||||
|
}
|
||||||
|
|
||||||
|
_ADV_TYPE_FLAGS = const(0x01)
|
||||||
|
_ADV_TYPE_NAME = const(0x09)
|
||||||
|
_ADV_TYPE_UUID128_COMPLETE = const(0x7)
|
||||||
|
|
||||||
|
_NOTIFY_ENABLE = const(1)
|
||||||
|
|
||||||
|
ACCESSORY_UUID = bluetooth.UUID("a5a5a5a5-ffff-9999-1111-5a5a5a5a5a5a")
|
||||||
|
STATE_UUID = bluetooth.UUID("a5a5a5a5-eeee-9999-1111-5a5a5a5a5a5a")
|
||||||
|
CCC_UUID = bluetooth.UUID(0x2902)
|
||||||
|
|
||||||
|
STATE_CHARACTERISTIC = (
|
||||||
|
STATE_UUID,
|
||||||
|
bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,
|
||||||
|
)
|
||||||
|
|
||||||
|
ACCESSORY_SERVICE = (ACCESSORY_UUID, (STATE_CHARACTERISTIC,))
|
||||||
|
|
||||||
|
|
||||||
|
class Central:
|
||||||
|
def __init__(self):
|
||||||
|
self.done = False
|
||||||
|
self._conn_handle = None
|
||||||
|
self._service = None
|
||||||
|
self._characteristic_handle = None
|
||||||
|
self._cccd_handle = None
|
||||||
|
self._reads_remaining = None
|
||||||
|
ble.active(1)
|
||||||
|
ble.irq(self._ble_event_handler)
|
||||||
|
ble.gap_connect(*BDADDR)
|
||||||
|
|
||||||
|
def _ble_event_handler(self, event, data):
|
||||||
|
print(EVENT_NAMES[event])
|
||||||
|
|
||||||
|
if event == _IRQ_PERIPHERAL_CONNECT:
|
||||||
|
conn_handle, _, _ = data
|
||||||
|
self._conn_handle = conn_handle
|
||||||
|
ble.gattc_discover_services(self._conn_handle, ACCESSORY_UUID)
|
||||||
|
|
||||||
|
elif event == _IRQ_PERIPHERAL_DISCONNECT:
|
||||||
|
conn_handle, _, addr = data
|
||||||
|
assert self._conn_handle == conn_handle
|
||||||
|
self._conn_handle = None
|
||||||
|
print("connection closed")
|
||||||
|
|
||||||
|
elif event == _IRQ_GATTC_SERVICE_RESULT:
|
||||||
|
_, first_handle, last_handle, uuid = data
|
||||||
|
print("service found:", last_handle - first_handle, uuid)
|
||||||
|
if uuid == ACCESSORY_UUID:
|
||||||
|
assert self._service is None
|
||||||
|
self._service = (first_handle, last_handle)
|
||||||
|
|
||||||
|
elif event == _IRQ_GATTC_SERVICE_DONE:
|
||||||
|
print("service handle range:", self._service[1] - self._service[0])
|
||||||
|
start_handle, end_handle = self._service
|
||||||
|
ble.gattc_discover_characteristics(self._conn_handle, start_handle, end_handle)
|
||||||
|
|
||||||
|
elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:
|
||||||
|
_, end_handle, value_handle, properties, uuid = data
|
||||||
|
assert uuid == STATE_UUID
|
||||||
|
print("characteristic found:", uuid)
|
||||||
|
assert self._characteristic_handle is None
|
||||||
|
self._characteristic_handle = value_handle
|
||||||
|
|
||||||
|
elif event == _IRQ_GATTC_CHARACTERISTIC_DONE:
|
||||||
|
start_handle, end_handle = self._service
|
||||||
|
ble.gattc_discover_descriptors(self._conn_handle, start_handle, end_handle)
|
||||||
|
|
||||||
|
elif event == _IRQ_GATTC_DESCRIPTOR_RESULT:
|
||||||
|
_, dsc_handle, uuid = data
|
||||||
|
if uuid == CCC_UUID:
|
||||||
|
print("CCCD found:", uuid)
|
||||||
|
assert self._cccd_handle is None
|
||||||
|
self._cccd_handle = dsc_handle
|
||||||
|
|
||||||
|
elif event == _IRQ_GATTC_DESCRIPTOR_DONE:
|
||||||
|
# Discovery complete, proceed to MTU exchange.
|
||||||
|
ble.gattc_exchange_mtu(self._conn_handle)
|
||||||
|
|
||||||
|
elif event == _IRQ_MTU_EXCHANGED:
|
||||||
|
# MTU exchanged, proceed to enable CCCD.
|
||||||
|
print("CCCD write")
|
||||||
|
ble.gattc_write(
|
||||||
|
self._conn_handle, self._cccd_handle, struct.pack("<h", _NOTIFY_ENABLE), 1
|
||||||
|
)
|
||||||
|
|
||||||
|
elif event == _IRQ_GATTC_WRITE_DONE:
|
||||||
|
conn_handle, _, result = data
|
||||||
|
print("CCCD write result:", result)
|
||||||
|
print("issue gattc_read")
|
||||||
|
self._reads_remaining = 2
|
||||||
|
ble.gattc_read(self._conn_handle, self._characteristic_handle)
|
||||||
|
|
||||||
|
elif event == _IRQ_GATTC_READ_RESULT:
|
||||||
|
_, _, char_data = data
|
||||||
|
print("gattc_read result:", bytes(char_data))
|
||||||
|
|
||||||
|
elif event == _IRQ_GATTC_READ_DONE:
|
||||||
|
self._reads_remaining -= 1
|
||||||
|
if self._reads_remaining > 0:
|
||||||
|
ble.gattc_read(self._conn_handle, self._characteristic_handle)
|
||||||
|
else:
|
||||||
|
self.done = True
|
||||||
|
ble.gap_disconnect(self._conn_handle)
|
||||||
|
|
||||||
|
|
||||||
|
class Peripheral:
|
||||||
|
def __init__(self):
|
||||||
|
self.done = False
|
||||||
|
ble.active(1)
|
||||||
|
ble.irq(self._ble_event_handler)
|
||||||
|
ble.gatts_register_services((ACCESSORY_SERVICE,))
|
||||||
|
add_payload = self.advertising_payload("acc", (ACCESSORY_UUID,))
|
||||||
|
ble.gap_advertise(500000, add_payload)
|
||||||
|
|
||||||
|
def advertising_payload(self, name, services):
|
||||||
|
payload = bytearray()
|
||||||
|
|
||||||
|
def _append(adv_type, value):
|
||||||
|
nonlocal payload
|
||||||
|
payload.extend(struct.pack("BB", len(value) + 1, adv_type) + value)
|
||||||
|
|
||||||
|
_append(_ADV_TYPE_FLAGS, struct.pack("B", 0x02 + 0x04))
|
||||||
|
_append(_ADV_TYPE_NAME, name)
|
||||||
|
|
||||||
|
for uuid in services:
|
||||||
|
b = bytes(uuid)
|
||||||
|
assert len(b) == 16
|
||||||
|
_append(_ADV_TYPE_UUID128_COMPLETE, b)
|
||||||
|
|
||||||
|
return payload
|
||||||
|
|
||||||
|
def _ble_event_handler(self, event, data):
|
||||||
|
if event not in (_IRQ_GET_SECRET, _IRQ_SET_SECRET):
|
||||||
|
print(EVENT_NAMES[event])
|
||||||
|
if event == _IRQ_CENTRAL_DISCONNECT:
|
||||||
|
self.done = True
|
||||||
|
|
||||||
|
|
||||||
|
# Acting in peripheral role.
|
||||||
|
def instance0():
|
||||||
|
print("peripheral start")
|
||||||
|
peripheral = Peripheral()
|
||||||
|
multitest.globals(BDADDR=ble.config("mac"))
|
||||||
|
multitest.next()
|
||||||
|
while not peripheral.done:
|
||||||
|
time.sleep_ms(100)
|
||||||
|
multitest.broadcast("finished")
|
||||||
|
ble.active(0)
|
||||||
|
|
||||||
|
|
||||||
|
# Acting in central role.
|
||||||
|
def instance1():
|
||||||
|
print("central start")
|
||||||
|
multitest.next()
|
||||||
|
central = Central()
|
||||||
|
while not central.done:
|
||||||
|
time.sleep_ms(100)
|
||||||
|
multitest.wait("finished")
|
||||||
|
ble.active(0)
|
||||||
|
|
||||||
|
|
||||||
|
ble = bluetooth.BLE()
|
35
tests/multi_bluetooth/ble_irq_calls.py.exp
Normal file
35
tests/multi_bluetooth/ble_irq_calls.py.exp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
--- instance0 ---
|
||||||
|
peripheral start
|
||||||
|
_IRQ_CENTRAL_CONNECT
|
||||||
|
_IRQ_MTU_EXCHANGED
|
||||||
|
_IRQ_GATTS_READ_REQUEST
|
||||||
|
_IRQ_GATTS_READ_REQUEST
|
||||||
|
_IRQ_CENTRAL_DISCONNECT
|
||||||
|
--- instance1 ---
|
||||||
|
central start
|
||||||
|
_IRQ_PERIPHERAL_CONNECT
|
||||||
|
_IRQ_GATTC_SERVICE_RESULT
|
||||||
|
service found: 3 UUID('a5a5a5a5-ffff-9999-1111-5a5a5a5a5a5a')
|
||||||
|
_IRQ_GATTC_SERVICE_DONE
|
||||||
|
service handle range: 3
|
||||||
|
_IRQ_GATTC_CHARACTERISTIC_RESULT
|
||||||
|
characteristic found: UUID('a5a5a5a5-eeee-9999-1111-5a5a5a5a5a5a')
|
||||||
|
_IRQ_GATTC_CHARACTERISTIC_DONE
|
||||||
|
_IRQ_GATTC_DESCRIPTOR_RESULT
|
||||||
|
_IRQ_GATTC_DESCRIPTOR_RESULT
|
||||||
|
_IRQ_GATTC_DESCRIPTOR_RESULT
|
||||||
|
CCCD found: UUID(0x2902)
|
||||||
|
_IRQ_GATTC_DESCRIPTOR_DONE
|
||||||
|
_IRQ_MTU_EXCHANGED
|
||||||
|
CCCD write
|
||||||
|
_IRQ_GATTC_WRITE_DONE
|
||||||
|
CCCD write result: 0
|
||||||
|
issue gattc_read
|
||||||
|
_IRQ_GATTC_READ_RESULT
|
||||||
|
gattc_read result: b''
|
||||||
|
_IRQ_GATTC_READ_DONE
|
||||||
|
_IRQ_GATTC_READ_RESULT
|
||||||
|
gattc_read result: b''
|
||||||
|
_IRQ_GATTC_READ_DONE
|
||||||
|
_IRQ_PERIPHERAL_DISCONNECT
|
||||||
|
connection closed
|
Loading…
x
Reference in New Issue
Block a user