Skip to content

Commit 9a495b9

Browse files
committed
pybricks.iodevices.I2CDevice: Save state only after success.
A user could inadvertently make another async I2C request, but we don't allow this if another operation is ongoing. So we shouldn't override the state in this case.
1 parent cde1558 commit 9a495b9

File tree

1 file changed

+15
-6
lines changed

1 file changed

+15
-6
lines changed

pybricks/iodevices/pb_type_iodevices_i2cdevice.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,20 +162,22 @@ static mp_obj_t write_then_read(size_t n_args, const mp_obj_t *pos_args, mp_map_
162162

163163
// Pre-allocate the return value so we have something to write the result to.
164164
size_t len = pb_obj_get_positive_int(read_length_in);
165+
mp_obj_str_t *read_result;
165166
if (len) {
166-
self->read_result = mp_obj_new_bytes(NULL, len);
167-
self->read_result->hash = 0;
168-
self->read_result->data = m_new(byte, self->read_result->len);
167+
read_result = mp_obj_new_bytes(NULL, len);
168+
read_result->hash = 0;
169+
read_result->data = m_new(byte, read_result->len);
169170
} else {
170-
self->read_result = (mp_obj_str_t *)&mp_const_empty_bytes_obj;
171+
read_result = (mp_obj_str_t *)&mp_const_empty_bytes_obj;
171172
}
172173

173174
// Kick off the operation. This will immediately raise if a transaction is
174175
// in progress.
176+
pbio_os_state_t state = 0;
175177
pbio_error_t err = pbdrv_i2c_write_then_read(
176-
&self->state, self->i2c_dev, self->address,
178+
&state, self->i2c_dev, self->address,
177179
write_data, self->write_len,
178-
(uint8_t *)self->read_result->data, self->read_result->len, self->nxt_quirk);
180+
(uint8_t *)read_result->data, read_result->len, self->nxt_quirk);
179181

180182
// Expect yield after the initial call.
181183
if (err == PBIO_SUCCESS) {
@@ -184,6 +186,13 @@ static mp_obj_t write_then_read(size_t n_args, const mp_obj_t *pos_args, mp_map_
184186
pb_assert(err);
185187
}
186188

189+
// The initial operation above can fail if an I2C transaction is already in
190+
// progress. If so, we don't want to reset it state or allow the return
191+
// result to be garbage collected. Now that the first iteration succeeded,
192+
// save the state and assign the new result buffer.
193+
self->state = state;
194+
self->read_result = read_result;
195+
187196
// If runloop active, return an awaitable object.
188197
if (pb_module_tools_run_loop_is_active()) {
189198
operation_obj_t *operation = mp_obj_malloc(operation_obj_t, &operation_type);

0 commit comments

Comments
 (0)