1 | /* |
2 | * This file is part of the MicroPython project, http://micropython.org/ |
3 | * |
4 | * The MIT License (MIT) |
5 | * |
6 | * Copyright (c) 2014-2018 Paul Sokolovsky |
7 | * |
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
9 | * of this software and associated documentation files (the "Software"), to deal |
10 | * in the Software without restriction, including without limitation the rights |
11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
12 | * copies of the Software, and to permit persons to whom the Software is |
13 | * furnished to do so, subject to the following conditions: |
14 | * |
15 | * The above copyright notice and this permission notice shall be included in |
16 | * all copies or substantial portions of the Software. |
17 | * |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
24 | * THE SOFTWARE. |
25 | */ |
26 | |
27 | #include <assert.h> |
28 | #include <string.h> |
29 | #include <stdint.h> |
30 | |
31 | #include "py/runtime.h" |
32 | #include "py/objtuple.h" |
33 | #include "py/binary.h" |
34 | |
35 | #if MICROPY_PY_UCTYPES |
36 | |
37 | /// \module uctypes - Access data structures in memory |
38 | /// |
39 | /// The module allows to define layout of raw data structure (using terms |
40 | /// of C language), and then access memory buffers using this definition. |
41 | /// The module also provides convenience functions to access memory buffers |
42 | /// contained in Python objects or wrap memory buffers in Python objects. |
43 | /// \constant UINT8_1 - uint8_t value type |
44 | |
45 | /// \class struct - C-like structure |
46 | /// |
47 | /// Encapsulalation of in-memory data structure. This class doesn't define |
48 | /// any methods, only attribute access (for structure fields) and |
49 | /// indexing (for pointer and array fields). |
50 | /// |
51 | /// Usage: |
52 | /// |
53 | /// # Define layout of a structure with 2 fields |
54 | /// # 0 and 4 are byte offsets of fields from the beginning of struct |
55 | /// # they are logically ORed with field type |
56 | /// FOO_STRUCT = {"a": 0 | uctypes.UINT32, "b": 4 | uctypes.UINT8} |
57 | /// |
58 | /// # Example memory buffer to access (contained in bytes object) |
59 | /// buf = b"\x64\0\0\0\0x14" |
60 | /// |
61 | /// # Create structure object referring to address of |
62 | /// # the data in the buffer above |
63 | /// s = uctypes.struct(FOO_STRUCT, uctypes.addressof(buf)) |
64 | /// |
65 | /// # Access fields |
66 | /// print(s.a, s.b) |
67 | /// # Result: |
68 | /// # 100, 20 |
69 | |
70 | #define LAYOUT_LITTLE_ENDIAN (0) |
71 | #define LAYOUT_BIG_ENDIAN (1) |
72 | #define LAYOUT_NATIVE (2) |
73 | |
74 | #define VAL_TYPE_BITS 4 |
75 | #define BITF_LEN_BITS 5 |
76 | #define BITF_OFF_BITS 5 |
77 | #define OFFSET_BITS 17 |
78 | #if VAL_TYPE_BITS + BITF_LEN_BITS + BITF_OFF_BITS + OFFSET_BITS != 31 |
79 | #error Invalid encoding field length |
80 | #endif |
81 | |
82 | enum { |
83 | UINT8, INT8, UINT16, INT16, |
84 | UINT32, INT32, UINT64, INT64, |
85 | |
86 | BFUINT8, BFINT8, BFUINT16, BFINT16, |
87 | BFUINT32, BFINT32, |
88 | |
89 | FLOAT32, FLOAT64, |
90 | }; |
91 | |
92 | #define AGG_TYPE_BITS 2 |
93 | |
94 | enum { |
95 | STRUCT, PTR, ARRAY, |
96 | }; |
97 | |
98 | // Here we need to set sign bit right |
99 | #define TYPE2SMALLINT(x, nbits) ((((int)x) << (32 - nbits)) >> 1) |
100 | #define GET_TYPE(x, nbits) (((x) >> (31 - nbits)) & ((1 << nbits) - 1)) |
101 | // Bit 0 is "is_signed" |
102 | #define GET_SCALAR_SIZE(val_type) (1 << ((val_type) >> 1)) |
103 | #define VALUE_MASK(type_nbits) ~((int)0x80000000 >> type_nbits) |
104 | |
105 | #define IS_SCALAR_ARRAY(tuple_desc) ((tuple_desc)->len == 2) |
106 | // We cannot apply the below to INT8, as their range [-128, 127] |
107 | #define IS_SCALAR_ARRAY_OF_BYTES(tuple_desc) (GET_TYPE(MP_OBJ_SMALL_INT_VALUE((tuple_desc)->items[1]), VAL_TYPE_BITS) == UINT8) |
108 | |
109 | // "struct" in uctypes context means "structural", i.e. aggregate, type. |
110 | STATIC const mp_obj_type_t uctypes_struct_type; |
111 | |
112 | typedef struct _mp_obj_uctypes_struct_t { |
113 | mp_obj_base_t base; |
114 | mp_obj_t desc; |
115 | byte *addr; |
116 | uint32_t flags; |
117 | } mp_obj_uctypes_struct_t; |
118 | |
119 | STATIC NORETURN void syntax_error(void) { |
120 | mp_raise_TypeError(MP_ERROR_TEXT("syntax error in uctypes descriptor" )); |
121 | } |
122 | |
123 | STATIC mp_obj_t uctypes_struct_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { |
124 | mp_arg_check_num(n_args, n_kw, 2, 3, false); |
125 | mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t); |
126 | o->base.type = type; |
127 | o->addr = (void *)(uintptr_t)mp_obj_int_get_truncated(args[0]); |
128 | o->desc = args[1]; |
129 | o->flags = LAYOUT_NATIVE; |
130 | if (n_args == 3) { |
131 | o->flags = mp_obj_get_int(args[2]); |
132 | } |
133 | return MP_OBJ_FROM_PTR(o); |
134 | } |
135 | |
136 | STATIC void uctypes_struct_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { |
137 | (void)kind; |
138 | mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); |
139 | const char *typen = "unk" ; |
140 | if (mp_obj_is_dict_or_ordereddict(self->desc)) { |
141 | typen = "STRUCT" ; |
142 | } else if (mp_obj_is_type(self->desc, &mp_type_tuple)) { |
143 | mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc); |
144 | mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]); |
145 | uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS); |
146 | switch (agg_type) { |
147 | case PTR: |
148 | typen = "PTR" ; |
149 | break; |
150 | case ARRAY: |
151 | typen = "ARRAY" ; |
152 | break; |
153 | } |
154 | } else { |
155 | typen = "ERROR" ; |
156 | } |
157 | mp_printf(print, "<struct %s %p>" , typen, self->addr); |
158 | } |
159 | |
160 | // Get size of any type descriptor |
161 | STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size); |
162 | |
163 | // Get size of scalar type descriptor |
164 | static inline mp_uint_t uctypes_struct_scalar_size(int val_type) { |
165 | if (val_type == FLOAT32) { |
166 | return 4; |
167 | } else { |
168 | return GET_SCALAR_SIZE(val_type & 7); |
169 | } |
170 | } |
171 | |
172 | // Get size of aggregate type descriptor |
173 | STATIC mp_uint_t uctypes_struct_agg_size(mp_obj_tuple_t *t, int layout_type, mp_uint_t *max_field_size) { |
174 | mp_uint_t total_size = 0; |
175 | |
176 | mp_int_t offset_ = MP_OBJ_SMALL_INT_VALUE(t->items[0]); |
177 | mp_uint_t agg_type = GET_TYPE(offset_, AGG_TYPE_BITS); |
178 | |
179 | switch (agg_type) { |
180 | case STRUCT: |
181 | return uctypes_struct_size(t->items[1], layout_type, max_field_size); |
182 | case PTR: |
183 | if (sizeof(void *) > *max_field_size) { |
184 | *max_field_size = sizeof(void *); |
185 | } |
186 | return sizeof(void *); |
187 | case ARRAY: { |
188 | mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]); |
189 | uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS); |
190 | arr_sz &= VALUE_MASK(VAL_TYPE_BITS); |
191 | mp_uint_t item_s; |
192 | if (t->len == 2) { |
193 | // Elements of array are scalar |
194 | item_s = GET_SCALAR_SIZE(val_type); |
195 | if (item_s > *max_field_size) { |
196 | *max_field_size = item_s; |
197 | } |
198 | } else { |
199 | // Elements of array are aggregates |
200 | item_s = uctypes_struct_size(t->items[2], layout_type, max_field_size); |
201 | } |
202 | |
203 | return item_s * arr_sz; |
204 | } |
205 | default: |
206 | assert(0); |
207 | } |
208 | |
209 | return total_size; |
210 | } |
211 | |
212 | STATIC mp_uint_t uctypes_struct_size(mp_obj_t desc_in, int layout_type, mp_uint_t *max_field_size) { |
213 | if (!mp_obj_is_dict_or_ordereddict(desc_in)) { |
214 | if (mp_obj_is_type(desc_in, &mp_type_tuple)) { |
215 | return uctypes_struct_agg_size((mp_obj_tuple_t *)MP_OBJ_TO_PTR(desc_in), layout_type, max_field_size); |
216 | } else if (mp_obj_is_small_int(desc_in)) { |
217 | // We allow sizeof on both type definitions and structures/structure fields, |
218 | // but scalar structure field is lowered into native Python int, so all |
219 | // type info is lost. So, we cannot say if it's scalar type description, |
220 | // or such lowered scalar. |
221 | mp_raise_TypeError(MP_ERROR_TEXT("can't unambiguously get sizeof scalar" )); |
222 | } |
223 | syntax_error(); |
224 | } |
225 | |
226 | mp_obj_dict_t *d = MP_OBJ_TO_PTR(desc_in); |
227 | mp_uint_t total_size = 0; |
228 | |
229 | for (mp_uint_t i = 0; i < d->map.alloc; i++) { |
230 | if (mp_map_slot_is_filled(&d->map, i)) { |
231 | mp_obj_t v = d->map.table[i].value; |
232 | if (mp_obj_is_small_int(v)) { |
233 | mp_uint_t offset = MP_OBJ_SMALL_INT_VALUE(v); |
234 | mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS); |
235 | offset &= VALUE_MASK(VAL_TYPE_BITS); |
236 | if (val_type >= BFUINT8 && val_type <= BFINT32) { |
237 | offset &= (1 << OFFSET_BITS) - 1; |
238 | } |
239 | mp_uint_t s = uctypes_struct_scalar_size(val_type); |
240 | if (s > *max_field_size) { |
241 | *max_field_size = s; |
242 | } |
243 | if (offset + s > total_size) { |
244 | total_size = offset + s; |
245 | } |
246 | } else { |
247 | if (!mp_obj_is_type(v, &mp_type_tuple)) { |
248 | syntax_error(); |
249 | } |
250 | mp_obj_tuple_t *t = MP_OBJ_TO_PTR(v); |
251 | mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]); |
252 | offset &= VALUE_MASK(AGG_TYPE_BITS); |
253 | mp_uint_t s = uctypes_struct_agg_size(t, layout_type, max_field_size); |
254 | if (offset + s > total_size) { |
255 | total_size = offset + s; |
256 | } |
257 | } |
258 | } |
259 | } |
260 | |
261 | // Round size up to alignment of biggest field |
262 | if (layout_type == LAYOUT_NATIVE) { |
263 | total_size = (total_size + *max_field_size - 1) & ~(*max_field_size - 1); |
264 | } |
265 | return total_size; |
266 | } |
267 | |
268 | STATIC mp_obj_t uctypes_struct_sizeof(size_t n_args, const mp_obj_t *args) { |
269 | mp_obj_t obj_in = args[0]; |
270 | mp_uint_t max_field_size = 0; |
271 | if (mp_obj_is_type(obj_in, &mp_type_bytearray)) { |
272 | return mp_obj_len(obj_in); |
273 | } |
274 | int layout_type = LAYOUT_NATIVE; |
275 | // We can apply sizeof either to structure definition (a dict) |
276 | // or to instantiated structure |
277 | if (mp_obj_is_type(obj_in, &uctypes_struct_type)) { |
278 | if (n_args != 1) { |
279 | mp_raise_TypeError(NULL); |
280 | } |
281 | // Extract structure definition |
282 | mp_obj_uctypes_struct_t *obj = MP_OBJ_TO_PTR(obj_in); |
283 | obj_in = obj->desc; |
284 | layout_type = obj->flags; |
285 | } else { |
286 | if (n_args == 2) { |
287 | layout_type = mp_obj_get_int(args[1]); |
288 | } |
289 | } |
290 | mp_uint_t size = uctypes_struct_size(obj_in, layout_type, &max_field_size); |
291 | return MP_OBJ_NEW_SMALL_INT(size); |
292 | } |
293 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(uctypes_struct_sizeof_obj, 1, 2, uctypes_struct_sizeof); |
294 | |
295 | static inline mp_obj_t get_unaligned(uint val_type, byte *p, int big_endian) { |
296 | char struct_type = big_endian ? '>' : '<'; |
297 | static const char type2char[16] = "BbHhIiQq------fd" ; |
298 | return mp_binary_get_val(struct_type, type2char[val_type], p, &p); |
299 | } |
300 | |
301 | static inline void set_unaligned(uint val_type, byte *p, int big_endian, mp_obj_t val) { |
302 | char struct_type = big_endian ? '>' : '<'; |
303 | static const char type2char[16] = "BbHhIiQq------fd" ; |
304 | mp_binary_set_val(struct_type, type2char[val_type], val, p, &p); |
305 | } |
306 | |
307 | static inline mp_uint_t get_aligned_basic(uint val_type, void *p) { |
308 | switch (val_type) { |
309 | case UINT8: |
310 | return *(uint8_t *)p; |
311 | case UINT16: |
312 | return *(uint16_t *)p; |
313 | case UINT32: |
314 | return *(uint32_t *)p; |
315 | } |
316 | assert(0); |
317 | return 0; |
318 | } |
319 | |
320 | static inline void set_aligned_basic(uint val_type, void *p, mp_uint_t v) { |
321 | switch (val_type) { |
322 | case UINT8: |
323 | *(uint8_t *)p = (uint8_t)v; |
324 | return; |
325 | case UINT16: |
326 | *(uint16_t *)p = (uint16_t)v; |
327 | return; |
328 | case UINT32: |
329 | *(uint32_t *)p = (uint32_t)v; |
330 | return; |
331 | } |
332 | assert(0); |
333 | } |
334 | |
335 | STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) { |
336 | switch (val_type) { |
337 | case UINT8: |
338 | return MP_OBJ_NEW_SMALL_INT(((uint8_t *)p)[index]); |
339 | case INT8: |
340 | return MP_OBJ_NEW_SMALL_INT(((int8_t *)p)[index]); |
341 | case UINT16: |
342 | return MP_OBJ_NEW_SMALL_INT(((uint16_t *)p)[index]); |
343 | case INT16: |
344 | return MP_OBJ_NEW_SMALL_INT(((int16_t *)p)[index]); |
345 | case UINT32: |
346 | return mp_obj_new_int_from_uint(((uint32_t *)p)[index]); |
347 | case INT32: |
348 | return mp_obj_new_int(((int32_t *)p)[index]); |
349 | case UINT64: |
350 | return mp_obj_new_int_from_ull(((uint64_t *)p)[index]); |
351 | case INT64: |
352 | return mp_obj_new_int_from_ll(((int64_t *)p)[index]); |
353 | #if MICROPY_PY_BUILTINS_FLOAT |
354 | case FLOAT32: |
355 | return mp_obj_new_float_from_f(((float *)p)[index]); |
356 | case FLOAT64: |
357 | return mp_obj_new_float_from_d(((double *)p)[index]); |
358 | #endif |
359 | default: |
360 | assert(0); |
361 | return MP_OBJ_NULL; |
362 | } |
363 | } |
364 | |
365 | STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) { |
366 | #if MICROPY_PY_BUILTINS_FLOAT |
367 | if (val_type == FLOAT32 || val_type == FLOAT64) { |
368 | if (val_type == FLOAT32) { |
369 | ((float *)p)[index] = mp_obj_get_float_to_f(val); |
370 | } else { |
371 | ((double *)p)[index] = mp_obj_get_float_to_d(val); |
372 | } |
373 | return; |
374 | } |
375 | #endif |
376 | mp_int_t v = mp_obj_get_int_truncated(val); |
377 | switch (val_type) { |
378 | case UINT8: |
379 | ((uint8_t *)p)[index] = (uint8_t)v; |
380 | return; |
381 | case INT8: |
382 | ((int8_t *)p)[index] = (int8_t)v; |
383 | return; |
384 | case UINT16: |
385 | ((uint16_t *)p)[index] = (uint16_t)v; |
386 | return; |
387 | case INT16: |
388 | ((int16_t *)p)[index] = (int16_t)v; |
389 | return; |
390 | case UINT32: |
391 | ((uint32_t *)p)[index] = (uint32_t)v; |
392 | return; |
393 | case INT32: |
394 | ((int32_t *)p)[index] = (int32_t)v; |
395 | return; |
396 | case INT64: |
397 | case UINT64: |
398 | if (sizeof(mp_int_t) == 8) { |
399 | ((uint64_t *)p)[index] = (uint64_t)v; |
400 | } else { |
401 | // TODO: Doesn't offer atomic store semantics, but should at least try |
402 | set_unaligned(val_type, (void *)&((uint64_t *)p)[index], MP_ENDIANNESS_BIG, val); |
403 | } |
404 | return; |
405 | default: |
406 | assert(0); |
407 | } |
408 | } |
409 | |
410 | STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set_val) { |
411 | mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); |
412 | |
413 | if (!mp_obj_is_dict_or_ordereddict(self->desc)) { |
414 | mp_raise_TypeError(MP_ERROR_TEXT("struct: no fields" )); |
415 | } |
416 | |
417 | mp_obj_t deref = mp_obj_dict_get(self->desc, MP_OBJ_NEW_QSTR(attr)); |
418 | if (mp_obj_is_small_int(deref)) { |
419 | mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(deref); |
420 | mp_uint_t val_type = GET_TYPE(offset, VAL_TYPE_BITS); |
421 | offset &= VALUE_MASK(VAL_TYPE_BITS); |
422 | // printf("scalar type=%d offset=%x\n", val_type, offset); |
423 | |
424 | if (val_type <= INT64 || val_type == FLOAT32 || val_type == FLOAT64) { |
425 | // printf("size=%d\n", GET_SCALAR_SIZE(val_type)); |
426 | if (self->flags == LAYOUT_NATIVE) { |
427 | if (set_val == MP_OBJ_NULL) { |
428 | return get_aligned(val_type, self->addr + offset, 0); |
429 | } else { |
430 | set_aligned(val_type, self->addr + offset, 0, set_val); |
431 | return set_val; // just !MP_OBJ_NULL |
432 | } |
433 | } else { |
434 | if (set_val == MP_OBJ_NULL) { |
435 | return get_unaligned(val_type, self->addr + offset, self->flags); |
436 | } else { |
437 | set_unaligned(val_type, self->addr + offset, self->flags, set_val); |
438 | return set_val; // just !MP_OBJ_NULL |
439 | } |
440 | } |
441 | } else if (val_type >= BFUINT8 && val_type <= BFINT32) { |
442 | uint bit_offset = (offset >> 17) & 31; |
443 | uint bit_len = (offset >> 22) & 31; |
444 | offset &= (1 << 17) - 1; |
445 | mp_uint_t val; |
446 | if (self->flags == LAYOUT_NATIVE) { |
447 | val = get_aligned_basic(val_type & 6, self->addr + offset); |
448 | } else { |
449 | val = mp_binary_get_int(GET_SCALAR_SIZE(val_type & 7), val_type & 1, self->flags, self->addr + offset); |
450 | } |
451 | if (set_val == MP_OBJ_NULL) { |
452 | val >>= bit_offset; |
453 | val &= (1 << bit_len) - 1; |
454 | // TODO: signed |
455 | assert((val_type & 1) == 0); |
456 | return mp_obj_new_int(val); |
457 | } else { |
458 | mp_uint_t set_val_int = (mp_uint_t)mp_obj_get_int(set_val); |
459 | mp_uint_t mask = (1 << bit_len) - 1; |
460 | set_val_int &= mask; |
461 | set_val_int <<= bit_offset; |
462 | mask <<= bit_offset; |
463 | val = (val & ~mask) | set_val_int; |
464 | |
465 | if (self->flags == LAYOUT_NATIVE) { |
466 | set_aligned_basic(val_type & 6, self->addr + offset, val); |
467 | } else { |
468 | mp_binary_set_int(GET_SCALAR_SIZE(val_type & 7), self->flags == LAYOUT_BIG_ENDIAN, |
469 | self->addr + offset, val); |
470 | } |
471 | return set_val; // just !MP_OBJ_NULL |
472 | } |
473 | } |
474 | |
475 | assert(0); |
476 | return MP_OBJ_NULL; |
477 | } |
478 | |
479 | if (!mp_obj_is_type(deref, &mp_type_tuple)) { |
480 | syntax_error(); |
481 | } |
482 | |
483 | if (set_val != MP_OBJ_NULL) { |
484 | // Cannot assign to aggregate |
485 | syntax_error(); |
486 | } |
487 | |
488 | mp_obj_tuple_t *sub = MP_OBJ_TO_PTR(deref); |
489 | mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(sub->items[0]); |
490 | mp_uint_t agg_type = GET_TYPE(offset, AGG_TYPE_BITS); |
491 | offset &= VALUE_MASK(AGG_TYPE_BITS); |
492 | // printf("agg type=%d offset=%x\n", agg_type, offset); |
493 | |
494 | switch (agg_type) { |
495 | case STRUCT: { |
496 | mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t); |
497 | o->base.type = &uctypes_struct_type; |
498 | o->desc = sub->items[1]; |
499 | o->addr = self->addr + offset; |
500 | o->flags = self->flags; |
501 | return MP_OBJ_FROM_PTR(o); |
502 | } |
503 | case ARRAY: { |
504 | mp_uint_t dummy; |
505 | if (IS_SCALAR_ARRAY(sub) && IS_SCALAR_ARRAY_OF_BYTES(sub)) { |
506 | return mp_obj_new_bytearray_by_ref(uctypes_struct_agg_size(sub, self->flags, &dummy), self->addr + offset); |
507 | } |
508 | // Fall thru to return uctypes struct object |
509 | MP_FALLTHROUGH |
510 | } |
511 | case PTR: { |
512 | mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t); |
513 | o->base.type = &uctypes_struct_type; |
514 | o->desc = MP_OBJ_FROM_PTR(sub); |
515 | o->addr = self->addr + offset; |
516 | o->flags = self->flags; |
517 | // printf("PTR/ARR base addr=%p\n", o->addr); |
518 | return MP_OBJ_FROM_PTR(o); |
519 | } |
520 | } |
521 | |
522 | // Should be unreachable once all cases are handled |
523 | return MP_OBJ_NULL; |
524 | } |
525 | |
526 | STATIC void uctypes_struct_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { |
527 | if (dest[0] == MP_OBJ_NULL) { |
528 | // load attribute |
529 | mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL); |
530 | dest[0] = val; |
531 | } else { |
532 | // delete/store attribute |
533 | if (uctypes_struct_attr_op(self_in, attr, dest[1]) != MP_OBJ_NULL) { |
534 | dest[0] = MP_OBJ_NULL; // indicate success |
535 | } |
536 | } |
537 | } |
538 | |
539 | STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) { |
540 | mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); |
541 | |
542 | if (value == MP_OBJ_NULL) { |
543 | // delete |
544 | return MP_OBJ_NULL; // op not supported |
545 | } else { |
546 | // load / store |
547 | if (!mp_obj_is_type(self->desc, &mp_type_tuple)) { |
548 | mp_raise_TypeError(MP_ERROR_TEXT("struct: can't index" )); |
549 | } |
550 | |
551 | mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc); |
552 | mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]); |
553 | uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS); |
554 | |
555 | mp_int_t index = MP_OBJ_SMALL_INT_VALUE(index_in); |
556 | |
557 | if (agg_type == ARRAY) { |
558 | mp_int_t arr_sz = MP_OBJ_SMALL_INT_VALUE(t->items[1]); |
559 | uint val_type = GET_TYPE(arr_sz, VAL_TYPE_BITS); |
560 | arr_sz &= VALUE_MASK(VAL_TYPE_BITS); |
561 | if (index >= arr_sz) { |
562 | mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("struct: index out of range" )); |
563 | } |
564 | |
565 | if (t->len == 2) { |
566 | // array of scalars |
567 | if (self->flags == LAYOUT_NATIVE) { |
568 | if (value == MP_OBJ_SENTINEL) { |
569 | return get_aligned(val_type, self->addr, index); |
570 | } else { |
571 | set_aligned(val_type, self->addr, index, value); |
572 | return value; // just !MP_OBJ_NULL |
573 | } |
574 | } else { |
575 | byte *p = self->addr + GET_SCALAR_SIZE(val_type) * index; |
576 | if (value == MP_OBJ_SENTINEL) { |
577 | return get_unaligned(val_type, p, self->flags); |
578 | } else { |
579 | set_unaligned(val_type, p, self->flags, value); |
580 | return value; // just !MP_OBJ_NULL |
581 | } |
582 | } |
583 | } else if (value == MP_OBJ_SENTINEL) { |
584 | mp_uint_t dummy = 0; |
585 | mp_uint_t size = uctypes_struct_size(t->items[2], self->flags, &dummy); |
586 | mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t); |
587 | o->base.type = &uctypes_struct_type; |
588 | o->desc = t->items[2]; |
589 | o->addr = self->addr + size * index; |
590 | o->flags = self->flags; |
591 | return MP_OBJ_FROM_PTR(o); |
592 | } else { |
593 | return MP_OBJ_NULL; // op not supported |
594 | } |
595 | |
596 | } else if (agg_type == PTR) { |
597 | byte *p = *(void **)self->addr; |
598 | if (mp_obj_is_small_int(t->items[1])) { |
599 | uint val_type = GET_TYPE(MP_OBJ_SMALL_INT_VALUE(t->items[1]), VAL_TYPE_BITS); |
600 | return get_aligned(val_type, p, index); |
601 | } else { |
602 | mp_uint_t dummy = 0; |
603 | mp_uint_t size = uctypes_struct_size(t->items[1], self->flags, &dummy); |
604 | mp_obj_uctypes_struct_t *o = m_new_obj(mp_obj_uctypes_struct_t); |
605 | o->base.type = &uctypes_struct_type; |
606 | o->desc = t->items[1]; |
607 | o->addr = p + size * index; |
608 | o->flags = self->flags; |
609 | return MP_OBJ_FROM_PTR(o); |
610 | } |
611 | } |
612 | |
613 | assert(0); |
614 | return MP_OBJ_NULL; |
615 | } |
616 | } |
617 | |
618 | STATIC mp_obj_t uctypes_struct_unary_op(mp_unary_op_t op, mp_obj_t self_in) { |
619 | mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); |
620 | switch (op) { |
621 | case MP_UNARY_OP_INT: |
622 | if (mp_obj_is_type(self->desc, &mp_type_tuple)) { |
623 | mp_obj_tuple_t *t = MP_OBJ_TO_PTR(self->desc); |
624 | mp_int_t offset = MP_OBJ_SMALL_INT_VALUE(t->items[0]); |
625 | uint agg_type = GET_TYPE(offset, AGG_TYPE_BITS); |
626 | if (agg_type == PTR) { |
627 | byte *p = *(void **)self->addr; |
628 | return mp_obj_new_int((mp_int_t)(uintptr_t)p); |
629 | } |
630 | } |
631 | MP_FALLTHROUGH |
632 | |
633 | default: |
634 | return MP_OBJ_NULL; // op not supported |
635 | } |
636 | } |
637 | |
638 | STATIC mp_int_t uctypes_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { |
639 | (void)flags; |
640 | mp_obj_uctypes_struct_t *self = MP_OBJ_TO_PTR(self_in); |
641 | mp_uint_t max_field_size = 0; |
642 | mp_uint_t size = uctypes_struct_size(self->desc, self->flags, &max_field_size); |
643 | |
644 | bufinfo->buf = self->addr; |
645 | bufinfo->len = size; |
646 | bufinfo->typecode = BYTEARRAY_TYPECODE; |
647 | return 0; |
648 | } |
649 | |
650 | /// \function addressof() |
651 | /// Return address of object's data (applies to object providing buffer |
652 | /// interface). |
653 | STATIC mp_obj_t uctypes_struct_addressof(mp_obj_t buf) { |
654 | mp_buffer_info_t bufinfo; |
655 | mp_get_buffer_raise(buf, &bufinfo, MP_BUFFER_READ); |
656 | return mp_obj_new_int((mp_int_t)(uintptr_t)bufinfo.buf); |
657 | } |
658 | MP_DEFINE_CONST_FUN_OBJ_1(uctypes_struct_addressof_obj, uctypes_struct_addressof); |
659 | |
660 | /// \function bytearray_at() |
661 | /// Capture memory at given address of given size as bytearray. Memory is |
662 | /// captured by reference (and thus memory pointed by bytearray may change |
663 | /// or become invalid at later time). Use bytes_at() to capture by value. |
664 | STATIC mp_obj_t uctypes_struct_bytearray_at(mp_obj_t ptr, mp_obj_t size) { |
665 | return mp_obj_new_bytearray_by_ref(mp_obj_int_get_truncated(size), (void *)(uintptr_t)mp_obj_int_get_truncated(ptr)); |
666 | } |
667 | MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytearray_at_obj, uctypes_struct_bytearray_at); |
668 | |
669 | /// \function bytes_at() |
670 | /// Capture memory at given address of given size as bytes. Memory is |
671 | /// captured by value, i.e. copied. Use bytearray_at() to capture by reference |
672 | /// ("zero copy"). |
673 | STATIC mp_obj_t uctypes_struct_bytes_at(mp_obj_t ptr, mp_obj_t size) { |
674 | return mp_obj_new_bytes((void *)(uintptr_t)mp_obj_int_get_truncated(ptr), mp_obj_int_get_truncated(size)); |
675 | } |
676 | MP_DEFINE_CONST_FUN_OBJ_2(uctypes_struct_bytes_at_obj, uctypes_struct_bytes_at); |
677 | |
678 | |
679 | STATIC const mp_obj_type_t uctypes_struct_type = { |
680 | { &mp_type_type }, |
681 | .name = MP_QSTR_struct, |
682 | .print = uctypes_struct_print, |
683 | .make_new = uctypes_struct_make_new, |
684 | .attr = uctypes_struct_attr, |
685 | .subscr = uctypes_struct_subscr, |
686 | .unary_op = uctypes_struct_unary_op, |
687 | .buffer_p = { .get_buffer = uctypes_get_buffer }, |
688 | }; |
689 | |
690 | STATIC const mp_rom_map_elem_t mp_module_uctypes_globals_table[] = { |
691 | { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uctypes) }, |
692 | { MP_ROM_QSTR(MP_QSTR_struct), MP_ROM_PTR(&uctypes_struct_type) }, |
693 | { MP_ROM_QSTR(MP_QSTR_sizeof), MP_ROM_PTR(&uctypes_struct_sizeof_obj) }, |
694 | { MP_ROM_QSTR(MP_QSTR_addressof), MP_ROM_PTR(&uctypes_struct_addressof_obj) }, |
695 | { MP_ROM_QSTR(MP_QSTR_bytes_at), MP_ROM_PTR(&uctypes_struct_bytes_at_obj) }, |
696 | { MP_ROM_QSTR(MP_QSTR_bytearray_at), MP_ROM_PTR(&uctypes_struct_bytearray_at_obj) }, |
697 | |
698 | /// \moduleref uctypes |
699 | |
700 | /// \constant NATIVE - Native structure layout - native endianness, |
701 | /// platform-specific field alignment |
702 | { MP_ROM_QSTR(MP_QSTR_NATIVE), MP_ROM_INT(LAYOUT_NATIVE) }, |
703 | /// \constant LITTLE_ENDIAN - Little-endian structure layout, tightly packed |
704 | /// (no alignment constraints) |
705 | { MP_ROM_QSTR(MP_QSTR_LITTLE_ENDIAN), MP_ROM_INT(LAYOUT_LITTLE_ENDIAN) }, |
706 | /// \constant BIG_ENDIAN - Big-endian structure layout, tightly packed |
707 | /// (no alignment constraints) |
708 | { MP_ROM_QSTR(MP_QSTR_BIG_ENDIAN), MP_ROM_INT(LAYOUT_BIG_ENDIAN) }, |
709 | |
710 | /// \constant VOID - void value type, may be used only as pointer target type. |
711 | { MP_ROM_QSTR(MP_QSTR_VOID), MP_ROM_INT(TYPE2SMALLINT(UINT8, VAL_TYPE_BITS)) }, |
712 | |
713 | /// \constant UINT8 - uint8_t value type |
714 | { MP_ROM_QSTR(MP_QSTR_UINT8), MP_ROM_INT(TYPE2SMALLINT(UINT8, 4)) }, |
715 | /// \constant INT8 - int8_t value type |
716 | { MP_ROM_QSTR(MP_QSTR_INT8), MP_ROM_INT(TYPE2SMALLINT(INT8, 4)) }, |
717 | /// \constant UINT16 - uint16_t value type |
718 | { MP_ROM_QSTR(MP_QSTR_UINT16), MP_ROM_INT(TYPE2SMALLINT(UINT16, 4)) }, |
719 | /// \constant INT16 - int16_t value type |
720 | { MP_ROM_QSTR(MP_QSTR_INT16), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) }, |
721 | /// \constant UINT32 - uint32_t value type |
722 | { MP_ROM_QSTR(MP_QSTR_UINT32), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) }, |
723 | /// \constant INT32 - int32_t value type |
724 | { MP_ROM_QSTR(MP_QSTR_INT32), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) }, |
725 | /// \constant UINT64 - uint64_t value type |
726 | { MP_ROM_QSTR(MP_QSTR_UINT64), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) }, |
727 | /// \constant INT64 - int64_t value type |
728 | { MP_ROM_QSTR(MP_QSTR_INT64), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) }, |
729 | |
730 | { MP_ROM_QSTR(MP_QSTR_BFUINT8), MP_ROM_INT(TYPE2SMALLINT(BFUINT8, 4)) }, |
731 | { MP_ROM_QSTR(MP_QSTR_BFINT8), MP_ROM_INT(TYPE2SMALLINT(BFINT8, 4)) }, |
732 | { MP_ROM_QSTR(MP_QSTR_BFUINT16), MP_ROM_INT(TYPE2SMALLINT(BFUINT16, 4)) }, |
733 | { MP_ROM_QSTR(MP_QSTR_BFINT16), MP_ROM_INT(TYPE2SMALLINT(BFINT16, 4)) }, |
734 | { MP_ROM_QSTR(MP_QSTR_BFUINT32), MP_ROM_INT(TYPE2SMALLINT(BFUINT32, 4)) }, |
735 | { MP_ROM_QSTR(MP_QSTR_BFINT32), MP_ROM_INT(TYPE2SMALLINT(BFINT32, 4)) }, |
736 | |
737 | { MP_ROM_QSTR(MP_QSTR_BF_POS), MP_ROM_INT(17) }, |
738 | { MP_ROM_QSTR(MP_QSTR_BF_LEN), MP_ROM_INT(22) }, |
739 | |
740 | #if MICROPY_PY_BUILTINS_FLOAT |
741 | { MP_ROM_QSTR(MP_QSTR_FLOAT32), MP_ROM_INT(TYPE2SMALLINT(FLOAT32, 4)) }, |
742 | { MP_ROM_QSTR(MP_QSTR_FLOAT64), MP_ROM_INT(TYPE2SMALLINT(FLOAT64, 4)) }, |
743 | #endif |
744 | |
745 | #if MICROPY_PY_UCTYPES_NATIVE_C_TYPES |
746 | // C native type aliases. These depend on GCC-compatible predefined |
747 | // preprocessor macros. |
748 | #if __SIZEOF_SHORT__ == 2 |
749 | { MP_ROM_QSTR(MP_QSTR_SHORT), MP_ROM_INT(TYPE2SMALLINT(INT16, 4)) }, |
750 | { MP_ROM_QSTR(MP_QSTR_USHORT), MP_ROM_INT(TYPE2SMALLINT(UINT16, 4)) }, |
751 | #endif |
752 | #if __SIZEOF_INT__ == 4 |
753 | { MP_ROM_QSTR(MP_QSTR_INT), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) }, |
754 | { MP_ROM_QSTR(MP_QSTR_UINT), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) }, |
755 | #endif |
756 | #if __SIZEOF_LONG__ == 4 |
757 | { MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT32, 4)) }, |
758 | { MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT32, 4)) }, |
759 | #elif __SIZEOF_LONG__ == 8 |
760 | { MP_ROM_QSTR(MP_QSTR_LONG), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) }, |
761 | { MP_ROM_QSTR(MP_QSTR_ULONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) }, |
762 | #endif |
763 | #if __SIZEOF_LONG_LONG__ == 8 |
764 | { MP_ROM_QSTR(MP_QSTR_LONGLONG), MP_ROM_INT(TYPE2SMALLINT(INT64, 4)) }, |
765 | { MP_ROM_QSTR(MP_QSTR_ULONGLONG), MP_ROM_INT(TYPE2SMALLINT(UINT64, 4)) }, |
766 | #endif |
767 | #endif // MICROPY_PY_UCTYPES_NATIVE_C_TYPES |
768 | |
769 | { MP_ROM_QSTR(MP_QSTR_PTR), MP_ROM_INT(TYPE2SMALLINT(PTR, AGG_TYPE_BITS)) }, |
770 | { MP_ROM_QSTR(MP_QSTR_ARRAY), MP_ROM_INT(TYPE2SMALLINT(ARRAY, AGG_TYPE_BITS)) }, |
771 | }; |
772 | |
773 | STATIC MP_DEFINE_CONST_DICT(mp_module_uctypes_globals, mp_module_uctypes_globals_table); |
774 | |
775 | const mp_obj_module_t mp_module_uctypes = { |
776 | .base = { &mp_type_module }, |
777 | .globals = (mp_obj_dict_t *)&mp_module_uctypes_globals, |
778 | }; |
779 | |
780 | #endif |
781 | |