pypicoboot 1.1.5__tar.gz → 1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pypicoboot
3
- Version: 1.1.5
3
+ Version: 1.3
4
4
  Summary: Pico Boot for Python
5
5
  Home-page: https://github.com/polhenarejos/pypicoboot
6
6
  Author: Pol Henarejos
@@ -0,0 +1,3 @@
1
+ from ._version import __version__
2
+ from .picoboot import PicoBoot, Model
3
+ from .core.exceptions import PicoBootError, PicoBootNotFoundError, PicoBootInvalidStateError
@@ -17,4 +17,4 @@
17
17
  */
18
18
  """
19
19
 
20
- __version__ = "1.1.5"
20
+ __version__ = "1.3"
@@ -1 +1,2 @@
1
1
  from .enums import NamedIntEnum
2
+ from .exceptions import *
@@ -0,0 +1,28 @@
1
+ """
2
+ /*
3
+ * This file is part of the pypicoboot distribution (https://github.com/polhenarejos/pypicoboot).
4
+ * Copyright (c) 2025 Pol Henarejos.
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU Affero General Public License as published by
8
+ * the Free Software Foundation, version 3.
9
+ *
10
+ * This program is distributed in the hope that it will be useful, but
11
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Affero General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License
16
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+ """
19
+
20
+
21
+ class PicoBootError(Exception):
22
+ pass
23
+
24
+ class PicoBootNotFoundError(PicoBootError):
25
+ pass
26
+
27
+ class PicoBootInvalidStateError(PicoBootError):
28
+ pass
@@ -0,0 +1,58 @@
1
+ """
2
+ /*
3
+ * This file is part of the pypicoboot distribution (https://github.com/polhenarejos/pypicoboot).
4
+ * Copyright (c) 2025 Pol Henarejos.
5
+ *
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU Affero General Public License as published by
8
+ * the Free Software Foundation, version 3.
9
+ *
10
+ * This program is distributed in the hope that it will be useful, but
11
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ * Affero General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License
16
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+ """
19
+
20
+ import os
21
+ import logging
22
+
23
+ TRACE_LEVEL = 5
24
+ logging.addLevelName(TRACE_LEVEL, "TRACE")
25
+
26
+ def trace(self, message, *args, **kwargs):
27
+ if self.isEnabledFor(TRACE_LEVEL):
28
+ self._log(TRACE_LEVEL, message, args, **kwargs)
29
+
30
+ # Afegeix logger.trace()
31
+ logging.Logger.trace = trace
32
+
33
+ def get_logger(name: str):
34
+ env_level = os.getenv("PICOBOOT_LOG", "CRITICAL").upper()
35
+
36
+ valid_levels = {
37
+ "TRACE": TRACE_LEVEL,
38
+ "DEBUG": logging.DEBUG,
39
+ "INFO": logging.INFO,
40
+ "WARNING": logging.WARNING,
41
+ "ERROR": logging.ERROR,
42
+ "CRITICAL": logging.CRITICAL,
43
+ }
44
+
45
+ level = valid_levels.get(env_level, logging.CRITICAL)
46
+
47
+ logger = logging.getLogger(name)
48
+ logger.setLevel(level)
49
+
50
+ if not logger.handlers:
51
+ handler = logging.StreamHandler()
52
+ handler.setFormatter(logging.Formatter(
53
+ fmt="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
54
+ datefmt="%Y-%m-%d %H:%M:%S"
55
+ ))
56
+ logger.addHandler(handler)
57
+
58
+ return logger
@@ -16,31 +16,6 @@
16
16
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
17
  */
