{"id":26038857,"url":"https://github.com/secfurry/sideshow","last_synced_at":"2025-07-31T23:07:55.264Z","repository":{"id":280708202,"uuid":"942850165","full_name":"secfurry/sideshow","owner":"secfurry","description":"eInk Badge with the Inky Frame using Rust","archived":false,"fork":false,"pushed_at":"2025-03-04T21:50:51.000Z","size":1,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-04T22:28:34.543Z","etag":null,"topics":["eink","embedded","embedded-rust","inkyframe","pico","pinorami","rp2040","rp2040w","rust","sdcard"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/secfurry.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-03-04T19:22:09.000Z","updated_at":"2025-03-04T21:52:50.000Z","dependencies_parsed_at":"2025-03-04T22:28:39.141Z","dependency_job_id":"8c3f346c-3bb0-49ba-ae2d-1d2b45d71f5a","html_url":"https://github.com/secfurry/sideshow","commit_stats":null,"previous_names":["secfurry/sideshow"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secfurry%2Fsideshow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secfurry%2Fsideshow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secfurry%2Fsideshow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/secfurry%2Fsideshow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/secfurry","download_url":"https://codeload.github.com/secfurry/sideshow/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242378228,"owners_count":20118175,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["eink","embedded","embedded-rust","inkyframe","pico","pinorami","rp2040","rp2040w","rust","sdcard"],"created_at":"2025-03-07T10:37:39.206Z","updated_at":"2025-07-31T23:07:55.236Z","avatar_url":"https://github.com/secfurry.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SideShow\n\neInk display Badge based on the Pinorami InkyFrame.\n\n## How does it work?\n\nSideShow uses the built-in SD Card reader combined with the PCF RTC to run as\na super low power badge by displaying images on the eInk display.\n\n## States\n\n### Automatic\n\nWith the default configration, the device will \"wake-up\" every 15 minutes automatically\nand update the display. When not processing anything, the device will attempt to\nturn itself off to save power when using the JST battery connector on the InkyFrame\nboard.\n\nThe display update process follows the following routes:\n\n- Increase the \"current display\" count (held in PCF memory) by `1`.\n  - If the \"current display\" count is `\u003e= 127`, reset it to `0`.\n- Open the `/backgrounds` directory _(changable by configuration)_ on the SD Card.\n  - Get the current file count in this directory\n  - Choose a random image from this directory and write it's parsed contents to\n    the eInk display buffer.\n- Open the `/badges` directory _(changable by configuration)_ on the SD Card,\n  - Iterate through the files in the directory until one of the following conditions are met.\n    - File count equals the \"current display\" count.\n    - File is the last file in the directory.\n  - If the file was the last entry, the \"current display\" count will be set to `127`.\n  - Write the selected image's parsed contents to the eInk display buffer.\n- Update the eInk display.\n\nThe dual background and \"badge\" images work on the concept that TGA images allow\nfor transparency, which is supported by our TGA parser. Transparent pixels will\n__not__ be drawn and can allow for the previously drawn pixels to show through.\n\nThis selection process allows for randomized backgrounds for every \"badge\" displayed.\n\nNOTE: SideShow will only read TGA-type image files. You can use `imagmagick` to\nconvert them easily using `convert src.jpg dst.tga`\n\nIt's also recommended that the images are the size of the eInk display (640x400 for\nInkyFrame4, 600x448 for InkyFrame5) as SideShow will draw them at (0, 0) directly.\n\n### Buttons\n\nThe button configuration can be changed but supports the following button actions:\n\n- __Lock__: Prevent the current \"Badge\" from being changed automatically. This will\n  change the background but not the \"Badge\". When this action is used, the top\n  LEDs (Action and Network) will display the new Lock state. It's a toggle button\n  to switch the Lock state.\n  - Action __On__, Network __Off__: Lock is Disabled.\n  - Action __Off__, Network __On__: Lock is Enabled.\n- __Random__: Select a random \"Badge\" and background and display it. This will\n  override the Lock value and disable it. The \"current display\" count will be set\n  to the current \"Badge\" position.\n- __Previous__: Select the previous \"Badge\" and display it. The \"current display\"\n  count will be set to the current \"Badge\" position (`-1`). This button __does not__\n  override the Lock, if set. If the current \"Badge\" is the first entry (`0`), the\n  \"current display\" value will be set to `127`, which wraps around the selection.\n- __Next__: Select the next \"Badge\" and display it. The \"current display\"\n  count will be set to the current \"Badge\" position (`+1`). This button __does not__\n  override the Lock, if set. If the current \"Badge\" is the last entry, the\n  \"current display\" value will be set to `0`, which wraps around the selection.\n- __Custom__: TODO.\n\nThe default button configuration is:\n\n- __A__: Nothing\n- __B__: Lock\n- __C__: Random\n- __D__: Previous\n- __E__: Next\n\nWhen a button is pressed, it's LED will light up indicating the pressed selection.\n\n### Errors\n\nIf SideShow encounters an error, it will switch to an error state and will require it\nto be power-cycled to clear it.\n\nError states are indicated by the Activity and Network LEDs flashing back-and-forth\nevery second. Which button LEDs are lit up indicate the type of error that occurred.\n\nThe work by [@ticky](https://github.com/ticky) has allowed for expansion of the\nerror types for better debugging. The resulting error code will be in 5-bit binary.\nThe table mapping of the LEDs to the errors is listed below.\n\n#### Error Descriptions\n\n- __Byte__: Operations on the PCF stored byte failed.\n- __Wake__: Operations on the PCF wake alarm and interrupts failed.\n- __InvalidPins__: Setup for the eInk display was not correct. Usually this error\n     is due to a configuration/code error.\n- __InvalidRoot__: Operations on the SD Card (non-image related) failed. This is\n     usually due to an error with the SD Card or it's formatting. Sometimes it\n     will be a fluke issue, but may require re-formatting the SD Card if the error\n     occurs multiple times in a row.\n- __Badge/DirOpen__: Generic error occurred when trying to open the Badge directory.\n- __Badge/DirNotFound__: The Badge directory could not be found.\n- __Badge/DirNotADir__: The Badge directory was found, but it's type was not a directory.\n- __Badge/DirList__: Reading the Badge directory listing failed.\n- __Badge/DirListReset__: Resetting and re-reading the Badge directory listing failed.\n- __Badge/DirIter__: Walking through the Badge directory listing failed.\n- __Badge/FileOpen__: Opening the selected Badge file failed. (Before Parsing).\n- __Badge/ImageIo__: Reading the selected Badge file failed. (During Parsing, but\n     not format related).\n- __Badge/ImageType__: The selected Badge image type was not a valid TGA file.\n- __Badge/ImageRead__: Generic parsing/reading error occurred when reading the selected\n     Badge file.\n- __Badge/ImageParse__: The selected Badge image could not be parsed due to improperly\n     returned TGA data. (Corrupted or badly formatted file?).\n- __Background/DirOpen__: Generic error occurred when trying to open the Background\n     directory.\n- __Background/DirNotFound__: The Background directory could not be found.\n- __Background/DirNotADir__: The Background directory was found, but it's type was\n     not a directory.\n- __Background/DirList__: Reading the Background directory listing failed.\n- __Background/DirListReset__: Resetting and re-reading the Background directory\n     listing failed.\n- __Background/DirIter__: Walking through the Background directory listing failed.\n- __Background/FileOpen__: Opening the selected Background file failed. (Before Parsing).\n- __Background/ImageIo__: Reading the selected Background file failed. (During Parsing,\n     but not format related).\n- __Background/ImageType__: The selected Background image type was not a valid TGA file.\n- __Background/ImageRead__: Generic parsing/reading error occurred when reading the selected\n     Background file.\n- __Background/ImageParse__: The selected Background image could not be parsed due to\n     improperly returned TGA data. (Corrupted or badly formatted file?).\n\n#### Error Mapping Table\n\nTo display the error codes, the button LEDs will light up to display a 5-bit binary\nnumber. _(A = 16, B = 8, C = 4, D = 2, E = 1)_.\n\n| Error                   | Number Value | LED Indicator |\n| ----------------------- | ------------ | ------------- |\n| Byte                    |            0 |     [None]    |\n| Wake                    |            1 |           E   |\n| InvalidPins             |            2 |         D     |\n| InvalidRoot             |            3 |         D E   |\n| Badge/DirOpen           |            4 |       C       |\n| Badge/DirNotFound       |            5 |       C   E   |\n| Badge/DirNotADir        |            6 |       C D     |\n| Badge/DirList           |            7 |       C D E   |\n| Badge/DirListReset      |            8 |     B         |\n| Badge/DirIter           |            9 |     B     E   |\n| Badge/FileOpen          |           10 |     B   D     |\n| Badge/ImageIo           |           11 |     B   D E   |\n| Badge/ImageType         |           12 |     B C       |\n| Badge/ImageRead         |           13 |     B C   E   |\n| Badge/ImageParse        |           14 |     B C D     |\n| Background/DirOpen      |           16 |   A           |\n| Background/DirNotFound  |           17 |   A       E   |\n| Background/DirNotADir   |           18 |   A     D     |\n| Background/DirList      |           19 |   A     D E   |\n| Background/DirListReset |           20 |   A   C       |\n| Background/DirIter      |           21 |   A   C   E   |\n| Background/FileOpen     |           22 |   A   C D     |\n| Background/ImageIo      |           23 |   A   C D E   |\n| Background/ImageType    |           24 |   A B         |\n| Background/ImageRead    |           25 |   A B     E   |\n| Background/ImageParse   |           26 |   A B   D     |\n\n_Due to numbering, most Background related errors will have the \"A\" LED enabled._\n\n#### Critical Errors\n\nThere are two odd \"critical\" type errors that will only happen during initialization.\nThe code for them is [here](src/sideshow.rs#L490). __This error type does not use__\n__the Activity or Network LEDs.__\n\nThe two conditions are:\n\n- __A | B__: Stack overflow in critical section. This error is _super rare_. If\n   you receive this error, attempt to run Sideshow with the `static` or `static_large`\n   feature flags. If that still fails, please leave an [Issue](https://github.com/secfurry/inky-frame/issues/new?title=Stack+Overflow+Critical).\n- __D | E__: SDCard initilization error. This error occurs when the SDCard does\n   not respond properly to the `INIT (CMD0)` command and may indicate a bad SDCard\n   or one that does not support SPI. If you receive this error, try another SDCard\n   if avaliable. If you can't or the other one fails with the same error, please\n   leave an [Issue](https://github.com/secfurry/inky-frame/issues/new?title=SDCard+Init+Critical)\n   with information on the SDCard and it's manufactor, size and class markings\n   (eg: C with the number, U with the number, etc.). _This should be fixed now,_\n   _see the Bugs section below!_\n\n## Configuration\n\nThe configuration is fairly simple. Any changes made are in `sideshow.rs` in the\nfollowing code block:\n\n```rust\n// =================== [   Configuration   ] ===================\n/// Time in milliseconds) to wait for a button check. Only\n/// takes affect when NOT on battery power.\nconst SLEEP_STEP: u32 = 50u32;\n/// Time (in seconds) to wake up and change the current\n/// badge and/or background.\nconst SLEEP_TIME: u32 = 15u32 * 60u32;\n\n/// Directory name in the SD Card root to get the badge\n/// images from.\nconst DIR_BADGES: \u0026str = \"/badges\";\n/// Directory name in the SD Card root to get the background\n/// images from.\nconst DIR_BACKGROUNDS: \u0026str = \"/backgrounds\";\n\n/// Action to return when the 'A' button is pressed.\nconst BUTTON_A: Action = Action::None;\n/// Action to return when the 'B' button is pressed.\nconst BUTTON_B: Action = Action::Lock;\n/// Action to return when the 'C' button is pressed.\nconst BUTTON_C: Action = Action::Rand;\n/// Action to return when the 'D' button is pressed.\nconst BUTTON_D: Action = Action::Prev;\n/// Action to return when the 'E' button is pressed.\nconst BUTTON_E: Action = Action::Next;\n// =================== [ Configuration End ] ===================\n```\n\nEach name is self-explanatory and any changes require a re-compilation and upload to\nthe device to take affect.\n\n## Setup\n\nTo start using SideShow, you'll need to compile this repository first.\n\nThe cargo configuration should contain all the values needed to compile in the\n`thumbv6m-none-eabi` target format (for the RP2040 processor). You'll need to make\nsure you have the `flip-link` linker installed before compiling. To do this, use\nthe command `cargo install flip-link` to install it.\n\nIf a Pico debug probe is avaliable (or you can setup one,\n[see here](https://mcuoneclipse.com/2022/09/17/picoprobe-using-the-raspberry-pi-pico-as-debug-probe/)),\ninstalling `probe-rs` using `cargo install probe-rs-tools` will allow for direct\nflashing of the firmware when the probe is connected to the SideShow device when\n`cargo run` is called.\n\nIf you don't have a debug probe avaliable, you can convert the compiled ELF into\na U2F file using `elf2uf2-rs` (`cargo install elf2uf2-rs`) and can be loaded using\nthe Bootloader mode of the Pico (hold down the \"Boot\" button when plugging the\ndevice in to expose the flash storage) by copying the generated file over to flash.\n_Make sure to comment out the first two lines of `.cargo/config.toml` to avoid any_\n_compilation errors._\n\n### Case\n\nIncluded in the `case` directory are STL files that can be used to 3d-print a\nnice case to contain the device with:\n\n- USB-C connector port\n- Simple switch (for on/off)\n- LiPo Battery Pack\n- AdaFruit PowerBoost 1000\n\n## InkyFrame Devices\n\nThe current code configuration is support for the InkyFrame 4. With a couple of\ncode and configuration changes, it can work on different devices or larger screen\nsizes.\n\nIf using an InkyFrame5, build with the \"inky5\" feature. This will also use the\n\"static_large\" feature for the larger screen.\n\nSee the [InkyFrame](https://github.com/secfurry/inky-frame) repository for compatibility.\n\n## Stupid Notes\n\nIf you have the device on battery (via JST) and it wakes up way too early or\ninstantly. Unplug it from the battery and let it sit for a minute, sometimes\nthe PCF gets wonky and needs a lil reset.\n\n## Bugs\n\n- Files named from MacOS are not correctly found by their name, even when correct.\n  _Thanks to [@ticky](https://github.com/ticky) for the finding_\n\n### SDCard Bugs\n\n__This should be fixed with the inky-frame v0.3.0 update!__\n__Turns out some cheap vendors don't follow standard protocols, weeeeee!__\n\n_Copied from the [inky-frame](https://github.com/secfurry/inky-frame) README._\n\nSome SDCards don't support SPI mode or don't initialize properly. I'm not\n100% sure if it's a protocol issue or something else. These cards return\n`READY (0)` when asked to go into `IDLE (1)` mode. They'll work fine on PCs.\n\nThese SDCards work fine on some of my Ender 3 3D Printers, _which use Arduino's_\n_SDCard library_ and have the same initializing sequence. But other devices, like\nthe Flipper Zero, don't work with them either.\n\nYou'll know if it fails as it won't get past the initialization phase and basically\n\"freezes\" and does not respond with the \"D\" and \"E\" LEDs on. __This error type__\n__does not use the Activity or Network LEDs.__\n\nIf you have a SDCard that has issues also, please leave me an [Issue](https://github.com/secfurry/inky-frame/issues/new?title=SDCard+Init+Critical)\nwith information on the SDCard and it's manufactor, size and class markings\n(eg: C with the number, U with the number, etc.) so I can test further.\n\nSDCards verified to __not__ work:\n\n- [These SDHC Class 10/U1 Cards](https://www.amazon.com/dp/B07XJVFVSJ)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecfurry%2Fsideshow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsecfurry%2Fsideshow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsecfurry%2Fsideshow/lists"}