1313#include <pbio/port_interface.h>
1414
1515#include <pybricks/common.h>
16+ #include <pybricks/iodevices/iodevices.h>
1617#include <pybricks/parameters.h>
1718
1819#include <pybricks/util_mp/pb_kwarg_helper.h>
1920#include <pybricks/util_mp/pb_obj_helper.h>
2021
2122#include <pybricks/util_pb/pb_error.h>
2223
23- typedef struct _device_obj_t device_obj_t ;
24-
25- /**
26- * Given a completed I2C operation, maps the resulting read buffer to an object
27- * of a desired form. For example, it could map two bytes to a single floating
28- * point value representing temperature.
29- *
30- * @param [in] device The device object.
31- */
32- typedef mp_obj_t (* return_map_t )(device_obj_t * device );
33-
3424// Object representing a pybricks.iodevices.I2CDevice instance.
35- struct _device_obj_t {
25+ typedef struct {
3626 mp_obj_base_t base ;
3727 /**
3828 * The following are buffered parameters for one ongoing I2C operation, See
@@ -45,21 +35,14 @@ struct _device_obj_t {
4535 pbio_os_state_t state ;
4636 uint8_t address ;
4737 bool nxt_quirk ;
48- return_map_t return_map ;
38+ pb_type_i2c_device_return_map_t return_map ;
4939 size_t write_len ;
5040 size_t read_len ;
5141 uint8_t * read_buf ;
52- };
42+ } device_obj_t ;
5343
5444// pybricks.iodevices.I2CDevice.__init__
55- static mp_obj_t make_new (const mp_obj_type_t * type , size_t n_args , size_t n_kw , const mp_obj_t * args ) {
56- PB_PARSE_ARGS_CLASS (n_args , n_kw , args ,
57- PB_ARG_REQUIRED (port ),
58- PB_ARG_REQUIRED (address ),
59- PB_ARG_DEFAULT_FALSE (custom ),
60- PB_ARG_DEFAULT_FALSE (powered ),
61- PB_ARG_DEFAULT_FALSE (nxt_quirk )
62- );
45+ mp_obj_t pb_type_i2c_device_make_new (mp_obj_t port_in , mp_obj_t address_in , bool custom , bool powered , bool nxt_quirk ) {
6346
6447 pb_module_tools_assert_blocking ();
6548
@@ -69,7 +52,7 @@ static mp_obj_t make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
6952 pb_assert (pbio_port_get_port (port_id , & port ));
7053
7154 // Set the port mode to LEGO DCM or raw I2C mode.
72- pbio_error_t err = pbio_port_set_mode (port , mp_obj_is_true ( custom_in ) ? PBIO_PORT_MODE_I2C : PBIO_PORT_MODE_LEGO_DCM );
55+ pbio_error_t err = pbio_port_set_mode (port , custom ? PBIO_PORT_MODE_I2C : PBIO_PORT_MODE_LEGO_DCM );
7356 if (err == PBIO_ERROR_AGAIN ) {
7457 // If coming from a different mode, give port some time to get started.
7558 // This happens when the user has a custom device and decides to switch
@@ -82,17 +65,30 @@ static mp_obj_t make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
8265 pbdrv_i2c_dev_t * i2c_dev ;
8366 pb_assert (pbio_port_get_i2c_dev (port , & i2c_dev ));
8467
85- device_obj_t * device = mp_obj_malloc (device_obj_t , type );
68+ device_obj_t * device = mp_obj_malloc (device_obj_t , & pb_type_i2c_device );
8669 device -> i2c_dev = i2c_dev ;
8770 device -> address = mp_obj_get_int (address_in );
88- device -> nxt_quirk = mp_obj_is_true ( nxt_quirk_in ) ;
89- if (mp_obj_is_true ( powered_in ) ) {
71+ device -> nxt_quirk = nxt_quirk ;
72+ if (powered ) {
9073 pbio_port_p1p2_set_power (port , PBIO_PORT_POWER_REQUIREMENTS_BATTERY_VOLTAGE_P1_POS );
9174 }
9275
9376 return MP_OBJ_FROM_PTR (device );
9477}
9578
79+ // wrapper to parse args for __init__
80+ static mp_obj_t make_new (const mp_obj_type_t * type , size_t n_args , size_t n_kw , const mp_obj_t * args ) {
81+ PB_PARSE_ARGS_CLASS (n_args , n_kw , args ,
82+ PB_ARG_REQUIRED (port ),
83+ PB_ARG_REQUIRED (address ),
84+ PB_ARG_DEFAULT_FALSE (custom ),
85+ PB_ARG_DEFAULT_FALSE (powered ),
86+ PB_ARG_DEFAULT_FALSE (nxt_quirk )
87+ );
88+
89+ return pb_type_i2c_device_make_new (port_in , address_in , mp_obj_is_true (custom_in ), mp_obj_is_true (powered_in ), mp_obj_is_true (nxt_quirk_in ));
90+ }
91+
9692// Object representing the iterable that is returned when calling an I2C
9793// method. This object can then be awaited (iterated). It has a reference to
9894// the device from which it was created. Only one operation can be active at
@@ -142,7 +138,7 @@ static mp_obj_t operation_iternext(mp_obj_t op_in) {
142138 }
143139
144140 // Set return value via stop iteration.
145- return mp_make_stop_iteration (device -> return_map (device ));
141+ return mp_make_stop_iteration (device -> return_map (device -> read_buf , device -> read_len ));
146142}
147143
148144static const mp_rom_map_elem_t operation_locals_dict_table [] = {
@@ -156,7 +152,10 @@ MP_DEFINE_CONST_OBJ_TYPE(operation_type,
156152 iter , operation_iternext ,
157153 locals_dict , & operation_locals_dict );
158154
159- static mp_obj_t start_operation (device_obj_t * device , const uint8_t * write_data , size_t write_len , size_t read_len , return_map_t return_map ) {
155+ mp_obj_t pb_type_i2c_device_start_operation (mp_obj_t i2c_device_obj , const uint8_t * write_data , size_t write_len , size_t read_len , pb_type_i2c_device_return_map_t return_map ) {
156+
157+ pb_assert_type (i2c_device_obj , & pb_type_i2c_device );
158+ device_obj_t * device = MP_OBJ_TO_PTR (i2c_device_obj );
160159
161160 // Kick off the operation. This will immediately raise if a transaction is
162161 // in progress.
@@ -200,12 +199,7 @@ static mp_obj_t start_operation(device_obj_t *device, const uint8_t *write_data,
200199 if (!device -> return_map ) {
201200 return mp_const_none ;
202201 }
203- return device -> return_map (device );
204- }
205-
206- static mp_obj_t return_map_bytes (device_obj_t * device ) {
207- // Operation was successfull, so data is not NULL if read len is nonzero.
208- return mp_obj_new_bytes (device -> read_buf , device -> read_len );
202+ return device -> return_map (device -> read_buf , device -> read_len );
209203}
210204
211205// pybricks.iodevices.I2CDevice.write_then_read
@@ -217,7 +211,7 @@ static mp_obj_t write_then_read(size_t n_args, const mp_obj_t *pos_args, mp_map_
217211 );
218212
219213 size_t write_len ;
220- return start_operation ( device , (const uint8_t * )mp_obj_str_get_data (write_data_in , & write_len ), write_len , pb_obj_get_positive_int (read_length_in ), return_map_bytes );
214+ return pb_type_i2c_device_start_operation ( MP_OBJ_FROM_PTR ( device ) , (const uint8_t * )mp_obj_str_get_data (write_data_in , & write_len ), write_len , pb_obj_get_positive_int (read_length_in ), mp_obj_new_bytes );
221215}
222216static MP_DEFINE_CONST_FUN_OBJ_KW (write_then_read_obj , 0 , write_then_read ) ;
223217
@@ -236,7 +230,7 @@ static mp_obj_t read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
236230 & (uint8_t ) { mp_obj_get_int (reg_in ) };
237231 size_t write_len = reg_in == mp_const_none ? 0 : 1 ;
238232
239- return start_operation ( device , write_data , write_len , pb_obj_get_positive_int (length_in ), return_map_bytes );
233+ return pb_type_i2c_device_start_operation ( MP_OBJ_FROM_PTR ( device ) , write_data , write_len , pb_obj_get_positive_int (length_in ), mp_obj_new_bytes );
240234}
241235static MP_DEFINE_CONST_FUN_OBJ_KW (read_obj , 0 , read ) ;
242236
@@ -259,7 +253,7 @@ static mp_obj_t write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args
259253
260254 // No register given, write data as is.
261255 if (reg_in == mp_const_none ) {
262- return start_operation ( device , (const uint8_t * )user_data , user_len , 0 , NULL );
256+ return pb_type_i2c_device_start_operation ( MP_OBJ_FROM_PTR ( device ) , (const uint8_t * )user_data , user_len , 0 , NULL );
263257 }
264258
265259 // Otherwise need to prefix write data with given register.
@@ -270,7 +264,7 @@ static mp_obj_t write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args
270264 write_data [0 ] = pb_obj_get_positive_int (reg_in );
271265 memcpy (& write_data [1 ], user_data , user_len );
272266
273- return start_operation ( device , write_data , user_len + 1 , 0 , NULL );
267+ return pb_type_i2c_device_start_operation ( MP_OBJ_FROM_PTR ( device ) , write_data , user_len + 1 , 0 , NULL );
274268}
275269static MP_DEFINE_CONST_FUN_OBJ_KW (write_obj , 0 , write ) ;
276270
0 commit comments