41
41
42
42
from micropython import const
43
43
44
+ try :
45
+ from typing import Optional , Union , Type , List
46
+ from busio import I2C
47
+ from microcontroller import Pin
48
+ from circuitpython_typing import WriteableBuffer
49
+ except ImportError :
50
+ pass
51
+
44
52
CTRLI = const (0x50 )
45
53
_R_BYPASS = const (0x05 )
46
54
_QS = const (0x44 )
954
962
955
963
956
964
class _RegBits :
957
- def __init__ (self , bank , reg , shift , mask ) :
965
+ def __init__ (self , bank : int , reg : int , shift : int , mask : int ) -> None :
958
966
self .bank = bank
959
967
self .reg = reg
960
968
self .shift = shift
961
969
self .mask = mask
962
970
963
- def __get__ (self , obj , objtype = None ):
971
+ def __get__ (self , obj : "_SCCBCameraBase" , objtype : Optional [ Type ] = None ) -> int :
964
972
reg_value = obj ._read_bank_register (self .bank , self .reg )
965
973
return (reg_value >> self .shift ) & self .mask
966
974
967
- def __set__ (self , obj , value ) :
975
+ def __set__ (self , obj : "_SCCBCameraBase" , value : Union [ bool , int ]) -> None :
968
976
if value & ~ self .mask :
969
977
raise ValueError (
970
978
f"Value 0x{ value :02x} does not fit in mask 0x{ self .mask :02x} "
@@ -976,38 +984,38 @@ def __set__(self, obj, value):
976
984
977
985
978
986
class _SCCBCameraBase : # pylint: disable=too-few-public-methods
979
- def __init__ (self , i2c_bus , i2c_address ) :
987
+ def __init__ (self , i2c_bus : I2C , i2c_address : int ) -> None :
980
988
self ._i2c_device = I2CDevice (i2c_bus , i2c_address )
981
989
self ._bank = None
982
990
983
- def _get_reg_bits (self , bank , reg , shift , mask ) :
991
+ def _get_reg_bits (self , bank : int , reg : int , shift : int , mask : int ) -> int :
984
992
return (self ._read_bank_register (bank , reg ) >> shift ) & mask
985
993
986
- def _set_reg_bits (
987
- self , bank , reg , shift , mask , value
988
- ): # pylint: disable=too-many-arguments
994
+ def _set_reg_bits ( # pylint: disable=too-many-arguments
995
+ self , bank : int , reg : int , shift : int , mask : int , value : int
996
+ ) -> None :
989
997
reg_value = self ._read_bank_register (bank , reg )
990
998
reg_value &= ~ (mask << shift )
991
999
reg_value |= value << shift
992
1000
self ._write_register (reg , reg_value )
993
1001
994
- def _write_list (self , reg_list ) :
1002
+ def _write_list (self , reg_list : List [ int ]) -> None :
995
1003
for i in range (0 , len (reg_list ), 2 ):
996
1004
self ._write_register (reg_list [i ], reg_list [i + 1 ])
997
1005
time .sleep (0.001 )
998
1006
999
- def _write_bank_register (self , bank , reg , value ) :
1007
+ def _write_bank_register (self , bank : int , reg : int , value : int ) -> None :
1000
1008
if self ._bank != bank :
1001
1009
self ._write_register (_BANK_SEL , bank )
1002
1010
self ._write_register (reg , value )
1003
1011
1004
- def _read_bank_register (self , bank , reg ) :
1012
+ def _read_bank_register (self , bank : int , reg : int ) -> int :
1005
1013
if self ._bank != bank :
1006
1014
self ._write_register (_BANK_SEL , bank )
1007
1015
result = self ._read_register (reg )
1008
1016
return result
1009
1017
1010
- def _write_register (self , reg , value ) :
1018
+ def _write_register (self , reg : int , value : int ) -> None :
1011
1019
if reg == _BANK_SEL :
1012
1020
if self ._bank == value :
1013
1021
return
@@ -1019,7 +1027,7 @@ def _write_register(self, reg, value):
1019
1027
with self ._i2c_device as i2c :
1020
1028
i2c .write (b )
1021
1029
1022
- def _read_register (self , reg ) :
1030
+ def _read_register (self , reg : int ) -> int :
1023
1031
b = bytearray (1 )
1024
1032
b [0 ] = reg
1025
1033
with self ._i2c_device as i2c :
@@ -1039,17 +1047,17 @@ class OV2640(_SCCBCameraBase): # pylint: disable=too-many-instance-attributes
1039
1047
1040
1048
def __init__ (
1041
1049
self ,
1042
- i2c_bus ,
1043
- data_pins ,
1044
- clock ,
1045
- vsync ,
1046
- href ,
1047
- shutdown = None ,
1048
- reset = None ,
1049
- mclk = None ,
1050
- mclk_frequency = 20_000_000 ,
1051
- i2c_address = 0x30 ,
1052
- size = OV2640_SIZE_QQVGA ,
1050
+ i2c_bus : I2C ,
1051
+ data_pins : Pin ,
1052
+ clock : Pin ,
1053
+ vsync : Pin ,
1054
+ href : Pin ,
1055
+ shutdown : Optional [ Pin ] = None ,
1056
+ reset : Optional [ Pin ] = None ,
1057
+ mclk : Optional [ Pin ] = None ,
1058
+ mclk_frequency : int = 20_000_000 ,
1059
+ i2c_address : int = 0x30 ,
1060
+ size : int = OV2640_SIZE_QQVGA ,
1053
1061
): # pylint: disable=too-many-arguments
1054
1062
"""
1055
1063
Args:
@@ -1122,11 +1130,11 @@ def __init__(
1122
1130
data_pins = data_pins , clock = clock , vsync = vsync , href = href
1123
1131
)
1124
1132
1125
- def capture (self , buf ) :
1133
+ def capture (self , buf : WriteableBuffer ) -> Optional [ memoryview ] :
1126
1134
"""Capture an image into the buffer.
1127
1135
1128
1136
Args:
1129
- buf (Union[bytearray, memoryview] ): A WritableBuffer to contain the \
1137
+ buf (WriteableBuffer ): A WritableBuffer to contain the \
1130
1138
captured image. Note that this can be a ulab array or a displayio Bitmap.
1131
1139
"""
1132
1140
self ._imagecapture .capture (buf )
@@ -1138,40 +1146,40 @@ def capture(self, buf):
1138
1146
return None
1139
1147
1140
1148
@property
1141
- def capture_buffer_size (self ):
1149
+ def capture_buffer_size (self ) -> int :
1142
1150
"""Return the size of capture buffer to use with current resolution & colorspace settings"""
1143
1151
if self .colorspace == OV2640_COLOR_JPEG :
1144
1152
return self .width * self .height // 5
1145
1153
return self .width * self .height * 2
1146
1154
1147
1155
@property
1148
- def mclk_frequency (self ):
1156
+ def mclk_frequency (self ) -> Optional [ int ] :
1149
1157
"""Get the actual frequency the generated mclk, or None"""
1150
1158
return self ._mclk_pwm .frequency if self ._mclk_pwm else None
1151
1159
1152
1160
@property
1153
- def width (self ):
1161
+ def width (self ) -> int :
1154
1162
"""Get the image width in pixels. A buffer of 2*width*height bytes \
1155
1163
stores a whole image."""
1156
1164
return self ._w
1157
1165
1158
1166
@property
1159
- def height (self ):
1167
+ def height (self ) -> int :
1160
1168
"""Get the image height in pixels. A buffer of 2*width*height bytes \
1161
1169
stores a whole image."""
1162
1170
return self ._h
1163
1171
1164
1172
@property
1165
- def colorspace (self ):
1173
+ def colorspace (self ) -> bytes :
1166
1174
"""Get or set the colorspace, one of the ``OV2640_COLOR_`` constants."""
1167
1175
return self ._colorspace
1168
1176
1169
1177
@colorspace .setter
1170
- def colorspace (self , colorspace ) :
1178
+ def colorspace (self , colorspace : bytes ) -> None :
1171
1179
self ._colorspace = colorspace
1172
1180
self ._set_size_and_colorspace ()
1173
1181
1174
- def _set_colorspace (self ):
1182
+ def _set_colorspace (self ) -> None :
1175
1183
colorspace = self ._colorspace
1176
1184
settings = _ov2640_color_settings [colorspace ]
1177
1185
@@ -1180,7 +1188,7 @@ def _set_colorspace(self):
1180
1188
self ._write_list (settings )
1181
1189
time .sleep (0.01 )
1182
1190
1183
- def deinit (self ):
1191
+ def deinit (self ) -> None :
1184
1192
"""Deinitialize the camera"""
1185
1193
self ._imagecapture .deinit ()
1186
1194
if self ._mclk_pwm :
@@ -1191,11 +1199,11 @@ def deinit(self):
1191
1199
self ._reset .deinit ()
1192
1200
1193
1201
@property
1194
- def size (self ):
1202
+ def size (self ) -> int :
1195
1203
"""Get or set the captured image size, one of the ``OV2640_SIZE_`` constants."""
1196
1204
return self ._size
1197
1205
1198
- def _set_size_and_colorspace (self ):
1206
+ def _set_size_and_colorspace (self ) -> None :
1199
1207
size = self ._size
1200
1208
width , height , ratio = _resolution_info [size ]
1201
1209
offset_x , offset_y , max_x , max_y = _ratio_table [ratio ]
@@ -1218,11 +1226,11 @@ def _set_size_and_colorspace(self):
1218
1226
self ._set_window (mode , offset_x , offset_y , max_x , max_y , width , height )
1219
1227
1220
1228
@size .setter
1221
- def size (self , size ) :
1229
+ def size (self , size : int ) -> None :
1222
1230
self ._size = size
1223
1231
self ._set_size_and_colorspace ()
1224
1232
1225
- def _set_flip (self ):
1233
+ def _set_flip (self ) -> None :
1226
1234
bits = 0
1227
1235
if self ._flip_x :
1228
1236
bits |= _REG04_HFLIP_IMG
@@ -1231,38 +1239,45 @@ def _set_flip(self):
1231
1239
self ._write_bank_register (_BANK_SENSOR , _REG04 , _REG04_SET (bits ))
1232
1240
1233
1241
@property
1234
- def flip_x (self ):
1242
+ def flip_x (self ) -> bool :
1235
1243
"""Get or set the X-flip flag"""
1236
1244
return self ._flip_x
1237
1245
1238
1246
@flip_x .setter
1239
- def flip_x (self , value ) :
1247
+ def flip_x (self , value : bool ) -> None :
1240
1248
self ._flip_x = bool (value )
1241
1249
self ._set_flip ()
1242
1250
1243
1251
@property
1244
- def flip_y (self ):
1252
+ def flip_y (self ) -> bool :
1245
1253
"""Get or set the Y-flip flag"""
1246
1254
return self ._flip_y
1247
1255
1248
1256
@flip_y .setter
1249
- def flip_y (self , value ) :
1257
+ def flip_y (self , value : bool ) -> None :
1250
1258
self ._flip_y = bool (value )
1251
1259
self ._set_flip ()
1252
1260
1253
1261
@property
1254
- def product_id (self ):
1262
+ def product_id (self ) -> int :
1255
1263
"""Get the product id (PID) register. The expected value is 0x26."""
1256
1264
return self ._read_bank_register (_BANK_SENSOR , _REG_PID )
1257
1265
1258
1266
@property
1259
- def product_version (self ):
1260
- """Get the version (VER) register. The expected value is 0x4x ."""
1267
+ def product_version (self ) -> int :
1268
+ """Get the version (VER) register. The expected value is 0x41 ."""
1261
1269
return self ._read_bank_register (_BANK_SENSOR , _REG_VER )
1262
1270
1263
- def _set_window (
1264
- self , mode , offset_x , offset_y , max_x , max_y , width , height
1265
- ): # pylint: disable=too-many-arguments, too-many-locals
1271
+ def _set_window ( # pylint: disable=too-many-arguments, too-many-locals
1272
+ self ,
1273
+ mode : int ,
1274
+ offset_x : int ,
1275
+ offset_y : int ,
1276
+ max_x : int ,
1277
+ max_y : int ,
1278
+ width : int ,
1279
+ height : int ,
1280
+ ) -> None :
1266
1281
self ._w = width
1267
1282
self ._h = height
1268
1283
@@ -1335,7 +1350,7 @@ def _set_window(
1335
1350
self .test_pattern = self ._test_pattern
1336
1351
1337
1352
@property
1338
- def exposure (self ):
1353
+ def exposure (self ) -> int :
1339
1354
"""The exposure level of the sensor"""
1340
1355
aec_9_2 = self ._get_reg_bits (_BANK_SENSOR , _AEC , 0 , 0xFF )
1341
1356
aec_15_10 = self ._get_reg_bits (_BANK_SENSOR , _REG45 , 0 , 0b111111 )
@@ -1344,7 +1359,7 @@ def exposure(self):
1344
1359
return aec_1_0 | (aec_9_2 << 2 ) | (aec_15_10 << 10 )
1345
1360
1346
1361
@exposure .setter
1347
- def exposure (self , exposure ) :
1362
+ def exposure (self , exposure : int ) -> None :
1348
1363
aec_1_0 = exposure & 0x11
1349
1364
aec_9_2 = (exposure >> 2 ) & 0b11111111
1350
1365
aec_15_10 = exposure >> 10
0 commit comments