[{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003eThis is an evolving collection of tips and tricks about working on the CircuitPython core and related libraries. Topics include code analysis and debugging, working with git and GitHub, maintaining documentation, and install/config for dev tools. Mostly these are notes to future-me, but perhaps they will also help other people who want to improve CircuitPython.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eControl Flow Graphs\u003c/h2\u003e\n\u003cp\u003eWhen you're getting started working on a new-to-you module of complex code, it can be pretty hard to build a picture in your head of how the code works just from reading the text. Fortunately, there are tools which can analyze source code and build actual pictures for you with directed graphs of which functions call which other functions.\u003c/p\u003e\n\u003cp\u003eBelow are some examples of how I've been generating graphs of control flow between the various functions in CircuitPython's usb module and TinyUSB library dependency. To make the graphs, I use Debian with the\u0026nbsp;\u003ccode\u003ecflow\u003c/code\u003e code analysis tool to generate a \u003ccode\u003egraphviz\u003c/code\u003e (.dot) graph file, then turn that into a PNG image to view with the \u003ccode\u003emirage\u003c/code\u003e image viewer. For \u003ccode\u003emirage\u003c/code\u003e to work, you need to run the last command in a terminal in X (vnc or physical display will work, but not ssh).\u003c/p\u003e\n\u003ch3\u003eshared-bindings/usb/*\u003c/h3\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003eThis example builds a directed graph of functions calls within the CircuitPython\u0026nbsp;\u003ccode\u003eshared-bindings/usb/*\u003c/code\u003e code. The \u003ccode\u003egrep -v ...\u003c/code\u003e stuff is removing some macros that would clutter up the graph without adding much benefit. The \u003ccode\u003esed '2i ...'\u003c/code\u003e stuff is inserting a line with additional graphviz attributes to improve the layout of the graph spec file created by \u003ccode\u003ecflow\u003c/code\u003e. The \u003ccode\u003esfdp\u003c/code\u003e command is part of graphviz, and it's designed to lay out complex graphs.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"cd ~/adafruit/circuitpython/shared-bindings/usb\ncflow -i _ --all --omit-arguments -f dot {.,core,util}/{*.c,*.h} \\\n    | sed '2i overlap=false; K=0.4; repulsiveforce=0.8; smoothing=\"power_dist\"' \\\n    | grep -v 'MP_' \u003e ~/cflow.dot\nsfdp -Tpng ~/cflow.dot \u003e ~/cflow-shared-bindings-usb.png \u0026\u0026 mirage ~/cflow-shared-bindings-usb.png","metadata":{"language":"terminal","linenums":false,"filename":""}},{"element_type":"button","content":"https://github.com/samblenny/usb-host-tests/releases/download/v0.2.2/cflow-shared-bindings-usb.png","metadata":{"button_type":"primary","icon":"","target":"_blank","zip_folder":"false"}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/945/original/usb-cflow-before.png?1755485240","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eshared-module/usb/*\u003c/h3\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"cd circuitpython/shared-module/usb\ncflow -i _ --all --omit-arguments -f dot {.,core}/{*.c,*.h} util/*.c \\\n  | sed '2i overlap=false; K=0.9; repulsiveforce=0.8; splines=true;' \\\n  | grep -v 'MP_' \u003e ~/cflow.dot\nsfdp -Tpng ~/cflow.dot \u003e ~/cflow-shared-module-usb.png \u0026\u0026 mirage ~/cflow-shared-module-usb.png","metadata":{"language":"terminal","linenums":false,"filename":""}},{"element_type":"button","content":"https://github.com/samblenny/usb-host-tests/releases/download/v0.2.2/cflow-shared-module-usb.png","metadata":{"button_type":"primary","icon":"","target":"_blank","zip_folder":"false"}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/947/original/cflow-shared-module-usb.png?1755496230","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003esupervisor/shared/usb.c\u003c/h3\u003e\n\u003cp\u003eFor this one, I'm using \u003ccode\u003e\u003cspan\u003e--preprocess='arm-none-eabi-gcc -E'\u003c/span\u003e\u003c/code\u003e and a bunch of \u003ccode\u003e-D ...\u003c/code\u003e defines and\u0026nbsp;\u003ccode\u003e-I ...\u003c/code\u003e include paths to run the preprocessor approximately like a \u003ccode\u003e\u003cspan class=\"s1\"\u003emake BOARD=adafruit_fruit_jam\u003c/span\u003e\u003c/code\u003e command.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"cd circuitpython/supervisor\ncflow \\\n  -D CIRCUITPY_USB_CDC \\\n  -D CIRCUITPY_USB_DEVICE \\\n  -D CIRCUITPY_USB_HOST \\\n  -D DISABLE_FILESYSTEM \\\n  -I . \\\n  -I lib/tinyusb/src \\\n  -I ports/raspberrypi/ \\\n  -I ports/raspberrypi/boards/adafruit_fruit_jam \\\n  -I ports/raspberrypi/build-adafruit_fruit_jam \\\n  -I ports/raspberrypi/sdk_config \\\n  -I ports/raspberrypi/sdk/src/common/pico_base_headers/include \\\n  -I ports/raspberrypi/sdk/src/common/pico_sync/include \\\n  -I ports/raspberrypi/sdk/src/common/pico_time/include \\\n  -I ports/raspberrypi/sdk/src/host/pico_stdio/include \\\n  -I ports/raspberrypi/sdk/src/rp2_common/cmsis/ \\\n  -I ports/raspberrypi/sdk/src/rp2_common/hardware_base/include \\\n  -I ports/raspberrypi/sdk/src/rp2_common/hardware_sync_spin_lock/include \\\n  -I ports/raspberrypi/sdk/src/rp2_common/hardware_sync/include \\\n  -I ports/raspberrypi/sdk/src/rp2_common/hardware_timer/include \\\n  -I ports/raspberrypi/sdk/src/rp2_common/pico_platform_compiler/include \\\n  -I ports/raspberrypi/sdk/src/rp2_common/pico_platform_panic/include \\\n  -I ports/raspberrypi/sdk/src/rp2_common/pico_platform_sections/include \\\n  -I ports/raspberrypi/sdk/src/rp2_common/pico_stdio_usb/include \\\n  -I ports/raspberrypi/sdk/src/rp2350/hardware_regs/include \\\n  -I ports/raspberrypi/sdk/src/rp2350/hardware_structs/include \\\n  -I ports/raspberrypi/sdk/src/rp2350/pico_platform/include \\\n  -i _ \\\n  --preprocess='arm-none-eabi-gcc -E' \\\n  --omit-arguments \\\n  -f dot supervisor/shared/usb/usb.c \\\n  | sed '2i overlap=false; K=0.4; repulsiveforce=0.8; smoothing=\"power_dist\"' \\\n  | grep -v 'MP_' \u003e ~/cflow.dot\nneato -Tpng ~/cflow.dot \u003e ~/cflow-supervisor-usb.png \u0026\u0026 mirage ~/cflow-supervisor-usb.png","metadata":{"language":"terminal","linenums":false,"filename":""}},{"element_type":"button","content":"https://github.com/samblenny/usb-host-tests/releases/download/v0.2.2/cflow-supervisor-usb.png","metadata":{"button_type":"primary","icon":"","target":"_blank","zip_folder":"false"}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/946/original/cflow-supervisor-usb.png?1755492871","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eDebugging\u003c/h2\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003ePrintf Debugging\u003c/h3\u003e\n\u003cp\u003eIf you want to do basic printf debugging within the CircuitPython core, you can put \u003ccode\u003emp_printf()\u003c/code\u003e lines pretty much wherever you want (but be careful about interrupt handlers):\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"mp_printf(\u0026mp_plat_print, \"this is a format string. the number is: %x\\n\", 0x4F);","metadata":{"language":"auto","linenums":false,"filename":""}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003eCAUTION: There are a variety of reasons why your \u003ccode\u003emp_printf()\u003c/code\u003e lines might not get flushed to the serial port immediately. So, if you want feedback with very low latency, this might be an unsuitable choice.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eLED Debugging\u003c/h3\u003e\n\u003cp\u003eThis code snippet (git diff below) modifies the CircuitPython core USB implementation to turn on the Fruit Jam's red LED when a USB device is plugged in and off when it's unplugged. The LED is active low and shares pin 29 with the IR decoder, so LED drive is open drain.\u003c/p\u003e\n\u003cp\u003eYou could adapt this for any situation where you want a 1-bit debugging indicator while working on the CircuitPython core. To get multiple bits, or higher frequency, you'd probably want to use a logic analyzer on the GPIO header pins and modify the debug macros to use push-pull output instead of open drain.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c\nindex c9df0cf738..f650ed318a 100644\n--- a/shared-module/usb/core/Device.c\n+++ b/shared-module/usb/core/Device.c\n@@ -18,16 +18,35 @@\n #include \"supervisor/shared/tick.h\"\n #include \"supervisor/usb.h\"\n \n+// === DON'T MERGE THIS ===\n+#include \"hardware/gpio.h\"\n+#define FRUIT_JAM_LED_PIN (29)\n+#define DEBUG_GPIO_OUT_LOW(pin) { \\\n+    gpio_put(pin, 0); \\\n+    gpio_set_dir(pin, GPIO_OUT); \\\n+    gpio_set_function(pin, GPIO_FUNC_SIO); \\\n+}\n+#define DEBUG_GPIO_HIGHZ(pin) { \\\n+    gpio_set_function(pin, GPIO_FUNC_NULL); \\\n+}\n+// =========================\n+\n // Track what device numbers are mounted. We can't use tuh_ready() because it is\n // true before enumeration completes and TinyUSB drivers are started.\n static size_t _mounted_devices = 0;\n \n void tuh_mount_cb(uint8_t dev_addr) {\n     _mounted_devices |= 1 \u003c\u003c dev_addr;\n+    // === DON'T MERGE THIS ===\n+    DEBUG_GPIO_OUT_LOW(FRUIT_JAM_LED_PIN);\n+    //mp_printf(\u0026mp_plat_print, \"m%x\\n\", dev_addr);\n }\n \n void tuh_umount_cb(uint8_t dev_addr) {\n     _mounted_devices \u0026= ~(1 \u003c\u003c dev_addr);\n+    // === DON'T MERGE THIS ===\n+    DEBUG_GPIO_HIGHZ(FRUIT_JAM_LED_PIN);\n+    //mp_printf(\u0026mp_plat_print, \"u%x\\n\", dev_addr);\n }\n \n static xfer_result_t _xfer_result;","metadata":{"language":"terminal","linenums":false,"filename":""}},{"element_type":"text","content":"\n  \n  \n  \n        \u003ch3\u003eTinyUSB Debug Log\u003c/h3\u003e\n\u003cp\u003eTinyUSB has built in debug logging that can be routed to a UART with a serial adapter or RTT with a debug probe. To enable UART logging for Fruit Jam:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eIn \u003ccode\u003eports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.h\u003c/code\u003e, uncomment the lines for the UART pins and TinyUSB debug:\n\u003cpre\u003e// #define CIRCUITPY_CONSOLE_UART_TX (\u0026amp;pin_GPIO44)\u003cbr\u003e// #define CIRCUITPY_CONSOLE_UART_RX (\u0026amp;pin_GPIO45)\u003cbr\u003e// #define CIRCUITPY_DEBUG_TINYUSB 0\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003eIncrease the TinyUSB log level from 0 to 2 (2 means show USB host log messages):\u003cbr\u003e\n\u003cpre\u003e#define CIRCUITPY_CONSOLE_UART_TX (\u0026amp;pin_GPIO44)\u003cbr\u003e#define CIRCUITPY_CONSOLE_UART_RX (\u0026amp;pin_GPIO45)\u003cbr\u003e#define CIRCUITPY_DEBUG_TINYUSB 2\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003eBuild and flash a firmware image\u003cbr\u003e\n\u003cpre class=\"p1\"\u003e\u003cspan class=\"s1\"\u003e(.venv) \u003c/span\u003e\u003cspan class=\"s2\"\u003e$ \u003c/span\u003e\u003cspan class=\"s1\"\u003ecd ports/raspberrypi/\u003c/span\u003e\u003cbr\u003e\u003cspan class=\"s1\"\u003e(.venv) \u003c/span\u003e\u003cspan class=\"s2\"\u003e$ \u003c/span\u003e\u003cspan class=\"s1\"\u003emake -j BOARD=adafruit_fruit_jam\u003c/span\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003cli\u003eConnect a\u0026nbsp;\u003ca href=\"https://www.raspberrypi.com/documentation/microcontrollers/debug-probe.html#the-debug-probe\" target=\"_blank\"\u003eRaspberry Pi Debug Probe\u003c/a\u003e to the Fruit Jam Debug port and GPIO header:\u003cbr\u003e\u003cstrong\u003eBlack\u003c/strong\u003e wire (probe ground) to Fruit Jam \u003cstrong\u003eGND\u003c/strong\u003e\u003cbr\u003e\u003cstrong\u003eYellow\u003c/strong\u003e wire (probe RX) to Fruit Jam console TX on \u003cstrong\u003eA4\u003c/strong\u003e (GPIO44)\u003cbr\u003e\u003cstrong\u003eOrange\u003c/strong\u003e wire (probe TX) to Fruit Jam console RX on \u003cstrong\u003eA5\u003c/strong\u003e (GPIO45)\u003c/li\u003e\n\u003cli\u003eStart a serial monitor with a large scrollback buffer at 115200 baud to listen to the Raspberry Pi Debug Probe UART (example for Debian):\u003cbr\u003e\n\u003cpre class=\"p1\"\u003e\u003cspan class=\"s1\"\u003e$ screen -h 9999 -fn /dev/serial/by-id/usb-Raspberry_Pi_Debug_Probe* 115200\u003c/span\u003e\u003c/pre\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n      \n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/949/original/Fruit-Jam-Debug-Wiring.jpeg?1756691665","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eGit \u0026amp; GitHub\u003c/h2\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eContributing Changes\u003c/h3\u003e\n\u003cp\u003eContributing fixes or new features to CircuitPython core and CircuitPython libraries requires some effort to follow project conventions and to avoid breaking stuff that was previously working. These guides are a useful starting point:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://learn.adafruit.com/contribute-to-circuitpython-with-git-and-github\"\u003ehttps://learn.adafruit.com/contribute-to-circuitpython-with-git-and-github\u003c/a\u003e (general info)\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library\"\u003ehttps://learn.adafruit.com/creating-and-sharing-a-circuitpython-library\u003c/a\u003e (pre-commit, code linters, etc)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eSome things to keep in mind:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eCircuitPython uses a lot of submodule dependencies for libraries and frozen modules. The circuitpython repo has Makefile rules to manage submodules, so you often need to use\u0026nbsp;\u003ccode\u003emake\u003c/code\u003e to manage submodules instead of the standard \u003ccode\u003egit submodule ...\u003c/code\u003e command line invocations. For example, supposing you want to build for an RP2350 board, when you initially clone your fork of circuitpython, you might do \u003ccode\u003ecd ports/raspberrypi\u003c/code\u003e followed by \u003ccode\u003emake fetch-port-submodules\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eWhen you sync your local circuitpython fork to get upstream changes from adafruit/circuitpython, you may need to update submodules for libraries or frozen modules.\u003c/li\u003e\n\u003cli\u003eWhen the upstream repo for a frozen module gets updated with a new tag, there may be a time window when the circuitpython submodule commit reference for that module is set to the previous tag. In that case, using \u003ccode\u003e\u003cspan\u003emake update-frozen-libraries\u003c/span\u003e\u003c/code\u003e might give you the latest upstream tag instead of the correct one for the current submodule commit.\u003c/li\u003e\n\u003cli\u003eIf you increase the size of code for built-in modules or frozen modules that get included in Atmel SAMD21 builds, you may cause CI build check failures due to the code not fitting in flash for certain translations of some boards. The typical fix for this is to edit board config files and turn off built-in features.\u003c/li\u003e\n\u003cli\u003eWhen you make a pull request (PR) to adafruit/circuitpython, your code will go through many CI checks that can last for up to a half hour or longer. To avoid delays due to simple coding errors, it helps to enable the \"pre-commit\" tools to run some of the checks on your local computer where they will finish much faster.\u0026nbsp;\u003c/li\u003e\n\u003c/ol\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eKeep Your Fork in Sync\u003c/h3\u003e\n\u003cp\u003eOn GitHub, you can just press a button to sync your fork of CircuitPython to the upstream Adafruit repo to follow new commits and releases. In your local repo, you can get the changes with \u003ccode\u003egit pull\u003c/code\u003e. But... that wont fix your submodules!\u003c/p\u003e\n\u003cp\u003eBe sure to change directories into the port you're working with, then use \u003ccode\u003emake\u003c/code\u003e to fetch the port submodules. For example:\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eWriting Docs\u003c/h2\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n        \u003ch3\u003eEdit Docs for CircuitPython Core\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003eDocumentation comments are in \u003ccode\u003eshared-bindings/\u003c/code\u003e. The \u003ccode\u003e//|\u003c/code\u003e prefix is a MicroPython/CircuitPython preprocessor thing. After the prefix, documentation comments use \u003ca href=\"https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html\" target=\"_blank\"\u003eSphinx reStructuredText\u003c/a\u003e syntax.\u003c/li\u003e\n\u003cli\u003eTo build the docs, do \u003ccode\u003emake html\u003c/code\u003e from the top level of the circuitpython repo\u003c/li\u003e\n\u003cli\u003eTo serve local docs, do \u003ccode\u003ecd _build/html/; python3 -m http.server\u003c/code\u003e\n\u003c/li\u003e\n\u003cli\u003eView the docs on port 8000 of your dev computer's IP address\u003c/li\u003e\n\u003c/ol\u003e\n      ","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eEdit Docs for Libraries\u003c/h3\u003e\n\u003cp\u003eCircuitPython libraries use inline documentation with reStructuredText formatted comments. To build local html previews of your documentation edits:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eMake sure you have a python virtual environment (venv) set up and active.\u003c/li\u003e\n\u003cli\u003eMake sure your venv has \u003ccode\u003eSphinx\u003c/code\u003e and \u003ccode\u003esphinx-rtd-theme\u003c/code\u003e installed (that will normally happen if you follow the guides for setting up your dev environment to work on CircuitPython core or library repos)\u003c/li\u003e\n\u003cli\u003eIn a library repo, say perhaps Adafruit_CircuitPython_TLV320, run these shell commands to build the html documentation files and start a local webserver:\u003c/li\u003e\n\u003c/ol\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"cd Adafruit_CircuitPython_TLV320/docs\nsphinx-build -E -W -b html . _build/html\ncd _build/html\n# type Ctrl-C to stop this web server when you're done\npython3 -m http.server --bind 127.0.0.1","metadata":{"language":"terminal","linenums":false,"filename":""}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cul\u003e\n\u003cli\u003eOnce the web server is running, you can view the html documentation by going to \u003ca href=\"http://localhost:8080\"\u003ehttp://localhost:8080\u003c/a\u003e in your web browser.\u003c/li\u003e\n\u003cli\u003eTo stop the web server, type Ctrl-C in the same terminal window where you started it.\u003c/li\u003e\n\u003c/ul\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"cd circuitpython/ports/raspberrypi\nmake fetch-port-submodules","metadata":{"language":"terminal","linenums":false,"filename":""}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eCynthion USB Analyzer\u003c/h2\u003e\n\u003cp\u003eThe \u003ca href=\"https://cynthion.readthedocs.io/en/latest/getting_started.html\" target=\"_blank\"\u003eCynthion Getting Started\u003c/a\u003e documentation is mostly pretty straightforward and easy to follow. But, there are some things that require extra steps...\u003c/p\u003e\n\u003ch3\u003eFix udev rule for Debian\u003c/h3\u003e\n\u003cp\u003eOn Debian, if you follow the docs to install a \u003ccode\u003e54-cynthion.rules\u003c/code\u003e file in \u003ccode\u003e/etc/udev/rules.d\u003c/code\u003e, those udev rules use \u003ccode\u003eTAG+=\"uaccess\"\u003c/code\u003e to grant access to the USB device for your Cynthion. The problem with using a \u003ccode\u003euaccess\u003c/code\u003e tag is that it only works for users logged into the console (physically attached monitor/keyboard/mouse). So, if you try to remote control your Cynthion over SSH or VNC, you'll get mysterious permission errors.\u003c/p\u003e\n\u003cp\u003eThe fix is easy. Just edit the rules file, changing \u003ccode\u003eTAG+=\"uaccess\"\u003c/code\u003e to \u003ccode\u003eGROUP=\"plugdev\"\u003c/code\u003e. If for some reason your user account on the Debian box does not already belong to the \u003ccode\u003eplugdev\u003c/code\u003e group, then add it to\u0026nbsp;\u003ccode\u003eplugdev\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThe above udev stuff is current at the time I write this (August 31, 2025). Things may change as there are open GitHub issues about udev related permissions issues in the\u0026nbsp;\u003ca href=\"https://github.com/greatscottgadgets/cynthion\" target=\"_blank\"\u003egreatscottgadgets/cynthion\u003c/a\u003e repo. Related links:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/greatscottgadgets/cynthion/issues/210\" target=\"_blank\"\u003eImprove experience for permissions setup without uaccess #210\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/greatscottgadgets/cynthion/issues/209\" target=\"_blank\"\u003eImprove experience/error message when having permissions issues #209\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/greatscottgadgets/cynthion/issues/195\" target=\"_blank\"\u003e[SOLVED] ValueError: The device has no langid (permission issue, no string descriptors supported or device error) #195\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}}]