1- :mod: `uctypes ` -- access C structures
2- =====================================
1+ :mod: `uctypes ` -- access binary data in a structured way
2+ ========================================================
33
44.. module :: uctypes
5- :synopsis: access C structures
5+ :synopsis: access binary data in a structured way
66
77This module implements "foreign data interface" for MicroPython. The idea
8- behind it is similar to CPython's ``ctypes `` modules, but actual API is
9- different, streamlined and optimized for small size.
8+ behind it is similar to CPython's ``ctypes `` modules, but the actual API is
9+ different, streamlined and optimized for small size. The basic idea of the
10+ module is to define data structure layout with about the same power as the
11+ C language allows, and the access it using familiar dot-syntax to reference
12+ sub-fields.
13+
14+ .. seealso ::
15+
16+ Module :mod: `ustruct `
17+ Standard Python way to access binary data structures (doesn't scale
18+ well to large and complex structures).
1019
1120Defining structure layout
1221-------------------------
1322
1423Structure layout is defined by a "descriptor" - a Python dictionary which
1524encodes field names as keys and other properties required to access them as
16- an associated values. Currently, uctypes requires explicit specification of
17- offsets for each field. Offset are given in bytes from structure start.
25+ associated values. Currently, uctypes requires explicit specification of
26+ offsets for each field. Offset are given in bytes from a structure start.
1827
1928Following are encoding examples for various field types:
2029
21- Scalar types::
30+ * Scalar types::
2231
2332 "field_name": uctypes.UINT32 | 0
2433
25- in other words, value is scalar type identifier ORed with field offset
26- (in bytes) from the start of the structure.
34+ in other words, value is scalar type identifier ORed with field offset
35+ (in bytes) from the start of the structure.
2736
28- Recursive structures::
37+ * Recursive structures::
2938
3039 "sub": (2, {
3140 "b0": uctypes.UINT8 | 0,
3241 "b1": uctypes.UINT8 | 1,
3342 })
3443
35- i.e. value is a 2-tuple, first element of which is offset, and second is
36- a structure descriptor dictionary (note: offsets in recursive descriptors
37- are relative to a structure it defines).
44+ i.e. value is a 2-tuple, first element of which is offset, and second is
45+ a structure descriptor dictionary (note: offsets in recursive descriptors
46+ are relative to a structure it defines).
3847
39- Arrays of primitive types::
48+ * Arrays of primitive types::
4049
4150 "arr": (uctypes.ARRAY | 0, uctypes.UINT8 | 2),
4251
43- i.e. value is a 2-tuple, first element of which is ARRAY flag ORed
44- with offset, and second is scalar element type ORed number of elements
45- in array.
52+ i.e. value is a 2-tuple, first element of which is ARRAY flag ORed
53+ with offset, and second is scalar element type ORed number of elements
54+ in array.
4655
47- Arrays of aggregate types::
56+ * Arrays of aggregate types::
4857
4958 "arr2": (uctypes.ARRAY | 0, 2, {"b": uctypes.UINT8 | 0}),
5059
51- i.e. value is a 3-tuple, first element of which is ARRAY flag ORed
52- with offset, second is a number of elements in array, and third is
53- descriptor of element type.
60+ i.e. value is a 3-tuple, first element of which is ARRAY flag ORed
61+ with offset, second is a number of elements in array, and third is
62+ descriptor of element type.
5463
55- Pointer to a primitive type::
64+ * Pointer to a primitive type::
5665
5766 "ptr": (uctypes.PTR | 0, uctypes.UINT8),
5867
59- i.e. value is a 2-tuple, first element of which is PTR flag ORed
60- with offset, and second is scalar element type.
68+ i.e. value is a 2-tuple, first element of which is PTR flag ORed
69+ with offset, and second is scalar element type.
6170
62- Pointer to aggregate type::
71+ * Pointer to an aggregate type::
6372
6473 "ptr2": (uctypes.PTR | 0, {"b": uctypes.UINT8 | 0}),
6574
66- i.e. value is a 2-tuple, first element of which is PTR flag ORed
67- with offset, second is descriptor of type pointed to.
75+ i.e. value is a 2-tuple, first element of which is PTR flag ORed
76+ with offset, second is descriptor of type pointed to.
6877
69- Bitfields::
78+ * Bitfields::
7079
7180 "bitf0": uctypes.BFUINT16 | 0 | 0 << uctypes.BF_POS | 8 << uctypes.BF_LEN,
7281
73- i.e. value is type of scalar value containing given bitfield (typenames are
74- similar to scalar types, but prefixes with "BF"), ORed with offset for
75- scalar value containing the bitfield, and further ORed with values for
76- bit offset and bit length of the bitfield within scalar value, shifted by
77- BF_POS and BF_LEN positions, respectively. Bitfield position is counted
78- from the least significant bit, and is the number of right-most bit of a
79- field (in other words, it's a number of bits a scalar needs to be shifted
80- right to extra the bitfield).
81-
82- In the example above, first UINT16 value will be extracted at offset 0
83- (this detail may be important when accessing hardware registers, where
84- particular access size and alignment are required), and then bitfield
85- whose rightmost bit is least-significant bit of this UINT16, and length
86- is 8 bits, will be extracted - effectively, this will access
87- least-significant byte of UINT16.
88-
89- Note that bitfield operations are independent of target byte endianness,
90- in particular, example above will access least-significant byte of UINT16
91- in both little- and big-endian structures. But it depends on the least
92- significant bit being numbered 0. Some targets may use different
93- numbering in their native ABI, but ``uctypes `` always uses normalized
94- numbering described above.
82+ i.e. value is type of scalar value containing given bitfield (typenames are
83+ similar to scalar types, but prefixes with "BF"), ORed with offset for
84+ scalar value containing the bitfield, and further ORed with values for
85+ bit offset and bit length of the bitfield within scalar value, shifted by
86+ BF_POS and BF_LEN positions, respectively. Bitfield position is counted
87+ from the least significant bit, and is the number of right-most bit of a
88+ field (in other words, it's a number of bits a scalar needs to be shifted
89+ right to extra the bitfield).
90+
91+ In the example above, first UINT16 value will be extracted at offset 0
92+ (this detail may be important when accessing hardware registers, where
93+ particular access size and alignment are required), and then bitfield
94+ whose rightmost bit is least-significant bit of this UINT16, and length
95+ is 8 bits, will be extracted - effectively, this will access
96+ least-significant byte of UINT16.
97+
98+ Note that bitfield operations are independent of target byte endianness,
99+ in particular, example above will access least-significant byte of UINT16
100+ in both little- and big-endian structures. But it depends on the least
101+ significant bit being numbered 0. Some targets may use different
102+ numbering in their native ABI, but ``uctypes`` always uses normalized
103+ numbering described above.
95104
96105Module contents
97106---------------
@@ -103,17 +112,18 @@ Module contents
103112
104113.. data :: LITTLE_ENDIAN
105114
106- Little-endian packed structure. (Packed means that every field occupies
107- exactly as many bytes as defined in the descriptor, i.e. alignment is 1).
115+ Layout type for a little-endian packed structure. (Packed means that every
116+ field occupies exactly as many bytes as defined in the descriptor, i.e.
117+ the alignment is 1).
108118
109119.. data :: BIG_ENDIAN
110120
111- Big -endian packed structure.
121+ Layour type for a big -endian packed structure.
112122
113123.. data :: NATIVE
114124
115- Native structure - with data endianness and alignment conforming to
116- the ABI of the system on which MicroPython runs.
125+ Layout type for a native structure - with data endianness and alignment
126+ conforming to the ABI of the system on which MicroPython runs.
117127
118128.. function :: sizeof(struct)
119129
@@ -145,33 +155,55 @@ Structure descriptors and instantiating structure objects
145155
146156Given a structure descriptor dictionary and its layout type, you can
147157instantiate a specific structure instance at a given memory address
148- using uctypes.struct() constructor. Memory address usually comes from
158+ using :class: ` uctypes.struct() ` constructor. Memory address usually comes from
149159following sources:
150160
151161* Predefined address, when accessing hardware registers on a baremetal
152162 system. Lookup these addresses in datasheet for a particular MCU/SoC.
153- * As return value from a call to some FFI (Foreign Function Interface)
163+ * As a return value from a call to some FFI (Foreign Function Interface)
154164 function.
155- * From uctypes.addressof(), when you want to pass arguments to FFI
165+ * From uctypes.addressof(), when you want to pass arguments to an FFI
156166 function, or alternatively, to access some data for I/O (for example,
157- data read from file or network socket).
167+ data read from a file or network socket).
158168
159169Structure objects
160170-----------------
161171
162172Structure objects allow accessing individual fields using standard dot
163- notation: ``my_struct.field1 ``. If a field is of scalar type, getting
164- it will produce primitive value (Python integer or float) corresponding
165- to value contained in a field. Scalar field can also be assigned to.
173+ notation: ``my_struct.substruct1.field1 ``. If a field is of scalar type,
174+ getting it will produce a primitive value (Python integer or float)
175+ corresponding to the value contained in a field. A scalar field can also
176+ be assigned to.
166177
167178If a field is an array, its individual elements can be accessed with
168- standard subscript operator - both read and assigned to.
179+ the standard subscript operator `` [] `` - both read and assigned to.
169180
170181If a field is a pointer, it can be dereferenced using ``[0] `` syntax
171182(corresponding to C ``* `` operator, though ``[0] `` works in C too).
172- Subscripting pointer with other integer values but 0 are supported too,
183+ Subscripting a pointer with other integer values but 0 are supported too,
173184with the same semantics as in C.
174185
175186Summing up, accessing structure fields generally follows C syntax,
176- except for pointer derefence, you need to use ``[0] `` operator instead
177- of ``* ``.
187+ except for pointer derefence, when you need to use ``[0] `` operator
188+ instead of ``* ``.
189+
190+ Limitations
191+ -----------
192+
193+ Accessing non-scalar fields leads to allocation of intermediate objects
194+ to represent them. This means that special care should be taken to
195+ layout a structure which needs to be accessed when memory allocation
196+ is disabled (e.g. from an interrupt). The recommendations are:
197+
198+ * Avoid nested structures. For example, instead of
199+ ``mcu_registers.peripheral_a.register1 ``, define separate layout
200+ descriptors for each peripheral, to be accessed as
201+ ``peripheral_a.register1 ``.
202+ * Avoid other non-scalar data, like array. For example, instead of
203+ ``peripheral_a.register[0] `` use ``peripheral_a.register0 ``.
204+
205+ Note that these recommendations will lead to decreased readability
206+ and conciseness of layouts, so they should be used only if the need
207+ to access structure fields without allocation is anticipated (it's
208+ even possible to define 2 parallel layouts - one for normal usage,
209+ and a restricted one to use when memory allocation is prohibited).
0 commit comments