18
18
  """
19
- import os
20
- import logging
21
-
22
- def get_logger(name: str):
23
- env_level = os.getenv("PICOBOOT_LOG", "CRITICAL").upper()
24
-
25
- valid_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
26
- if env_level not in valid_levels:
27
- print(f"[logger] Warning: nivell '{env_level}' invàlid. Usant INFO.")
28
- env_level = "INFO"
29
-
30
- logger = logging.getLogger(name)
31
- logger.setLevel(env_level)
32
-
33
- if not logger.handlers:
34
- handler = logging.StreamHandler()
35
- handler.setFormatter(logging.Formatter(
36
- fmt="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
37
- datefmt="%Y-%m-%d %H:%M:%S"
38
- ))
39
- logger.addHandler(handler)
40
-
41
- return logger
42
-
43
- logger = get_logger("picoboot")
44
19
 
45
20
  from binascii import hexlify
46
21
  from typing import Optional
@@ -51,6 +26,10 @@ import itertools
51
26
  from .utils import uint_to_int
52
27
  from .core.enums import NamedIntEnum
53
28
  from .picobootmonitor import PicoBootMonitor, PicoBootMonitorObserver
29
+ from .core.log import get_logger
30
+ from .core.exceptions import PicoBootError, PicoBootNotFoundError, PicoBootInvalidStateError
31
+
32
+ logger = get_logger("PicoBoot")
54
33
 
55
34
  # Valors per defecte segons el datasheet (es poden canviar via OTP) :contentReference[oaicite:4]{index=4}
56
35
  DEFAULT_VID = 0x2E8A
@@ -156,9 +135,6 @@ class Model(NamedIntEnum):
156
135
  class Addresses(NamedIntEnum):
157
136
  BOOTROM_MAGIC = 0x00000010
158
137
 
159
- class PicoBootError(Exception):
160
- pass
161
-
162
138
  class PicoBoot:
163
139
 
164
140
  def __init__(self, dev: usb.core.Device, intf, ep_out, ep_in) -> None:
@@ -215,7 +191,7 @@ class PicoBoot:
215
191
  devices = list(devices) if devices is not None else []
216
192
  if not devices:
217
193
  logger.error("No device found in PICOBOOT mode")
218
- raise PicoBootError("No device found in PICOBOOT mode")
194
+ raise PicoBootNotFoundError("No device found in PICOBOOT mode")
219
195
 
220
196
  dev = None
221
197
  if serial is None:
@@ -233,7 +209,7 @@ class PicoBoot:
233
209
  break
234
210
  if dev is None:
235
211
  logger.error("No device found with this serial number")
236
- raise PicoBootError("No device found with this serial number")
212
+ raise PicoBootNotFoundError("No device found with this serial number")
237
213
 
238
214
  # Ensure active configuration
239
215
  # macOS does not allow detach_kernel_driver, and often returns Access Denied
@@ -262,7 +238,7 @@ class PicoBoot:
262
238
  break
263
239
  if intf is None:
264
240
  logger.error("No interface found with PICOBOOT at the device")
265
- raise PicoBootError("No interface found with PICOBOOT at the device")
241
+ raise PicoBootNotFoundError("No interface found with PICOBOOT at the device")
266
242
 
267
243
  #usb.util.claim_interface(dev, intf.bInterfaceNumber)
268
244
 
@@ -278,7 +254,7 @@ class PicoBoot:
278
254
 
279
255
  if ep_in is None or ep_out is None:
280
256
  logger.error("No PICOBOOT BULK_IN/BULK_OUT endpoints found")
281
- raise PicoBootError("No PICOBOOT BULK_IN/BULK_OUT endpoints found")
257
+ raise PicoBootNotFoundError("No PICOBOOT BULK_IN/BULK_OUT endpoints found")
282
258
  logger.info("PICOBOOT device opened successfully.")
283
259
  return cls(dev, intf, ep_out, ep_in)
284
260
 
@@ -369,7 +345,12 @@ class PicoBoot:
369
345
  raise
370
346
  logger.debug(f"Sending command {cmd_id} (0x{cmd_id:02X}) with token {token} (0x{token:08X}) and transfer_length {transfer_length}")
371
347
 
372
- self.ep_out.write(header, timeout=timeout)
348
+ logger.trace(f"Command header: {hexlify(header).decode()}")
349
+ try:
350
+ self.ep_out.write(header, timeout=timeout)
351
+ except usb.core.USBError as e:
352
+ logger.error(f"Failed to send command header: {e}")
353
+ raise PicoBootInvalidStateError("Failed to send command header: " + str(e))
373
354
  logger.debug(f"Command header sent: {hexlify(header).decode()}")
374
355
 
375
356
  data_in = b""
@@ -380,12 +361,17 @@ class PicoBoot:
380
361
  chunks = []
381
362
  maxpkt = self.ep_in.wMaxPacketSize
382
363
  while remaining > 0:
383
- chunk = bytes(self.ep_in.read(min(maxpkt, remaining), timeout=timeout))
364
+ try:
365
+ chunk = bytes(self.ep_in.read(min(maxpkt, remaining), timeout=timeout))
366
+ except usb.core.USBError as e:
367
+ logger.error(f"Failed to read data_in: {e}")
368
+ raise PicoBootInvalidStateError("Failed to read data_in: " + str(e))
384
369
  if not chunk:
385
370
  break
386
371
  chunks.append(chunk)
387
372
  remaining -= len(chunk)
388
373
  data_in = b"".join(chunks)
374
+ logger.trace(f"Received data_in: {hexlify(data_in).decode()}")
389
375
  if len(data_in) != transfer_length:
390
376
  logger.error(f"Expected {transfer_length} bytes, got {len(data_in)}")
391
377
  raise PicoBootError(f"Expected {transfer_length} bytes, got {len(data_in)}")
@@ -393,7 +379,12 @@ class PicoBoot:
393
379
  if data_out is None or len(data_out) < transfer_length:
394
380
  logger.error("data_out missing or too short for OUT command")
395
381
  raise ValueError("data_out missing or too short for OUT command")
396
- self.ep_out.write(data_out[:transfer_length], timeout=timeout)
382
+ logger.trace(f"Sending data_out: {hexlify(data_out[:transfer_length]).decode()}")
383
+ try:
384
+ self.ep_out.write(data_out[:transfer_length], timeout=timeout)
385
+ except usb.core.USBError as e:
386
+ logger.error(f"Failed to send data_out: {e}")
387
+ raise PicoBootInvalidStateError("Failed to send data_out: " + str(e))
397
388
 
398
389
  try:
399
390
  logger.debug("Waiting for ACK...")
@@ -404,6 +395,7 @@ class PicoBoot:
404
395
  except usb.core.USBError:
405
396
  logger.error("No ACK received after command")
406
397
  raise PicoBootError("No ACK received after command")
398
+ logger.debug("ACK received.")
407
399
 
408
400
  return data_in
409
401
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pypicoboot
3
- Version: 1.1.5
3
+ Version: 1.3
4
4
  Summary: Pico Boot for Python
5
5
  Home-page: https://github.com/polhenarejos/pypicoboot
6
6
  Author: Pol Henarejos
@@ -9,6 +9,8 @@ picoboot/picobootmonitor.py
9
9
  picoboot/utils.py
10
10
  picoboot/core/__init__.py
11
11
  picoboot/core/enums.py
12
+ picoboot/core/exceptions.py
13
+ picoboot/core/log.py
12
14
  picoboot/tools/picotool.py
13
15
  pypicoboot.egg-info/PKG-INFO
14
16
  pypicoboot.egg-info/SOURCES.txt
@@ -1,2 +0,0 @@
1
- from ._version import __version__
2
- from .picoboot import PicoBoot, Model
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes