diff --git a/Documentation/Fabrication/MPRLS_pressure_sensor/README.md b/Documentation/Fabrication/MPRLS_pressure_sensor/README.md deleted file mode 100644 index e499544..0000000 --- a/Documentation/Fabrication/MPRLS_pressure_sensor/README.md +++ /dev/null @@ -1,90 +0,0 @@ -# FLipMouse MPRLS Pressure Sensor Board - -**Fabrication Note v1.0, AsTeRICS Foundation** - -![FLipMouseLogo](./img/flipmouseLogo.png) - -# Scope - -The FLipMouse uses a pressure sensor to detect any sip and puff input on the mouthpiece. - -Version 2 uses a MPXV7007GP pressure sensor, which provides an analog value, exactly half of the supply voltage when idle. - -From 2022 onwards, this sensor is getting VERY expensive (~11$ 2021; ~35$ 2022) and hard to buy (~52 weeks lead time). - -Version 3 of the mouse supports 2 different types of sensors: - -* MPXV7007GP (same sensor as in FMv2) -* MPRLS0025PA00001A - -There are major differences between these two: - -* MPRLS uses I2C -* MPRLS is an absolute pressure sensor, needs calibration on FM startup -* MPRLS is not hand-solder friendly - -Because this sensor is basically impossible to solder with a solder iron. We still want to ship this sensor with assembled devices as well as construction kits, therefore we designed a small adapter PCB which needs to be __reflow soldered__ before further use. - -# Preparation - -## Material - -| Nr. | Description | Source | Image | -| ---- | ------------------------ | -------------------------------------- | ----- | -| 1 | MPRLS adapter PCB | | | -| 2 | 3 parts as stated in BOM | | | - -__Note: Material will be referenced in square brackets: []__ - -## Tools - -| Nr. | Description | Source | Image | -| ---- | --------------------------------- | ------------------------------------------------------------ | ------------------------------------------------- | -| 1 | Reflow solder equipment | Fablab, or university. You need a reflow oven, a stencil, solder paste, tweezers | | -| 2 | Testbench for MPRLS | | ![Picture of sensor testbench](img/testbench.jpg) | -| 3 | Permanent marker (red/blue/green) | DYI store, paper store (possibly any store) | | - -__Note: Tools will be referenced in curly brackets: {}__ - -
-# Procedure - -__Prepare PCB:__ - -1. Mount the stencil on your holder _{1}_ -1. Apply solder paste on PCB(s) _[1]_ - -__Place parts: (note: guaranteed information is available in the KiCAD project, this is for reference only)__ - -1. Place the MPRLS sensor, pin one has a small triangle _{2}_ -2. Place both capacitors (1nF / 100nF) _{2}_ - -__Solder:__ - -1. Follow the instructions for your reflow solder equipment to solder the PCBs - -__Testing:__ - -1. This sensor can be prone to solder errors, especially if you are not experienced in reflow soldering & paste application -2. Follow the test procedure for __EVERY__ soldered sensor PCB - - - -# Testing - -Sensor testing is done via the testbench for sensors, which is based on a Teensy. - -1. Attach the testbench to a USB port (micro USB cable) -2. Wait for finished initialisation, `Insert device` should be shown on the display -3. Attach each sensor under test on the left pin header (4pins): ![sensor connected on the testbench](img/sensorattached.jpg) -4. Hold down the sensor for the test to provide sufficient contact without soldering -5. The display should show `Found dev @0x18`, `MPRLS pressure`. __If not:__ This sensor is broken -6. Wait for the tester to run a test cycle -7. The display should show now: `Fin, avg.: xxx`, the actual value depends on your ambient pressure, but should be in the __range of 400-600__. __If not:__ this sensor is broken. -8. Every character on the __second line__ should be a __`+` symbol__. __If not:__ Either there was a bad contact (press the sensor against the pins and re-run the test) or this sensor is broken (if you tried it more than once). -9. If the test finished successfully, __mark this sensor__ with a permanent marker _{3}_. -10. Repeat the procedure with another sensor from __step 3__. - -## Documentation - -For each produced batch, fill out one document __template_MPRLS_production.ots__ and save it as: `mprls_.ods`(e.g.: mprls_20221118.ods) diff --git a/Documentation/Fabrication/MPRLS_pressure_sensor/README.pdf b/Documentation/Fabrication/MPRLS_pressure_sensor/README.pdf deleted file mode 100644 index 0ef4a02..0000000 Binary files a/Documentation/Fabrication/MPRLS_pressure_sensor/README.pdf and /dev/null differ diff --git a/Documentation/Fabrication/MPRLS_pressure_sensor/img/flipmouseLogo.png b/Documentation/Fabrication/MPRLS_pressure_sensor/img/flipmouseLogo.png deleted file mode 100644 index d6f4892..0000000 Binary files a/Documentation/Fabrication/MPRLS_pressure_sensor/img/flipmouseLogo.png and /dev/null differ diff --git a/Documentation/Fabrication/MPRLS_pressure_sensor/img/sensorattached.jpg b/Documentation/Fabrication/MPRLS_pressure_sensor/img/sensorattached.jpg deleted file mode 100644 index 5a4718b..0000000 Binary files a/Documentation/Fabrication/MPRLS_pressure_sensor/img/sensorattached.jpg and /dev/null differ diff --git a/Documentation/Fabrication/MPRLS_pressure_sensor/img/testbench.jpg b/Documentation/Fabrication/MPRLS_pressure_sensor/img/testbench.jpg deleted file mode 100644 index 90564ef..0000000 Binary files a/Documentation/Fabrication/MPRLS_pressure_sensor/img/testbench.jpg and /dev/null differ diff --git a/Documentation/Fabrication/MPRLS_pressure_sensor/template_MPRLS_production.ots b/Documentation/Fabrication/MPRLS_pressure_sensor/template_MPRLS_production.ots deleted file mode 100644 index 9d2b7ec..0000000 Binary files a/Documentation/Fabrication/MPRLS_pressure_sensor/template_MPRLS_production.ots and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/FM.uf2 b/Documentation/Fabrication/rp2040_preparation/FM.uf2 deleted file mode 100644 index 7124e16..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/FM.uf2 and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/README.md b/Documentation/Fabrication/rp2040_preparation/README.md deleted file mode 100644 index acfe174..0000000 --- a/Documentation/Fabrication/rp2040_preparation/README.md +++ /dev/null @@ -1,90 +0,0 @@ -# FLipMouse/Pad Arduino Initialisation - -**Fabrication Note v1.0, AsTeRICS Foundation** - -![FLipMouseLogo](./img/flipmouseLogo.png) - -# Scope - -FLipMouse and FLipPad use from version 3 onward an __Arduino Nano RP2040 Connect__ platform. - -The big advantage over the TeensyLC from version 2, this controller has much more RAM & ROM and already contains the ESP32, which is used for the Bluetooth connectivity. - -To fully use the update procedures from the WebGUI, the Arduino needs to be programmed initially: - -* __esp32_addon_bootloader:__ Bootloader Code to update the ESP32 BLE Mouse/Keyboard firmware without esptool.py -* __esp32_mouse_keyboard:__ Program the BLE HID over GATT firmware -* __FLipMouse/FLipPad firmware:__ Program the RP2040 with the current FLipMouse / FLipPad Firmware - -# Preparation - -## Material - -| Nr. | Description | Source | Image | -| ---- | ---------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | -| 1 | Arduino Nano RP2040 Connect | https://store.arduino.cc/products/arduino-nano-rp2040-connect | ![A new Arduino Nano RP2040 connect](./img/rp2040_unmarked.png) | - -__Note: Material will be referenced in square brackets: []__ - -## Tools / Requirements - -| Nr. | Description | Source | -| ---- | --------------------------------- | ------------------------------------------------------------ | -| 1 | Terminal + Python3 | Install python according to your OS | -| 2 | esptool | Install via pip: `pip install esptool` (if it cannot be executed from a terminal, run this command as root) | -| 2 | Permanent marker (red/blue/green) | DYI store, paper store (possibly any store) | - -__Note: Tools will be referenced in curly brackets: {}__ - -
-# Procedure - -1. Attach the Arduino Nano RP2040 Connect _[1]_ to the computer -2. Open a terminal -3. Call the script: `rp2040_prepare.py -t -p ` - -_-t_ Select the firmware to be flashed, either FP for FLipPad, FM for FLipMouse of FB for FABI (FP & FB are not finished yet) - -_-p_ Select a serial port which should be flashed (normally COMxx on Windows, /dev/ttyxxx on Linux) - -# Testing - -Not available, if procedure is followed, the software is flashed correctly: - -* __Blue blinking__ LED for a flashed Bluetooth firmware - -## Documentation - -For each produced batch, fill out one document __template_arduino_init_production.ots__ and save it as: `arduino_init_.ods`(e.g.: arduino_init_20221118.ods) - - -## Updating the firmware builds to be flashed - - - -1. Replace `bootloader.bin`,`esp32_addon_bootloader.bin`, `ota_initial_data.bin` and `partition-table.bin`with a current build from: _esp32_addon_bootloader/build/esp32_addon_bootloader.bin_ -2. Replace `mousekeyboard.bin` with a current build from: _esp32_mouse_keyboard/build/esp32_mouse_keyboard.bin_ -3. Replace `FM.uf2`, `FP.uf2`, `FB.uf2` with current builds from the FLipWare/FabiWare repositories (build with Arduino and select _Sketch->Export compiled binary_) -4. Replace `serialflasher1.uf2` with a new build from the serialflasher1.ino sketch from this directory (build with Arduino and select _Sketch->Export compiled binary_) -5. Replace `serialflasher2.uf2` with a new build from the serialflasher2.ino sketch from this directory (build with Arduino and select _Sketch->Export compiled binary_) -7. __Write down the current GIT tags (releases) or commit numbers for the builds to _VERSIONS.md_ __ - - - -## Insights - - - -This tool performs following steps: - -1. Flashing the serialflasher1.uf2 firmware calling `uf2conv.py`tool -2. Flashing the esp32_addon_bootloader firmware with `esptool.py` -3. Flashing the serialflasher2.uf2 firmware calling `uf2conv.py` tool -4. Flash the esp32_mouse_keyboard_firmware (included in rp2040_prepare.py) -5. Reset the Arduino to UF2 download mode by opening the given serial port with 1200Baud and closing it -6. Flashing the FM/FB/FP.uf2 firmware calling `uf2conv.py`tool -7. Verifying that everything worked by sending "AT BC $ID" to the serial port, which returns the version of the BLE module. This is printed on the command line. -8. Start over (wait until serial port is removed and a new one is detected) - - - diff --git a/Documentation/Fabrication/rp2040_preparation/README.pdf b/Documentation/Fabrication/rp2040_preparation/README.pdf deleted file mode 100644 index 46fc8ff..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/README.pdf and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/VERSIONS.md b/Documentation/Fabrication/rp2040_preparation/VERSIONS.md deleted file mode 100644 index cb52f59..0000000 --- a/Documentation/Fabrication/rp2040_preparation/VERSIONS.md +++ /dev/null @@ -1,21 +0,0 @@ -# Versions for intermediate serial/usb passthrough sketches - -serialflasher1.uf2 no version code, first commit -serialflasher2.uf2 no version code, first commit - -# Versions for esp32_addon_bootloader binary files - -__Note:__ You need to update all of these files! - -esp32_addon_bootloader.bin 5bd3413 (RP2040 branch) -ota_data_initial.bin 5bd3413 (RP2040 branch) -bootloader.bin 5bd3413 (RP2040 branch) -partition-table.bin 5bd3413 (RP2040 branch) - -# Versions for the esp32_mouse_keyboard binary file - -esp32_mouse_keyboard.bin fa59627 (RP2040 branch) - -# Versions for FLipWare - -FM.uf 712338a (RP2040 branch) diff --git a/Documentation/Fabrication/rp2040_preparation/bootloader.bin b/Documentation/Fabrication/rp2040_preparation/bootloader.bin deleted file mode 100644 index 58123a1..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/bootloader.bin and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/esp32_addon_bootloader.bin b/Documentation/Fabrication/rp2040_preparation/esp32_addon_bootloader.bin deleted file mode 100644 index 7c68565..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/esp32_addon_bootloader.bin and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/esp32_mouse_keyboard.bin b/Documentation/Fabrication/rp2040_preparation/esp32_mouse_keyboard.bin deleted file mode 100644 index 5c8780e..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/esp32_mouse_keyboard.bin and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/flash.bin b/Documentation/Fabrication/rp2040_preparation/flash.bin deleted file mode 100644 index 7ffcc2e..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/flash.bin and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/img/flipmouseLogo.png b/Documentation/Fabrication/rp2040_preparation/img/flipmouseLogo.png deleted file mode 100644 index d6f4892..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/img/flipmouseLogo.png and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/img/rp2040_marked.png b/Documentation/Fabrication/rp2040_preparation/img/rp2040_marked.png deleted file mode 100644 index 5664cf6..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/img/rp2040_marked.png and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/img/rp2040_unmarked.png b/Documentation/Fabrication/rp2040_preparation/img/rp2040_unmarked.png deleted file mode 100644 index d2b2da3..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/img/rp2040_unmarked.png and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/ota_data_initial.bin b/Documentation/Fabrication/rp2040_preparation/ota_data_initial.bin deleted file mode 100644 index b4033a7..0000000 --- a/Documentation/Fabrication/rp2040_preparation/ota_data_initial.bin +++ /dev/null @@ -1 +0,0 @@ -ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ \ No newline at end of file diff --git a/Documentation/Fabrication/rp2040_preparation/partition-table.bin b/Documentation/Fabrication/rp2040_preparation/partition-table.bin deleted file mode 100644 index e8ef43e..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/partition-table.bin and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/rp2040_preparation.py b/Documentation/Fabrication/rp2040_preparation/rp2040_preparation.py deleted file mode 100644 index 2bbf07a..0000000 --- a/Documentation/Fabrication/rp2040_preparation/rp2040_preparation.py +++ /dev/null @@ -1,260 +0,0 @@ -#!/usr/bin/env python3 - -# rp2040_preparation.py - -# Python tool for initial flashing of -# * esp32_addon_bootloader -# * esp32_mouse_keyboard -# * FLipMouse / FLipWare / FabiWare firmwares -# Please refer to README.md for documentation - -# Copyright 2022 Benjamin Aigner - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. -# - -import argparse -import serial -import io -import sys -import os -import time -import subprocess - -devices = { - 'FM': "FLipMouse", - 'FP': "FLipPad", - 'FB': "FABI" -} - -#subprocess.run('python D:/your_script.py') - -def main(): - def error(msg): - print(msg) - sys.exit(1) - parser = argparse.ArgumentParser(description='Prepare Arduino Nano RP2040 connect for FLipMouse, FLipPad or FABI') - parser.add_argument('-d' , '--device', dest="device", - help='select a device type to be flashed (FM, FP or FB)') - parser.add_argument('-s', '--serial', dest='serial', help='Serial port to reset before upload') - parser.add_argument('-o', '--start_with', dest='startwith', help='Start with this step') - args = parser.parse_args() - - if not args.device: - error("Error: Need a device type (e.g. -d FM)") - elif not args.device.upper() in devices: - error("Error: Need a correct device type (e.g. -d FM)") - else: - global current_device - current_device = args.device.upper() - - if not args.serial: - error("Error: Need a serial port (e.g. COM2 or /dev/ttyACM0)") - else: - global current_serial - current_serial = args.serial - - global startwith - if args.startwith: - startwith = int(args.startwith) - print("Starting with step " + args.startwith) - else: - startwith = 0 - - while 1: - print("Flashing " + devices[args.device] + " firmware to " + args.serial) - - # 1.) serialflasher1.uf2 -> esptool.py compatible serial interface to the ESP32, ESP32 is in download mode - if startwith <= 1: - print("Part 1 ###############################################") - proc = subprocess.run(["python3","uf2conv.py","serialflasher1.uf2","-s", current_serial,"-D"], capture_output=True, text=True) - print(proc.stdout) - if proc.returncode != 0: - print("Error flashing UF2 'serialflasher1.uf2'") - exit - time.sleep(5) - - # 2.) esptool.py -> flash the bootloader - if startwith <= 2: - print("Part 2 ###############################################") - retry = 0 - while 1: - # this was the output from idf.py build: - # esptool.py -p (PORT) -b 460800 --before no_reset --after hard_reset --chip esp32 write_flash --flash_mode dio --flash_size detect --flash_freq 40m - # 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0xd000 build/ota_data_initial.bin 0x10000 build/esp32_addon_bootloader.bin - proc = subprocess.run(["esptool.py","--port", current_serial,"--baud", "115200", "--before", "no_reset", "--after", "no_reset", "--chip", "esp32", "write_flash", \ - "--flash_mode", "dio", "--flash_size", "detect", "--flash_freq", "40m", \ - "0x1000", "bootloader.bin", "0x8000", "partition-table.bin", "0xd000", "ota_data_initial.bin", "0x10000", "esp32_addon_bootloader.bin"], capture_output=True, text=True) - print(proc.stdout) - print(proc.stderr) - if proc.returncode != 0: - print("Error flashing esp32_addon_bootloader.bin") - retry = retry + 1 - if retry > 10: - exit - else: - break - time.sleep(1) - - # 3.) serialflasher2.uf2 -> usb to serial passthrough sketch with 500k, compatible to FM/FP/FB ESP32 update mode - if startwith <= 3: - print("Part 3 ###############################################") - proc = subprocess.run(["python3","uf2conv.py","serialflasher2.uf2","-s", current_serial,"-D"], capture_output=True, text=True) - print(proc.stdout) - if proc.returncode != 0: - print("Error flashing UF2 'serialflasher1.uf2'") - exit - - - # 4.) wait for "OTA:ready" signal - if startwith <= 4: - print("Part 4 ###############################################") - retry = 0 - while 1: - try: - ser = serial.Serial(current_serial, timeout=1) - break - except Exception: - retry = retry + 1 - if retry > 10: - exit - else: - time.sleep(0.5) - - # avoid a Windows quirk: the Arduino does not respond to any data, if the DTR line is not set - if os.name == 'nt': - ser.dtr = True - ser.flushInput() - tries = 0 - while 1: - try: - line = ser.readline() - print(str(line)) - line = line.decode() - if line == "OTA:ready\r\n": - print("Got OTA:ready") - break - else: - tries = tries + 1 - if tries > 20: - error("Not receiving OTA:ready") - break - except Exception: - continue - - # 5.) flash esp32_mouse_keyboard.bin with update.py code - if startwith <= 5: - print("Part 5 ###############################################") - if not ser: - retry = 0 - while 1: - try: - ser = serial.Serial(current_serial, timeout=1) - break - except Exception: - retry = retry + 1 - if retry > 10: - exit - else: - time.sleep(0.5) - # as long as there is something available in the input file - with open('esp32_mouse_keyboard.bin', "rb") as input: - while True: - # read in 128B chunks - data = input.read(128) - #datalen += len(data) - #print(datalen) - ser.write(data) - ser.flush() - # if this is the last block (less than 128B) - if len(data) < 128: - # finished... - print("Finished") - break - #sleep for 10ms - time.sleep(10 / 1000) - # any feedback? - if ser.in_waiting: - line = ser.read(100) - print(line.decode()) - ser.flush() - - tries = 0 - while 1: - try: - line = ser.readline() - print(str(line)) - line = line.decode() - if line == "OTA:$FINISHED\r\n": - print("Got OTA:$FINISHED\r\n") - break - else: - tries = tries + 1 - if tries > 20: - error("Not receiving OTA:$FINISHED") - break - except Exception: - continue - ser.close() - - # 6.) FM/FB/FP.uf2 -> selected device firmware - if startwith <= 6: - print("Part 6 ###############################################") - proc = subprocess.run(["python3","uf2conv.py",current_device + ".uf2","-s", current_serial,"-D"], capture_output=True, text=True) - print(proc.stdout) - if proc.returncode != 0: - print(proc.stderr) - print("Error flashing UF2 '"+current_device+".uf2'") - exit - - # 7.) test output of "AT BC $ID" to confirm working firmware for RP2040 & ESP32 - if startwith <= 7: - print("Part 7 ###############################################") - retry = 0 - while 1: - try: - ser = serial.Serial(current_serial, timeout=1) - break - except Exception: - retry = retry + 1 - if retry > 10: - exit - else: - time.sleep(0.5) - #set device name depending on selected module - ser.write(str("AT BC $NAME "+devices[current_device] + "\r\n").encode()) - print(ser.readline().decode()) - retry = 0 - while 1: - ser.write(str("AT BC $ID\r\n").encode()) - line = ser.readline().decode() - if line.startswith("ESP32"): - break - else: - retry = retry + 1 - if retry > 15: - print("Error getting ESP32 revision number") - break - time.sleep(1) - ser.close() - - print("Finished - waiting 5s before starting new cycle") - # TODO: endless cycles? - break - time.sleep(5) - -if __name__ == "__main__": - main() diff --git a/Documentation/Fabrication/rp2040_preparation/serialflasher1.uf2 b/Documentation/Fabrication/rp2040_preparation/serialflasher1.uf2 deleted file mode 100644 index 9bc15a6..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/serialflasher1.uf2 and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/serialflasher1/serialflasher1.ino b/Documentation/Fabrication/rp2040_preparation/serialflasher1/serialflasher1.ino deleted file mode 100644 index 9c8f4d2..0000000 --- a/Documentation/Fabrication/rp2040_preparation/serialflasher1/serialflasher1.ino +++ /dev/null @@ -1,56 +0,0 @@ -/* - * RP2040 - ESP32 serial passthrough - * - * Resets the ESP32 into download mode when flashed (115k2 Baud) - */ - - -#define ORANGE_LED_PIN 6 - -#define ESP32_RESET_PIN 3 -#define ESP32_GPIO0_PIN 2 - -#define LED_TOGGLE_TIME 20000 - - -void setup() { - //LED output - pinMode(ORANGE_LED_PIN, OUTPUT); - //ESP32 reset / download pins - pinMode(ESP32_RESET_PIN, OUTPUT); - pinMode(ESP32_GPIO0_PIN, OUTPUT); - - //enable both serial interfaces - Serial.begin(115200); - Serial2.begin(115200); - - //enable ESP32 into download mode - digitalWrite(ESP32_GPIO0_PIN,LOW); // connect GPIO0 to GND - digitalWrite(ESP32_RESET_PIN,LOW); // reset ESP32 - delay(100); - digitalWrite(ESP32_RESET_PIN,HIGH); - delay(100); - digitalWrite(ESP32_GPIO0_PIN,HIGH); -} - -long cnt=0; -long bypass_reset=0; - -// the loop function runs over and over again forever -void loop() { - // toggle LED - - if (!(cnt++ % LED_TOGGLE_TIME)) - digitalWrite(ORANGE_LED_PIN,!digitalRead(ORANGE_LED_PIN)); - - // pass serial transfer to Serial2 (ESP) - - if (Serial.available()) { // If anything comes in Serial (USB), - Serial2.write(Serial.read()); // read it and send it out Serial1 (pins 0 & 1) - } - - if (Serial2.available()) { // If anything comes in Serial1 (pins 0 & 1) - Serial.write(Serial2.read()); // read it and send it out Serial (USB) - } - -} diff --git a/Documentation/Fabrication/rp2040_preparation/serialflasher1/serialflasher1.ino.arduino_nano_connect.uf2 b/Documentation/Fabrication/rp2040_preparation/serialflasher1/serialflasher1.ino.arduino_nano_connect.uf2 deleted file mode 100644 index 9bc15a6..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/serialflasher1/serialflasher1.ino.arduino_nano_connect.uf2 and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/serialflasher2.uf2 b/Documentation/Fabrication/rp2040_preparation/serialflasher2.uf2 deleted file mode 100644 index acdf7ae..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/serialflasher2.uf2 and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/serialflasher2/serialflasher2.ino b/Documentation/Fabrication/rp2040_preparation/serialflasher2/serialflasher2.ino deleted file mode 100644 index 7ed9d4b..0000000 --- a/Documentation/Fabrication/rp2040_preparation/serialflasher2/serialflasher2.ino +++ /dev/null @@ -1,54 +0,0 @@ -/* - * RP2040 - ESP32 serial passthrough - * - * Enables the ESP32 and passes serial data through (500kBaud) - */ - - -#define ORANGE_LED_PIN 6 - -#define ESP32_RESET_PIN 3 -#define ESP32_GPIO0_PIN 2 - -#define LED_TOGGLE_TIME 20000 - - -void setup() { - //LED output - pinMode(ORANGE_LED_PIN, OUTPUT); - //ESP32 reset / download pins - pinMode(ESP32_RESET_PIN, OUTPUT); - pinMode(ESP32_GPIO0_PIN, OUTPUT); - - //enable both serial interfaces - Serial.begin(500000); - Serial2.begin(500000); - - //enable ESP32 into normal mode - digitalWrite(ESP32_GPIO0_PIN,HIGH); // connect GPIO0 to VCC - digitalWrite(ESP32_RESET_PIN,LOW); // reset ESP32 - delay(10); - digitalWrite(ESP32_RESET_PIN,HIGH); -} - -long cnt=0; -long bypass_reset=0; - -// the loop function runs over and over again forever -void loop() { - // toggle LED - - if (!(cnt++ % LED_TOGGLE_TIME)) - digitalWrite(ORANGE_LED_PIN,!digitalRead(ORANGE_LED_PIN)); - - // pass serial transfer to Serial2 (ESP) - - if (Serial.available()) { // If anything comes in Serial (USB), - Serial2.write(Serial.read()); // read it and send it out Serial1 (pins 0 & 1) - } - - if (Serial2.available()) { // If anything comes in Serial1 (pins 0 & 1) - Serial.write(Serial2.read()); // read it and send it out Serial (USB) - } - -} diff --git a/Documentation/Fabrication/rp2040_preparation/serialflasher2/serialflasher2.ino.arduino_nano_connect.uf2 b/Documentation/Fabrication/rp2040_preparation/serialflasher2/serialflasher2.ino.arduino_nano_connect.uf2 deleted file mode 100644 index acdf7ae..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/serialflasher2/serialflasher2.ino.arduino_nano_connect.uf2 and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/template_arduino_init_production.ots b/Documentation/Fabrication/rp2040_preparation/template_arduino_init_production.ots deleted file mode 100644 index 9d2b7ec..0000000 Binary files a/Documentation/Fabrication/rp2040_preparation/template_arduino_init_production.ots and /dev/null differ diff --git a/Documentation/Fabrication/rp2040_preparation/uf2conv.py b/Documentation/Fabrication/rp2040_preparation/uf2conv.py deleted file mode 100644 index 2905929..0000000 --- a/Documentation/Fabrication/rp2040_preparation/uf2conv.py +++ /dev/null @@ -1,401 +0,0 @@ -#!/usr/bin/env python3 - -# UF2 upload utility taken from https://github.com/microsoft/uf2/blob/master/utils/uf2conv.py - -# Microsoft UF2 -# The MIT License (MIT) -# Copyright (c) Microsoft Corporation -# All rights reserved. - -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: - -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. - -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -import sys -import struct -import subprocess -import re -import os -import os.path -import argparse -import time -import glob - -toolspath = os.path.dirname(os.path.realpath(__file__)).replace('\\', '/') # CWD in UNIX format -try: - sys.path.insert(0, toolspath + "/pyserial") # Add pyserial dir to search path - import serial # If this fails, we can't continue and will bomb below -except Exception: - sys.stderr.write("pyserial directory not found next to this upload.py tool.\n") - sys.exit(1) - -UF2_MAGIC_START0 = 0x0A324655 # "UF2\n" -UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected -UF2_MAGIC_END = 0x0AB16F30 # Ditto - -families = { - 'SAMD21': 0x68ed2b88, - 'SAML21': 0x1851780a, - 'SAMD51': 0x55114460, - 'NRF52': 0x1b57745f, - 'STM32F0': 0x647824b6, - 'STM32F1': 0x5ee21072, - 'STM32F2': 0x5d1a0a2e, - 'STM32F3': 0x6b846188, - 'STM32F4': 0x57755a57, - 'STM32F7': 0x53b80f00, - 'STM32G0': 0x300f5633, - 'STM32G4': 0x4c71240a, - 'STM32H7': 0x6db66082, - 'STM32L0': 0x202e3a91, - 'STM32L1': 0x1e1f432d, - 'STM32L4': 0x00ff6919, - 'STM32L5': 0x04240bdf, - 'STM32WB': 0x70d16653, - 'STM32WL': 0x21460ff0, - 'ATMEGA32': 0x16573617, - 'MIMXRT10XX': 0x4FB2D5BD, - 'LPC55': 0x2abc77ec, - 'GD32F350': 0x31D228C6, - 'ESP32S2': 0xbfdd4eee, - 'RP2040': 0xe48bff56 -} - -INFO_FILE = "/INFO_UF2.TXT" - -appstartaddr = 0x2000 -familyid = 0x0 - - -def is_uf2(buf): - w = struct.unpack(" 476: - assert False, "Invalid UF2 data size at " + ptr - newaddr = hd[3] - if curraddr == None: - appstartaddr = newaddr - curraddr = newaddr - padding = newaddr - curraddr - if padding < 0: - assert False, "Block out of order at " + ptr - if padding > 10*1024*1024: - assert False, "More than 10M of padding needed at " + ptr - if padding % 4 != 0: - assert False, "Non-word padding size at " + ptr - while padding > 0: - padding -= 4 - outp += b"\x00\x00\x00\x00" - outp.append(block[32 : 32 + datalen]) - curraddr = newaddr + datalen - return b"".join(outp) - -def convert_to_carray(file_content): - outp = "const unsigned long bindata_len = %d;\n" % len(file_content) - outp += "const unsigned char bindata[] __attribute__((aligned(16))) = {" - for i in range(len(file_content)): - if i % 16 == 0: - outp += "\n" - outp += "0x%02x, " % file_content[i] - outp += "\n};\n" - return bytes(outp, "utf-8") - -def convert_to_uf2(file_content): - global familyid - datapadding = b"" - while len(datapadding) < 512 - 256 - 32 - 4: - datapadding += b"\x00\x00\x00\x00" - numblocks = (len(file_content) + 255) // 256 - outp = [] - for blockno in range(numblocks): - ptr = 256 * blockno - chunk = file_content[ptr:ptr + 256] - flags = 0x0 - if familyid: - flags |= 0x2000 - hd = struct.pack(b"= 3 and words[1] == "2" and words[2] == "FAT": - drives.append(words[0]) - else: - rootpath = "/run/media" - if not os.path.isdir(rootpath): - rootpath = "/media" - if not os.path.isdir(rootpath): - rootpath = "/opt/media" - if sys.platform == "darwin": - rootpath = "/Volumes" - elif sys.platform == "linux": - tmp = rootpath + "/" + os.environ["USER"] - if os.path.isdir(tmp): - rootpath = tmp - for d in os.listdir(rootpath): - drives.append(os.path.join(rootpath, d)) - - if (len(drives) == 0) and (sys.platform == "linux"): - globexpr = "/dev/disk/by-id/usb-RPI_RP2*-part1" - rpidisk = glob.glob(globexpr) - if len(rpidisk) > 0: - try: - cmd = ["udisksctl", "mount", "--block-device", os.path.realpath(rpidisk[0])] - proc_out = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - if proc_out.returncode == 0: - stdoutput = proc_out.stdout.decode("UTF-8") - match = re.search(r'Mounted\s+.*\s+at\s+([^\.\r\n]*)', stdoutput) - if match: - drives = [match.group(1)] - except Exception as ex: - print("Exception executing udisksctl. Exception: {}".format(ex)) - # If it fails, no problem since it was a heroic attempt - - def has_info(d): - try: - return os.path.isfile(d + INFO_FILE) - except: - return False - - return list(filter(has_info, drives)) - - -def board_id(path): - with open(path + INFO_FILE, mode='r') as file: - file_content = file.read() - return re.search("Board-ID: ([^\r\n]*)", file_content).group(1) - - -def list_drives(): - for d in get_drives(): - print(d, board_id(d)) - - -def write_file(name, buf): - with open(name, "wb") as f: - f.write(buf) - print("Wrote %d bytes to %s" % (len(buf), name)) - - -def main(): - global appstartaddr, familyid - def error(msg): - print(msg) - sys.exit(1) - parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.') - parser.add_argument('input', metavar='INPUT', type=str, nargs='?', - help='input file (HEX, BIN or UF2)') - parser.add_argument('-b' , '--base', dest='base', type=str, - default="0x2000", - help='set base address of application for BIN format (default: 0x2000)') - parser.add_argument('-o' , '--output', metavar="FILE", dest='output', type=str, - help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible') - parser.add_argument('-d' , '--device', dest="device_path", - help='select a device path to flash') - parser.add_argument('-l' , '--list', action='store_true', - help='list connected devices') - parser.add_argument('-c' , '--convert', action='store_true', - help='do not flash, just convert') - parser.add_argument('-D' , '--deploy', action='store_true', - help='just flash, do not convert') - parser.add_argument('-f' , '--family', dest='family', type=str, - default="0x0", - help='specify familyID - number or name (default: 0x0)') - parser.add_argument('-C' , '--carray', action='store_true', - help='convert binary file to a C array, not UF2') - parser.add_argument('-s', '--serial', dest='serial', help='Serial port to reset before upload') - args = parser.parse_args() - appstartaddr = int(args.base, 0) - - if args.family.upper() in families: - familyid = families[args.family.upper()] - else: - try: - familyid = int(args.family, 0) - except ValueError: - error("Family ID needs to be a number or one of: " + ", ".join(families.keys())) - - if args.serial: - if str(args.serial).startswith("/dev/tty") or str(args.serial).startswith("COM") or str(args.serial).startswith("/dev/cu"): - try: - print("Resetting " + str(args.serial)) - try: - ser = serial.Serial(args.serial, 1200) - ser.dtr = False - except: - pass # Ignore error in the case it is already in upload mode - except: - pass - if args.list: - list_drives() - else: - if not args.input: - error("Need input file") - with open(args.input, mode='rb') as f: - inpbuf = f.read() - from_uf2 = is_uf2(inpbuf) - ext = "uf2" - if args.deploy: - outbuf = inpbuf - elif from_uf2: - outbuf = convert_from_uf2(inpbuf) - ext = "bin" - elif is_hex(inpbuf): - outbuf = convert_from_hex_to_uf2(inpbuf.decode("utf-8")) - elif args.carray: - outbuf = convert_to_carray(inpbuf) - ext = "h" - else: - outbuf = convert_to_uf2(inpbuf) - print("Converting to %s, output size: %d, start address: 0x%x" % - (ext, len(outbuf), appstartaddr)) - if args.convert or ext != "uf2": - drives = [] - if args.output == None: - args.output = "flash." + ext - else: - now = time.time() - drives = [] - while (time.time() - now < 10.0) and (len(drives) == 0): - time.sleep(0.5) # Avoid 100% CPU use while waiting for drive to appear - drives = get_drives() - - if args.output: - write_file(args.output, outbuf) - else: - if len(drives) == 0: - error("No drive to deploy.") - for d in drives: - print("Flashing %s (%s)" % (d, board_id(d))) - write_file(d + "/NEW.UF2", outbuf) - - -if __name__ == "__main__": - main()