├── LICENSE ├── PiBeam_firmware.uf2 ├── README.md ├── documents └── readme ├── examples ├── HID_example_circuitpython │ ├── Demo_CameraOn_code.py │ ├── Display_Images_FromPiBeam │ │ ├── README.md │ │ ├── image_display.py │ │ └── images │ │ │ ├── img1.bmp │ │ │ ├── img2.bmp │ │ │ ├── img3.bmp │ │ │ ├── img4.bmp │ │ │ ├── img5.bmp │ │ │ └── img6.bmp │ ├── Display_Images_from_SDCard │ │ ├── README.md │ │ ├── display_sdcard_images.py │ │ └── images │ │ │ ├── img1.bmp │ │ │ ├── img2.bmp │ │ │ ├── img3.bmp │ │ │ ├── img4.bmp │ │ │ ├── img5.bmp │ │ │ └── img6.bmp │ ├── PiBeam_HID_firmware.uf2 │ ├── lib │ │ ├── PiBeam.py │ │ ├── adafruit_display_text │ │ │ ├── __init__.mpy │ │ │ ├── bitmap_label.mpy │ │ │ ├── label.mpy │ │ │ └── scrolling_label.mpy │ │ ├── adafruit_hid │ │ │ ├── __init__.mpy │ │ │ ├── consumer_control.mpy │ │ │ ├── consumer_control_code.mpy │ │ │ ├── keyboard.mpy │ │ │ ├── keyboard_layout_base.mpy │ │ │ ├── keyboard_layout_us.mpy │ │ │ ├── keycode.mpy │ │ │ └── mouse.mpy │ │ ├── adafruit_imageload │ │ │ ├── __init__.mpy │ │ │ ├── bmp │ │ │ │ ├── __init__.mpy │ │ │ │ ├── indexed.mpy │ │ │ │ └── negative_height_check.mpy │ │ │ ├── displayio_types.mpy │ │ │ ├── gif.mpy │ │ │ ├── png.mpy │ │ │ ├── pnm │ │ │ │ ├── __init__.mpy │ │ │ │ ├── pbm_ascii.mpy │ │ │ │ ├── pbm_binary.mpy │ │ │ │ ├── pgm │ │ │ │ │ ├── __init__.mpy │ │ │ │ │ ├── ascii.mpy │ │ │ │ │ └── binary.mpy │ │ │ │ ├── ppm_ascii.mpy │ │ │ │ └── ppm_binary.mpy │ │ │ └── tilegrid_inflator.mpy │ │ ├── adafruit_irremote.py │ │ ├── adafruit_sdcard.py │ │ ├── adafruit_st7789.mpy │ │ ├── adafruit_st7789.py │ │ └── keyboard_layout_win_uk.py │ ├── password_feeder_gmail.py │ └── readme.md ├── PiBeam.py ├── Receiver_LCD_sdcard_demo.py ├── button_demo.py ├── onboardLED_demo.py ├── readme ├── receiver_demo.py ├── sdcard_demo.py ├── transmitter_LCD_sdcard_demo.py └── transmitter_demo.py └── images ├── LED_blink.png ├── pibeampinout.jpg └── readme /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 SB Components 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PiBeam_firmware.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/PiBeam_firmware.uf2 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PiBeam_Software 2 | 3 | 4 | 5 | Introducing PiBeam, the ultimate USB IR Transceiver that revolutionizes the way you control your devices. PiBeam offers a versatile and cost-effective way to enable wireless communication and control in a variety of embedded electronics applications. 6 | 7 | PiBeam is a DIY USB transceiver device that can be programmed to control and manage your computer, gaming console, or multimedia system, PiBeam provides a user-friendly interface with TFT 1.14” Display that ensures a smooth and intuitive experience. 8 | 9 | An in-depth setup and working guide for PiBeam is available on this github. 10 | 11 | ### Features: 12 | - The device is powered by Raspberry Pi RP2040, which ensures efficient and fast processing. 13 | - The device features a TFT 1.14” display, providing a better user experience. 14 | - IR transceiver device, thereby it can send and receive IR signal data to establish two way communication. 15 | - Onboard Micro-SD card support for Data logging and storage 16 | - Boot button for programming and 3 user programmable buttons to add additional control features for project 17 | - One programmable LED and power status LED 18 | - Compatible with Windows, Mac, and Linux, ensuring broad compatibility across different systems. 19 | - The device is a plug-and-play device and does not require any drivers, making it easy to use. 20 | - Supports all common Remote protocols like NEC protocol, Sony SIRC 12 bit, 15bit, 20bit, Philips RC-5 & RC-6 mode 0, making it versatile for various applications. 21 | - Easy drag-and-drop programming using mass storage over USB. 22 | - Open-source hardware with Python support and compatible to use as a HID device 23 | 24 | ### Specifications: 25 | - RPi RP2040 microcontroller which is dual-core Arm Cortex-M0+ processor 26 | - 2MB of onboard flash storage, 264kB of RAM 27 | - Board supply voltage is 5V 28 | - Display 1.14” with resolution 240×135 pixels 29 | - 65K RGB Colors Display 30 | - Display interface using SPI 31 | - ST7789 Display Driver 32 | - Type A USB interface 33 | - Operating Temperature: -20°C to 70°C 34 | 35 | 36 | ## Getting Started with PiBeam 37 | ### Hardware Overview 38 | #### Pinout 39 | 40 | 41 | 42 | - (1) Type A 43 | - (2) Programmable LED 44 | - (3) 1.14” Display 45 | - (4) IR Transmitter 46 | - (5) Power LED 47 | - (6) IR Receiver 48 | - (7) RP2040 49 | - (8), (10) & (11) Programmable Buttons 50 | - (9) Boot Button 51 | 52 | ### Interfacing Details 53 | 54 | - IR Transmitter and Receiver info 55 | | Pico | Hardware Pin | Function | 56 | |---|---|---| 57 | |GP0 | TX | IR transmitter | 58 | |GP1 | RX | IR Receiver | 59 | 60 | - SD Card interfacing info 61 | | Pico | Hardware Pin | Function | 62 | |---|---|---| 63 | |GP18 | SCLK | Clock pin of SPI interface for microSD card | 64 | |GP19 | DIN | MOSI (Master OUT Slave IN) data pin of SPI interface for microSD card| 65 | |GP16 | DOUT | MISO (Master IN Slave OUT) data pin of SPI interface for microSD card| 66 | |GP17 | CS | Chip Select pin of SPI interface for microSD card| 67 | 68 | - Display interfacing info 69 | | Pico | Hardware Pin | Function | 70 | |---|---|---| 71 | |GP10 | SCLK | Clock pin of SPI interface for display | 72 | |GP11 | DIN | MOSI (Master OUT Slave IN) data pin of SPI interface| 73 | |GP8 | D/C | Data/command line of SPI interface for display | 74 | |GP12 | RESET | Display reset pin | 75 | |GP9 | CS | Chip Select pin of SPI interface for display| 76 | |GP13 | BL | Backlight pin for display | 77 | 78 | - Other peripherals 79 | | Pico | Hardware Pin | Function | 80 | |---|---|---| 81 | | GP25 | STAT | Status, programmable LED | 82 | | GP7 | BT1 | Programmable button | 83 | | GP28 | BT2 | Programmable button | 84 | | GP20 | BT3 | Programmable button | 85 | 86 | 87 | ### 1. Step to install boot Firmware 88 | - Every PiBeam board will be provided with boot firmware already installed, so you can skip this step and directly go to [step 2](https://github.com/sbcshop/PiBeam_Software#2-onboard-led-blink). 89 | - If in case you want to install firmware for your PiBeam, Push and hold the BOOT button and plug your PiBeam into the USB port of your computer. Release the BOOT button after your PiBeam is connected to USB port. 90 | - It will mount as a Mass Storage Device called RPI-RP2. 91 | - Drag and drop the MicroPython UF2 - [PiBeam_firmware](https://github.com/sbcshop/PiBeam_Software/blob/main/PiBeam_firmware.uf2) file provided in this github onto the RPI-RP2 volume. Your PiBeam will reboot. You are now running MicroPython on PiBeam. 92 | - If you want to use PiBeam as HID then you will have to install other boot firmware, instruction provided on [link](https://github.com/sbcshop/PiBeam_Software/edit/main/examples/HID_example_circuitpython/) 93 | 94 | ### 2. Onboard LED Blink 95 | - Download **Thonny IDE** from [Download link](https://thonny.org/) as per your OS and install it. 96 | - Once done start **Thonny IDE application**, Connect PiBeam to laptop/PC. 97 | - Select device at the bottom right with a suitable COM port, as shown in the below figure. You might get a different COM port. 98 | - Write simple onboard blink Python code or [Download Led blink code](https://github.com/sbcshop/PiBeam_Software/blob/main/examples/onboardLED_demo.py), then click on the green run button to make your script run on PiBeam. Make sure that you have also saved [PiBeam Library](https://github.com/sbcshop/PiBeam_Software/blob/main/examples/PiBeam.py) file to device to avoid any execution error. 99 | 100 | 101 | 102 | Now that we've reached this point, you're executing your script through Thonny IDE, so if you unplug PiBeam, it will stop running. To run your script without using an IDE, simply power up PiBeam and it should run your script, go to step 3. 103 | 104 | ### 3. How to move your script on PiBeam 105 | - Click on File -> Save Copy -> select Raspberry Pi Pico , Then save file as **main.py** 106 | 107 | 108 | 109 | In similar way you can add various python code files to Pico of PiBeam. Also you can try out sample codes given here in [examples folder](https://github.com/sbcshop/PiBeam_Software/tree/main/examples). 110 | 111 | - But in case if you want to move multiple files at one go, example suppose you are interested to save library files folder, below image demonstrate that 112 | 113 | 114 | - Here, we need only one library file [PiBeam.py](https://github.com/sbcshop/PiBeam_Software/blob/main/examples/PiBeam.py) for most of our code to try out, so move this to PiBeam with default name 115 | 116 | 117 | 118 | ### Example Codes 119 | Save whatever example code file you want to try as **main.py** in **PiBeam** as shown in above [step 3](https://github.com/sbcshop/PiBeam_Software/tree/main#3-how-to-move-your-script-on-pibeam), also add related library files with default name. 120 | In [example](https://github.com/sbcshop/PiBeam_Software/tree/main/examples) folder you will find demo example script code to test onboard components of PiBeam like 121 | - [Button and LED](https://github.com/sbcshop/PiBeam_Software/blob/main/examples/button_demo.py) : code to test programmable buttons and LED 122 | - [SD card](https://github.com/sbcshop/PiBeam_Software/blob/main/examples/sdcard_demo.py) : code to test micro SD card basic operations 123 | - [IR Transmitter](https://github.com/sbcshop/PiBeam_Software/blob/main/examples/transmitter_demo.py) : Demo code to test IR data transmission 124 | - [IR Receiver with LCD](https://github.com/sbcshop/PiBeam_Software/blob/main/examples/Receiver_LCD_sdcard_demo.py): Demo code to check received IR data on TFT display. Change protocol options as per your remote. 125 | 126 | To try below HID codes follow instructions provided on [link](https://github.com/sbcshop/PiBeam_Software/tree/main/examples/HID_example_circuitpython) 127 | - [Control PC Camera using PiBeam](https://github.com/sbcshop/PiBeam_Software/blob/main/examples/HID_example_circuitpython/Demo_CameraOn_code.py) : This demo code opens windows PC camera when power button of TV remote pressed. 128 | - [Display Images](https://github.com/sbcshop/PiBeam_Software/blob/main/examples/HID_example_circuitpython/Display_Images_FromPiBeam/image_display.py) : This demonstrates how to display images on a PiBeam display screen. 129 | 130 | Using this sample code as a guide, you can modify, build, and share codes!! 131 | 132 | ## Resources 133 | * [Schematic](https://github.com/sbcshop/PiBeam_Hardware/blob/main/Design%20Data/Sch%20PiBeam.pdf) 134 | * [Hardware Files](https://github.com/sbcshop/PiBeam_Hardware) 135 | * [3D Case Design File](https://github.com/sbcshop/PiBeam_Hardware/blob/main/Mechanical%20Data/PiBeam%20Casing%20STL%20files.zip) 136 | * [Step File](https://github.com/sbcshop/PiBeam_Hardware/blob/main/Mechanical%20Data/Step%20PiBeam.step) 137 | * [MicroPython getting started for RPi Pico/Pico W](https://docs.micropython.org/en/latest/rp2/quickref.html) 138 | * [Pico W Getting Started](https://projects.raspberrypi.org/en/projects/get-started-pico-w) 139 | * [RP2040 Datasheet](https://datasheets.raspberrypi.com/pico/pico-datasheet.pdf) 140 | 141 | 142 | ## Related Products 143 | * [ReadPi NFC](https://shop.sb-components.co.uk/products/readpi-an-rfid-nfc-reader-powered-with-raspberry-pi-pico-w?variant=40478483087443) - ReadPi with 13.56MHz NFC reader/writer powered by Raspberry Pi Pico W 144 | * [ArdiPi](https://shop.sb-components.co.uk/collections/latest-collections/products/ardipi-uno-r3-alternative-board-based-on-pico-w) - Arduino Uno form factor variants based on Raspberry Pi Pico W 145 | * [3.2" Touchsy Pico W](https://shop.sb-components.co.uk/collections/pre-order/products/touchsy-3-2-touch-lcd-display-based-on-pico-w) - 3.2" Touchsy Pico W with Resistive and Capacitive version. 146 | * [1.14” LCD HAT](https://shop.sb-components.co.uk/products/1-14-lcd-hat-for-pico) - 1.14” LCD HAT for Pico is a 1.14-inch display expansion board module of 240×135 resolution. 147 | * [1.14” LCD breakout](https://shop.sb-components.co.uk/products/1-14-inch-lcd-breakout) - The 1.14” LCD breakout is colorful and easy to experiment with graphics. 148 | 149 | 150 | ## Product License 151 | 152 | This is ***open source*** product. Kindly check LICENSE.md file for more information. 153 | 154 | Please contact support@sb-components.co.uk for technical support. 155 |

156 | 157 |

158 | -------------------------------------------------------------------------------- /documents/readme: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Demo_CameraOn_code.py: -------------------------------------------------------------------------------- 1 | from adafruit_hid.keyboard import Keyboard, Keycode 2 | from keyboard_layout_win_uk import KeyboardLayout 3 | from adafruit_display_text import label 4 | from PiBeam import LCD,IR,LED 5 | import usb_hid 6 | import time 7 | 8 | tft_bg_color = 0xFFFF00 # Yellow 9 | txt_color = 0x0000ff 10 | txt_font = 3 11 | 12 | tft = LCD(tft_bg_color) 13 | tft.bl() #tft.bl(False) - tft backlight off 14 | 15 | led = LED() 16 | 17 | ir = IR() 18 | 19 | tft.printf("SB COMPONENTS",txt_font,txt_color, 5, 40) 20 | tft.printf("PiBeam",txt_font,txt_color, 60, 80) 21 | 22 | def camera(): 23 | keyboard = Keyboard(usb_hid.devices) 24 | keyboard_layout = KeyboardLayout(keyboard) 25 | time.sleep(1) 26 | keyboard.send(Keycode.WINDOWS, Keycode.R) 27 | time.sleep(0.3) 28 | keyboard_layout.write('cmd.exe') 29 | keyboard.send(Keycode.ENTER) 30 | keyboard.send(Keycode.F11) 31 | time.sleep(1) 32 | keyboard_layout.write("start microsoft.windows.camera:") 33 | keyboard.send(Keycode.ENTER) 34 | tft.clear(tft_bg_color) 35 | tft.printf("Camera",txt_font,txt_color, 60, 40) 36 | tft.printf("ON",txt_font,txt_color, 90 ,80) 37 | keyboard.release_all() 38 | 39 | while True: 40 | val = ir.Read() # read for IR data incoming from IR remote 41 | if val is not None: 42 | led.on() 43 | print(val) 44 | #when power button of remote pressed, switch ON camera 45 | #change operation as per requirement 46 | if val[0] == 13 and val[1] == 245 and val[2] == 191 and val[3] == 64: #(13, 245, 191, 64) - code received for power button of remote 47 | print("camera on") 48 | camera() 49 | 50 | else: 51 | led.off() 52 | 53 | 54 | -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_FromPiBeam/README.md: -------------------------------------------------------------------------------- 1 | This code directly display images from onboard memory of RP2040 chip used on PiBeam instead of external SDCard. 2 | So, to achieve this simply create folder with name images in RP2040 default memory and upload images to it. 3 | Now running display_image.py file display images one by one on TFT display 4 | -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_FromPiBeam/image_display.py: -------------------------------------------------------------------------------- 1 | import os 2 | import board 3 | import terminalio 4 | import displayio 5 | import digitalio 6 | from adafruit_display_text import label 7 | from adafruit_st7789 import ST7789 8 | import busio 9 | import time 10 | 11 | 12 | # Release any resources currently in use for the displays 13 | displayio.release_displays() 14 | 15 | img_filenames = ( "/images/img1.bmp","/images/img2.bmp","/images/img3.bmp","/images/img4.bmp","/images/img5.bmp","/images/img6.bmp") 16 | 17 | board_type = os.uname().machine 18 | if 'Pico' in board_type: 19 | # Raspberry Pi Pico pinout, one possibility, at "southwest" of board 20 | tft_clk = board.GP10 # must be a SPI CLK 21 | tft_mosi= board.GP11 # must be a SPI TX 22 | tft_rst = board.GP12 23 | tft_dc = board.GP8 24 | tft_cs = board.GP9 25 | tft_bl = board.GP13 26 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi) 27 | else: 28 | print("ERROR: Unknown board!") 29 | 30 | display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_rst) 31 | display = ST7789(display_bus, rotation=180, width=135, height=240, rowstart=40, colstart=53) 32 | 33 | # Make the display context 34 | splash = displayio.Group() 35 | display.show(splash) 36 | 37 | tft_bl = board.GP13 38 | led = digitalio.DigitalInOut(tft_bl) 39 | led.direction = digitalio.Direction.OUTPUT 40 | led.value=True 41 | 42 | bmpfiles = sorted("/images/" + fn for fn in os.listdir("/images") if fn.lower().endswith("bmp")) 43 | 44 | while True: 45 | if len(bmpfiles) == 0: 46 | print("N0, BMP Files") 47 | break 48 | 49 | for filename in bmpfiles: 50 | print("showing bmp image", filename) 51 | 52 | bitmap_file = open(filename, "rb") 53 | bitmap = displayio.OnDiskBitmap(bitmap_file) 54 | tile_grid = displayio.TileGrid(bitmap,pixel_shader=getattr(bitmap, 'pixel_shader', displayio.ColorConverter())) 55 | 56 | group = displayio.Group() 57 | group.append(tile_grid) 58 | display.show(group) 59 | 60 | time.sleep(2)# Show the image for 2 seconds 61 | -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_FromPiBeam/images/img1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/Display_Images_FromPiBeam/images/img1.bmp -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_FromPiBeam/images/img2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/Display_Images_FromPiBeam/images/img2.bmp -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_FromPiBeam/images/img3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/Display_Images_FromPiBeam/images/img3.bmp -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_FromPiBeam/images/img4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/Display_Images_FromPiBeam/images/img4.bmp -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_FromPiBeam/images/img5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/Display_Images_FromPiBeam/images/img5.bmp -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_FromPiBeam/images/img6.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/Display_Images_FromPiBeam/images/img6.bmp -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_from_SDCard/README.md: -------------------------------------------------------------------------------- 1 | Create folder with name images and copy sample images provided in folder to your SDCard which is inserted in PiBeam. 2 | Run the [display_sdcard_images.py](https://github.com/sbcshop/PiBeam_Software/blob/main/examples/HID_example_circuitpython/Display_Images_from_SDCard/display_sdcard_images.py) code for testing 3 | -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_from_SDCard/display_sdcard_images.py: -------------------------------------------------------------------------------- 1 | import time 2 | import board 3 | import math 4 | import busio 5 | import terminalio 6 | import displayio 7 | import adafruit_imageload 8 | from adafruit_st7789 import ST7789 9 | import os 10 | import adafruit_sdcard 11 | import digitalio 12 | import storage 13 | 14 | spi = busio.SPI(board.GP18, board.GP19, board.GP16) 15 | cs = digitalio.DigitalInOut(board.GP17) 16 | sdcard = adafruit_sdcard.SDCard(spi, cs) 17 | vfs = storage.VfsFat(sdcard) 18 | storage.mount(vfs, "/sd") 19 | 20 | tft_bl = board.GP13 21 | led = digitalio.DigitalInOut(tft_bl) 22 | led.direction = digitalio.Direction.OUTPUT 23 | led.value=True 24 | # Release any resources currently in use for the displays 25 | displayio.release_displays() 26 | 27 | tft_clk = board.GP10 # must be a SPI CLK 28 | tft_mosi= board.GP11 # must be a SPI TX 29 | tft_rst = board.GP12 30 | tft_dc = board.GP8 31 | tft_cs = board.GP9 32 | tft_bl = board.GP13 33 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi) 34 | 35 | 36 | # Make the displayio SPI bus 37 | display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_rst) 38 | display = ST7789(display_bus, rotation=180, width=135, height=240, rowstart=40, colstart=53) 39 | 40 | # Make the main display context 41 | main = displayio.Group() 42 | display.show(main) 43 | 44 | bmpfiles = sorted("/sd/images/" + fn for fn in os.listdir("/sd/images/") if fn.lower().endswith("bmp")) 45 | 46 | while True: 47 | if len(bmpfiles) == 0: 48 | print("N0, BMP Files") 49 | break 50 | 51 | for filename in bmpfiles: 52 | print("showing bmp image", filename) 53 | 54 | bitmap_file = open(filename, "rb") 55 | bitmap = displayio.OnDiskBitmap(bitmap_file) 56 | tile_grid = displayio.TileGrid(bitmap,pixel_shader=getattr(bitmap, 'pixel_shader', displayio.ColorConverter())) 57 | 58 | group = displayio.Group() 59 | group.append(tile_grid) 60 | display.show(group) 61 | 62 | time.sleep(2)# Show the image for 2 seconds 63 | time.sleep(0.01) -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_from_SDCard/images/img1.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/Display_Images_from_SDCard/images/img1.bmp -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_from_SDCard/images/img2.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/Display_Images_from_SDCard/images/img2.bmp -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_from_SDCard/images/img3.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/Display_Images_from_SDCard/images/img3.bmp -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_from_SDCard/images/img4.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/Display_Images_from_SDCard/images/img4.bmp -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_from_SDCard/images/img5.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/Display_Images_from_SDCard/images/img5.bmp -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/Display_Images_from_SDCard/images/img6.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/Display_Images_from_SDCard/images/img6.bmp -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/PiBeam_HID_firmware.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/PiBeam_HID_firmware.uf2 -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/PiBeam.py: -------------------------------------------------------------------------------- 1 | # Basic Program to start camera of device and ongoing operations displayed on TFT 2 | # This code tested for Windows based PC/Laptop but can be modified for Other OS 3 | import time 4 | import os 5 | import usb_hid 6 | import digitalio 7 | import board 8 | import busio 9 | import terminalio 10 | import displayio 11 | import pulseio 12 | import adafruit_irremote 13 | from adafruit_display_text import label 14 | from adafruit_hid.keyboard import Keyboard, Keycode 15 | from keyboard_layout_win_uk import KeyboardLayout 16 | from adafruit_st7789 import ST7789 17 | 18 | class LCD: 19 | def __init__(self,BG_COLOR): 20 | 21 | displayio.release_displays() 22 | self.BG_COLOR = BG_COLOR 23 | 24 | self.tft_clk = board.GP10 # must be a SPI CLK 25 | self.tft_mosi= board.GP11 # must be a SPI TX 26 | self.tft_rst = board.GP12 27 | self.tft_dc = board.GP8 28 | self.tft_cs = board.GP9 29 | self.spi = busio.SPI(clock=self.tft_clk, MOSI=self.tft_mosi) 30 | 31 | self.display_bus = displayio.FourWire(self.spi, command=self.tft_dc, chip_select=self.tft_cs, reset=self.tft_rst) 32 | self.display = ST7789(self.display_bus, rotation=270, width=240, height=135, rowstart=40, colstart=53) 33 | 34 | # Make the display context 35 | self.splash = displayio.Group() 36 | self.display.show(self.splash) 37 | 38 | color_bitmap = displayio.Bitmap(self.display.width, self.display.height, 1) 39 | color_palette = displayio.Palette(1) 40 | color_palette[0] = BG_COLOR 41 | 42 | bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) 43 | self.splash.append(bg_sprite) 44 | 45 | def bl(self,val = True): 46 | self.tft_bl = board.GP13 47 | self.led = digitalio.DigitalInOut(self.tft_bl) 48 | self.led.direction = digitalio.Direction.OUTPUT 49 | 50 | if val == True: 51 | self.led.value=True 52 | 53 | elif val == False: 54 | self.led.value=False 55 | 56 | def clear(self,color): 57 | color_bitmap = displayio.Bitmap(self.display.width, self.display.height, 1) 58 | color_palette = displayio.Palette(1) 59 | color_palette[0] = color 60 | 61 | bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) 62 | self.splash.append(bg_sprite) 63 | 64 | # This function creates colorful rectangular box 65 | def inner_rectangle(self,BORDER,frame_color): 66 | # Draw a smaller inner rectangle 67 | inner_bitmap = displayio.Bitmap(self.display.width - BORDER * 2, self.display.height - BORDER * 2, 1) 68 | inner_palette = displayio.Palette(1) 69 | inner_palette[0] = frame_color 70 | inner_sprite = displayio.TileGrid(inner_bitmap, pixel_shader=inner_palette, x=BORDER, y=BORDER) 71 | self.splash.append(inner_sprite) 72 | 73 | #Function to print data on TFT 74 | def printf(self,text,FONTSCALE,TEXT_COLOR,x_pos, y_pos): 75 | text_area = label.Label(terminalio.FONT, text=text, color=TEXT_COLOR) 76 | text_group = displayio.Group(scale=FONTSCALE,x=x_pos,y=y_pos,) 77 | text_group.append(text_area) # Subgroup for text scaling 78 | self.splash.append(text_group) 79 | 80 | class IR: 81 | def __init__(self): 82 | self.pin = board.GP1 83 | self.pulsein = pulseio.PulseIn(self.pin, maxlen=120, idle_state=True) 84 | self.decoder = adafruit_irremote.NonblockingGenericDecode(self.pulsein) 85 | 86 | def Read(self): 87 | for message in self.decoder.read(): 88 | if isinstance(message, adafruit_irremote.IRMessage): 89 | return message.code 90 | #print("Decoded:", message.code) 91 | class LED: 92 | def __init__(self): 93 | self.tft_bl = board.GP25 94 | self.led = digitalio.DigitalInOut(self.tft_bl) 95 | self.led.direction = digitalio.Direction.OUTPUT 96 | 97 | def on(self): 98 | self.led.value=True 99 | 100 | def off(self): 101 | self.led.value=False 102 | -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_display_text/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_display_text/__init__.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_display_text/bitmap_label.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_display_text/bitmap_label.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_display_text/label.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_display_text/label.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_display_text/scrolling_label.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_display_text/scrolling_label.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_hid/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_hid/__init__.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_hid/consumer_control.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_hid/consumer_control.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_hid/consumer_control_code.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_hid/consumer_control_code.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_hid/keyboard.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_hid/keyboard.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_hid/keyboard_layout_base.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_hid/keyboard_layout_base.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_hid/keyboard_layout_us.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_hid/keyboard_layout_us.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_hid/keycode.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_hid/keycode.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_hid/mouse.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_hid/mouse.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/__init__.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/bmp/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/bmp/__init__.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/bmp/indexed.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/bmp/indexed.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/bmp/negative_height_check.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/bmp/negative_height_check.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/displayio_types.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/displayio_types.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/gif.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/gif.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/png.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/png.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/__init__.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/pbm_ascii.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/pbm_ascii.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/pbm_binary.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/pbm_binary.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/pgm/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/pgm/__init__.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/pgm/ascii.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/pgm/ascii.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/pgm/binary.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/pgm/binary.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/ppm_ascii.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/ppm_ascii.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/ppm_binary.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/pnm/ppm_binary.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_imageload/tilegrid_inflator.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_imageload/tilegrid_inflator.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_irremote.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Scott Shawcroft for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | # pylint: disable=missing-module-docstring 6 | from __future__ import annotations 7 | 8 | import array 9 | from collections import namedtuple 10 | import time 11 | 12 | try: 13 | from typing import List, NamedTuple, Optional, Tuple 14 | from pulseio import PulseOut 15 | except ImportError: 16 | pass 17 | 18 | """ 19 | `adafruit_irremote` 20 | ==================================================== 21 | 22 | Demo code for Circuit Playground Express: 23 | 24 | .. code-block:: python 25 | 26 | # Circuit Playground Express Demo Code 27 | # Adjust the pulseio 'board.PIN' if using something else 28 | import pulseio 29 | import board 30 | import adafruit_irremote 31 | 32 | pulsein = pulseio.PulseIn(board.REMOTEIN, maxlen=120, idle_state=True) 33 | decoder = adafruit_irremote.GenericDecode() 34 | 35 | 36 | while True: 37 | pulses = decoder.read_pulses(pulsein) 38 | print("Heard", len(pulses), "Pulses:", pulses) 39 | try: 40 | code = decoder.decode_bits(pulses) 41 | print("Decoded:", code) 42 | except adafruit_irremote.IRNECRepeatException: # unusual short code! 43 | print("NEC repeat!") 44 | except adafruit_irremote.IRDecodeException as e: # failed to decode 45 | print("Failed to decode: ", e.args) 46 | 47 | print("----------------------------") 48 | 49 | * Author(s): Scott Shawcroft 50 | 51 | Implementation Notes 52 | -------------------- 53 | 54 | **Hardware:** 55 | 56 | * `CircuitPlayground Express `_ 57 | 58 | * `IR Receiver Sensor `_ 59 | 60 | **Software and Dependencies:** 61 | 62 | * Adafruit CircuitPython firmware for the ESP8622 and M0-based boards: 63 | https://github.com/adafruit/circuitpython/releases 64 | 65 | """ 66 | 67 | __version__ = "0.0.0+auto.0" 68 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_IRRemote.git" 69 | 70 | 71 | class IRDecodeException(Exception): 72 | """Generic decode exception""" 73 | 74 | 75 | class IRNECRepeatException(Exception): 76 | """Exception when a NEC repeat is decoded""" 77 | 78 | 79 | def bin_data(pulses: List) -> List[List]: 80 | """Compute bins of pulse lengths where pulses are +-25% of the average. 81 | 82 | :param list pulses: Input pulse lengths 83 | """ 84 | bins = [[pulses[0], 0]] 85 | 86 | for _, pulse in enumerate(pulses): 87 | matchedbin = False 88 | # print(pulse, end=": ") 89 | for b, pulse_bin in enumerate(bins): 90 | if pulse_bin[0] * 0.75 <= pulse <= pulse_bin[0] * 1.25: 91 | # print("matches bin") 92 | bins[b][0] = (pulse_bin[0] + pulse) // 2 # avg em 93 | bins[b][1] += 1 # track it 94 | matchedbin = True 95 | break 96 | if not matchedbin: 97 | bins.append([pulse, 1]) 98 | # print(bins) 99 | return bins 100 | 101 | 102 | def decode_bits(pulses: List) -> NamedTuple: 103 | """Decode the pulses into bits.""" 104 | # pylint: disable=too-many-branches,too-many-statements 105 | 106 | # TODO The name pulses is redefined several times below, so we'll stash the 107 | # original in a separate variable for now. It might be worth refactoring to 108 | # avoid redefining pulses, for the sake of readability. 109 | input_pulses = tuple(pulses) 110 | pulses = list(pulses) # Copy to avoid mutating input. 111 | 112 | # special exception for NEC repeat code! 113 | if ( 114 | (len(pulses) == 3) 115 | and (8000 <= pulses[0] <= 10000) 116 | and (2000 <= pulses[1] <= 3000) 117 | and (450 <= pulses[2] <= 700) 118 | ): 119 | return NECRepeatIRMessage(input_pulses) 120 | 121 | if len(pulses) < 10: 122 | msg = UnparseableIRMessage(input_pulses, reason="Too short") 123 | raise FailedToDecode(msg) 124 | 125 | # Ignore any header (evens start at 1), and any trailer. 126 | if len(pulses) % 2 == 0: 127 | pulses_end = -1 128 | else: 129 | pulses_end = None 130 | 131 | evens = pulses[1:pulses_end:2] 132 | odds = pulses[2:pulses_end:2] 133 | 134 | # bin both halves 135 | even_bins = bin_data(evens) 136 | odd_bins = bin_data(odds) 137 | 138 | outliers = [b[0] for b in (even_bins + odd_bins) if b[1] == 1] 139 | even_bins = [b for b in even_bins if b[1] > 1] 140 | odd_bins = [b for b in odd_bins if b[1] > 1] 141 | 142 | if not even_bins or not odd_bins: 143 | msg = UnparseableIRMessage(input_pulses, reason="Not enough data") 144 | raise FailedToDecode(msg) 145 | 146 | if len(even_bins) == 1: 147 | pulses = odds 148 | pulse_bins = odd_bins 149 | elif len(odd_bins) == 1: 150 | pulses = evens 151 | pulse_bins = even_bins 152 | else: 153 | msg = UnparseableIRMessage(input_pulses, reason="Both even/odd pulses differ") 154 | raise FailedToDecode(msg) 155 | 156 | if len(pulse_bins) == 1: 157 | msg = UnparseableIRMessage(input_pulses, reason="Pulses do not differ") 158 | raise FailedToDecode(msg) 159 | if len(pulse_bins) > 2: 160 | msg = UnparseableIRMessage(input_pulses, reason="Only mark & space handled") 161 | raise FailedToDecode(msg) 162 | 163 | mark = min(pulse_bins[0][0], pulse_bins[1][0]) 164 | space = max(pulse_bins[0][0], pulse_bins[1][0]) 165 | 166 | if outliers: 167 | # skip outliers 168 | pulses = [ 169 | p for p in pulses if not (outliers[0] * 0.75) <= p <= (outliers[0] * 1.25) 170 | ] 171 | # convert marks/spaces to 0 and 1 172 | for i, pulse_length in enumerate(pulses): 173 | if (space * 0.75) <= pulse_length <= (space * 1.25): 174 | pulses[i] = False 175 | elif (mark * 0.75) <= pulse_length <= (mark * 1.25): 176 | pulses[i] = True 177 | else: 178 | msg = UnparseableIRMessage(input_pulses, reason="Pulses outside mark/space") 179 | raise FailedToDecode(msg) 180 | 181 | # convert bits to bytes! 182 | output = [0] * ((len(pulses) + 7) // 8) 183 | for i, pulse_length in enumerate(pulses): 184 | output[i // 8] = output[i // 8] << 1 185 | if pulse_length: 186 | output[i // 8] |= 1 187 | return IRMessage(tuple(input_pulses), code=tuple(output)) 188 | 189 | 190 | IRMessage = namedtuple("IRMessage", ("pulses", "code")) 191 | "Pulses and the code they were parsed into" 192 | 193 | UnparseableIRMessage = namedtuple("IRMessage", ("pulses", "reason")) 194 | "Pulses and the reason that they could not be parsed into a code" 195 | 196 | NECRepeatIRMessage = namedtuple("NECRepeatIRMessage", ("pulses",)) 197 | "Pulses interpreted as an NEC repeat code" 198 | 199 | 200 | class FailedToDecode(Exception): 201 | "Raised by decode_bits. Error argument is UnparseableIRMessage" 202 | 203 | 204 | class NonblockingGenericDecode: 205 | """ 206 | Decode pulses into bytes in a non-blocking fashion. 207 | 208 | :param ~pulseio.PulseIn input_pulses: Object to read pulses from 209 | :param int max_pulse: Pulse duration to end a burst. Units are microseconds. 210 | 211 | >>> pulses = PulseIn(...) 212 | >>> decoder = NonblockingGenericDecoder(pulses) 213 | >>> for message in decoder.read(): 214 | ... if isinstance(message, IRMessage): 215 | ... message.code # TA-DA! Do something with this in your application. 216 | ... else: 217 | ... # message is either NECRepeatIRMessage or 218 | ... # UnparseableIRMessage. You may decide to ignore it, raise 219 | ... # an error, or log the issue to a file. If you raise or log, 220 | ... # it may be helpful to include message.pulses in the error message. 221 | ... ... 222 | """ 223 | 224 | def __init__(self, pulses: List, max_pulse: int = 10_000) -> None: 225 | self.pulses = pulses # PulseIn 226 | self.max_pulse = max_pulse 227 | self._unparsed_pulses = [] # internal buffer of partial messages 228 | 229 | def read(self) -> None: 230 | """ 231 | Consume all pulses from PulseIn. Yield decoded messages, if any. 232 | 233 | If a partial message is received, this does not block to wait for the 234 | rest. It stashes the partial message, to be continued the next time it 235 | is called. 236 | """ 237 | # Consume from PulseIn. 238 | while self.pulses: 239 | pulse = self.pulses.popleft() 240 | self._unparsed_pulses.append(pulse) 241 | if pulse > self.max_pulse: 242 | # End of message! Decode it and yield a BaseIRMessage. 243 | try: 244 | yield decode_bits(self._unparsed_pulses) 245 | except FailedToDecode as err: 246 | # If you want to debug failed decodes, this would be a good 247 | # place to print/log or (re-)raise. 248 | unparseable_message = err.args[0] 249 | yield unparseable_message 250 | self._unparsed_pulses.clear() 251 | # TODO Do we need to consume and throw away more pulses here? 252 | # I'm unclear about the role that "pruning" plays in the 253 | # original implementation in GenericDecode._read_pulses_non_blocking. 254 | # When we reach here, we have consumed everything from PulseIn. 255 | # If there are some pulses in self._unparsed_pulses, they represent 256 | # partial messages. We'll finish them next time read() is called. 257 | 258 | 259 | class GenericDecode: 260 | """Generic decoding of infrared signals""" 261 | 262 | # Note: pylint's complaint about the following three methods (no self-use) 263 | # is absolutely correct, which is why the code was refactored, but we need 264 | # this here for back-compat, hence we disable pylint for that specific 265 | # complaint. 266 | 267 | def bin_data(self, pulses: List) -> List[List]: # pylint: disable=no-self-use 268 | "Wraps the top-level function bin_data for backward-compatibility." 269 | return bin_data(pulses) 270 | 271 | def decode_bits(self, pulses: List) -> Tuple: # pylint: disable=no-self-use 272 | "Wraps the top-level function decode_bits for backward-compatibility." 273 | try: 274 | result = decode_bits(pulses) 275 | except FailedToDecode as err: 276 | raise IRDecodeException from err 277 | if isinstance(result, NECRepeatIRMessage): 278 | raise IRNECRepeatException() 279 | return result.code 280 | 281 | def _read_pulses_non_blocking( # pylint: disable=no-self-use 282 | self, input_pulses: List, max_pulse: int = 10000, pulse_window: float = 0.10 283 | ) -> Optional[List]: 284 | """Read out a burst of pulses without blocking until pulses stop for a specified 285 | period (pulse_window), pruning pulses after a pulse longer than ``max_pulse``. 286 | 287 | :param ~pulseio.PulseIn input_pulses: Object to read pulses from 288 | :param int max_pulse: Pulse duration to end a burst 289 | :param float pulse_window: pulses are collected for this period of time 290 | """ 291 | # Note: pylint's complaint (no self-use) is absolutely correct, which 292 | # is why the code was refactored, but we need this here for 293 | # back-compat, hence we disable pylint. 294 | received = None 295 | recent_count = 0 296 | pruning = False 297 | while True: 298 | while input_pulses: 299 | pulse = input_pulses.popleft() 300 | recent_count += 1 301 | if pulse > max_pulse: 302 | if received is None: 303 | continue 304 | pruning = True 305 | if not pruning: 306 | if received is None: 307 | received = [] 308 | received.append(pulse) 309 | 310 | if recent_count == 0: 311 | return received 312 | recent_count = 0 313 | time.sleep(pulse_window) 314 | 315 | def read_pulses( 316 | self, 317 | input_pulses: list, 318 | *, 319 | max_pulse: int = 10000, 320 | blocking: bool = True, 321 | pulse_window: float = 0.10, 322 | blocking_delay: float = 0.10, 323 | ) -> Optional[List]: 324 | """Read out a burst of pulses until pulses stop for a specified 325 | period (pulse_window), pruning pulses after a pulse longer than ``max_pulse``. 326 | 327 | :param ~pulseio.PulseIn input_pulses: Object to read pulses from 328 | :param int max_pulse: Pulse duration to end a burst 329 | :param bool blocking: If True, will block until pulses found. 330 | If False, will return None if no pulses. 331 | Defaults to True for backwards compatibility 332 | :param float pulse_window: pulses are collected for this period of time 333 | :param float blocking_delay: delay between pulse checks when blocking 334 | """ 335 | while True: 336 | pulses = self._read_pulses_non_blocking( 337 | input_pulses, max_pulse, pulse_window 338 | ) 339 | if blocking and pulses is None: 340 | time.sleep(blocking_delay) 341 | continue 342 | return pulses 343 | 344 | 345 | class GenericTransmit: 346 | """Generic infrared transmit class that handles encoding. 347 | 348 | :param int header: The length of header in microseconds 349 | :param int one: The length of a one in microseconds 350 | :param int zero: The length of a zero in microseconds 351 | :param int trail: The length of the trail in microseconds, set to None to disable 352 | :param bool debug: Enable debug output, default False 353 | """ 354 | 355 | def __init__( 356 | self, header: int, one: int, zero: int, trail: int, *, debug: bool = False 357 | ) -> None: 358 | self.header = header 359 | self.one = one 360 | self.zero = zero 361 | self.trail = trail 362 | self.debug = debug 363 | 364 | def transmit( 365 | self, 366 | pulseout: PulseOut, 367 | data: bytearray, 368 | *, 369 | repeat: int = 0, 370 | delay: float = 0.0, 371 | nbits: Optional[int] = None, 372 | ) -> None: 373 | """Transmit the ``data`` using the ``pulseout``. 374 | 375 | :param pulseio.PulseOut pulseout: PulseOut to transmit on 376 | :param bytearray data: Data to transmit 377 | :param int repeat: Number of additional retransmissions of the data, default 0 378 | :param float delay: Delay between any retransmissions, default 0.0 379 | :param int nbits: Optional number of bits to send, 380 | useful to send fewer bits than in the data bytes 381 | """ 382 | bits_to_send = len(data) * 8 383 | if nbits is not None and nbits < bits_to_send: 384 | bits_to_send = nbits 385 | 386 | durations = array.array( 387 | "H", [0] * (2 + bits_to_send * 2 + (0 if self.trail is None else 1)) 388 | ) 389 | 390 | durations[0] = self.header[0] 391 | durations[1] = self.header[1] 392 | if self.trail is not None: 393 | durations[-1] = self.trail 394 | out = 2 395 | bit_count = 0 396 | for byte_index, _ in enumerate(data): 397 | for i in range(7, -1, -1): 398 | if (data[byte_index] & 1 << i) > 0: 399 | durations[out] = self.one[0] 400 | durations[out + 1] = self.one[1] 401 | else: 402 | durations[out] = self.zero[0] 403 | durations[out + 1] = self.zero[1] 404 | out += 2 405 | bit_count += 1 406 | if bit_count >= bits_to_send: 407 | break 408 | 409 | if self.debug: 410 | print(durations) 411 | 412 | pulseout.send(durations) 413 | for _ in range(repeat): 414 | if delay: 415 | time.sleep(delay) 416 | pulseout.send(durations) 417 | -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_sdcard.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2014-2016 Damien George 2 | # SPDX-FileCopyrightText: 2014-2016 Peter Hinch 3 | # SPDX-FileCopyrightText: 2014-2016 Radomir Dopieralski 4 | # SPDX-FileCopyrightText: 2017 Scott Shawcroft for Adafruit Industries 5 | # 6 | # SPDX-License-Identifier: MIT 7 | 8 | import time 9 | from micropython import const 10 | from adafruit_bus_device import spi_device 11 | 12 | try: 13 | from typing import Union, Optional 14 | from busio import SPI 15 | from digitalio import DigitalInOut 16 | from circuitpython_typing import ReadableBuffer, WriteableBuffer 17 | except ImportError: 18 | pass 19 | 20 | __version__ = "0.0.0-auto.0" 21 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_SD.git" 22 | 23 | _CMD_TIMEOUT = const(200) 24 | 25 | _R1_IDLE_STATE = const(1 << 0) 26 | # R1_ERASE_RESET = const(1 << 1) 27 | _R1_ILLEGAL_COMMAND = const(1 << 2) 28 | # R1_COM_CRC_ERROR = const(1 << 3) 29 | # R1_ERASE_SEQUENCE_ERROR = const(1 << 4) 30 | # R1_ADDRESS_ERROR = const(1 << 5) 31 | # R1_PARAMETER_ERROR = const(1 << 6) 32 | _TOKEN_CMD25 = const(0xFC) 33 | _TOKEN_STOP_TRAN = const(0xFD) 34 | _TOKEN_DATA = const(0xFE) 35 | 36 | # pylint: disable-msg=superfluous-parens 37 | class SDCard: 38 | """Controls an SD card over SPI. 39 | :param ~busio.SPI spi: The SPI bus 40 | :param ~digitalio.DigitalInOut cs: The chip select connected to the card 41 | :param int baudrate: The SPI data rate to use after card setup 42 | Example usage: 43 | .. code-block:: python 44 | import busio 45 | import storage 46 | import adafruit_sdcard 47 | import os 48 | import board 49 | spi = busio.SPI(SCK, MOSI, MISO) 50 | sd = adafruit_sdcard.SDCard(spi, board.SD_CS) 51 | vfs = storage.VfsFat(sdcard) 52 | storage.mount(vfs, '/sd') 53 | os.listdir('/') 54 | """ 55 | 56 | def __init__(self, spi: SPI, cs: DigitalInOut, baudrate: int = 1320000) -> None: 57 | # Create an SPIDevice running at a lower initialization baudrate first. 58 | self._spi = spi_device.SPIDevice(spi, cs, baudrate=250000, extra_clocks=8) 59 | 60 | self._cmdbuf = bytearray(6) 61 | self._single_byte = bytearray(1) 62 | 63 | # Card is byte addressing, set to 1 if addresses are per block 64 | self._cdv = 512 65 | 66 | # initialise the card 67 | self._init_card(cs) 68 | 69 | # Create a new SPIDevice with the (probably) higher operating baudrate. 70 | self._spi = spi_device.SPIDevice(spi, cs, baudrate=baudrate, extra_clocks=8) 71 | 72 | def _init_card(self, chip_select: DigitalInOut) -> None: 73 | """Initialize the card in SPI mode.""" 74 | # clock card at least 80 cycles with cs high 75 | with self._spi as card: 76 | # Force CS high. 77 | chip_select.value = True 78 | self._single_byte[0] = 0xFF 79 | for _ in range(80 // 8 + 1): 80 | card.write(self._single_byte) 81 | 82 | with self._spi as card: 83 | # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) 84 | for _ in range(5): 85 | if self._cmd(card, 0, 0, 0x95) == _R1_IDLE_STATE: 86 | break 87 | else: 88 | raise OSError("no SD card") 89 | 90 | # CMD8: determine card version 91 | rb7 = bytearray(4) 92 | r = self._cmd(card, 8, 0x01AA, 0x87, rb7, data_block=False) 93 | if r == _R1_IDLE_STATE: 94 | self._init_card_v2(card) 95 | elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): 96 | self._init_card_v1(card) 97 | else: 98 | raise OSError("couldn't determine SD card version") 99 | 100 | # get the number of sectors 101 | # CMD9: response R2 (R1 byte + 16-byte block read) 102 | csd = bytearray(16) 103 | if self._cmd(card, 9, 0, 0xAF, response_buf=csd) != 0: 104 | raise OSError("no response from SD card") 105 | # self.readinto(csd) 106 | csd_version = (csd[0] & 0xC0) >> 6 107 | if csd_version >= 2: 108 | raise OSError("SD card CSD format not supported") 109 | 110 | if csd_version == 1: 111 | self._sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 112 | else: 113 | block_length = 2 ** (csd[5] & 0xF) 114 | c_size = ((csd[6] & 0x3) << 10) | (csd[7] << 2) | ((csd[8] & 0xC) >> 6) 115 | mult = 2 ** (((csd[9] & 0x3) << 1 | (csd[10] & 0x80) >> 7) + 2) 116 | self._sectors = block_length // 512 * mult * (c_size + 1) 117 | 118 | # CMD16: set block length to 512 bytes 119 | if self._cmd(card, 16, 512, 0x15) != 0: 120 | raise OSError("can't set 512 block size") 121 | 122 | def _init_card_v1(self, card: SPI) -> None: 123 | """Initialize v1 SDCards which use byte addressing.""" 124 | for _ in range(_CMD_TIMEOUT): 125 | self._cmd(card, 55, 0, 0) 126 | if self._cmd(card, 41, 0, 0) == 0: 127 | # print("[SDCard] v1 card") 128 | return 129 | raise OSError("timeout waiting for v1 card") 130 | 131 | def _init_card_v2(self, card: SPI) -> None: 132 | """Initialize v2 SDCards which use 512-byte block addressing.""" 133 | ocr = bytearray(4) 134 | for _ in range(_CMD_TIMEOUT): 135 | time.sleep(0.050) 136 | self._cmd(card, 58, 0, 0xFD, response_buf=ocr, data_block=False) 137 | self._cmd(card, 55, 0, 0x65) 138 | # On non-longint builds, we cannot use 0x40000000 directly as the arg 139 | # so break it into bytes, which are interpreted by self._cmd(). 140 | if self._cmd(card, 41, b"\x40\x00\x00\x00", 0x77) == 0: 141 | self._cmd(card, 58, 0, 0xFD, response_buf=ocr, data_block=False) 142 | 143 | # Check for block addressing 144 | if (ocr[0] & 0x40) != 0: 145 | self._cdv = 1 146 | # print("[SDCard] v2 card") 147 | return 148 | raise OSError("timeout waiting for v2 card") 149 | 150 | def _wait_for_ready(self, card: SPI, timeout: float = 0.3) -> None: 151 | """ 152 | Wait for the card to clock out 0xff to indicate its ready. 153 | :param busio.SPI card: The locked SPI bus. 154 | :param float timeout: Maximum time to wait in seconds. 155 | """ 156 | start_time = time.monotonic() 157 | self._single_byte[0] = 0x00 158 | while time.monotonic() - start_time < timeout and self._single_byte[0] != 0xFF: 159 | card.readinto(self._single_byte, write_value=0xFF) 160 | 161 | # pylint: disable-msg=too-many-arguments 162 | # pylint: disable=no-member 163 | # no-member disable should be reconsidered when it can be tested 164 | def _cmd( 165 | self, 166 | card: SPI, 167 | cmd: int, 168 | arg: Union[int, ReadableBuffer] = 0, 169 | crc: int = 0, 170 | response_buf: Optional[WriteableBuffer] = None, 171 | data_block: bool = True, 172 | wait: bool = True, 173 | ) -> int: 174 | """ 175 | Issue a command to the card and read an optional data response. 176 | :param busio.SPI card: The locked SPI bus. 177 | :param int cmd: The command number. 178 | :param int|buf(4) arg: The command argument 179 | :param int crc: The crc to allow the card to verify the command and argument. 180 | :param WriteableBuffer response_buf: Buffer to read a data block response into. 181 | :param bool data_block: True if the response data is in a data block. 182 | :param bool wait: True if the command should wait until the card is ready 183 | """ 184 | # create and send the command 185 | buf = self._cmdbuf 186 | buf[0] = 0x40 | cmd 187 | if isinstance(arg, int): 188 | buf[1] = (arg >> 24) & 0xFF 189 | buf[2] = (arg >> 16) & 0xFF 190 | buf[3] = (arg >> 8) & 0xFF 191 | buf[4] = arg & 0xFF 192 | elif len(arg) == 4: 193 | # arg can be a 4-byte buf 194 | buf[1:5] = arg 195 | else: 196 | raise ValueError() 197 | 198 | if crc == 0: 199 | buf[5] = calculate_crc(buf[:-1]) 200 | else: 201 | buf[5] = crc 202 | 203 | if wait: 204 | self._wait_for_ready(card) 205 | 206 | card.write(buf) 207 | 208 | # wait for the response (response[7] == 0) 209 | for _ in range(_CMD_TIMEOUT): 210 | card.readinto(buf, end=1, write_value=0xFF) 211 | if not (buf[0] & 0x80): 212 | if response_buf: 213 | if data_block: 214 | # Wait for the start block byte 215 | buf[1] = 0xFF 216 | while buf[1] != 0xFE: 217 | card.readinto(buf, start=1, end=2, write_value=0xFF) 218 | card.readinto(response_buf, write_value=0xFF) 219 | if data_block: 220 | # Read the checksum 221 | card.readinto(buf, start=1, end=3, write_value=0xFF) 222 | return buf[0] 223 | return -1 224 | 225 | # pylint: enable-msg=too-many-arguments 226 | 227 | # pylint: disable-msg=too-many-arguments 228 | def _block_cmd( 229 | self, 230 | card: SPI, 231 | cmd: int, 232 | block: int, 233 | crc: int, 234 | response_buf: Optional[WriteableBuffer] = None, 235 | ) -> int: 236 | """ 237 | Issue a command to the card with a block argument. 238 | :param busio.SPI card: The locked SPI bus. 239 | :param int cmd: The command number. 240 | :param int block: The relevant block. 241 | :param int crc: The crc to allow the card to verify the command and argument. 242 | :param WriteableBuffer response_buf: Buffer to read a data block response into. 243 | """ 244 | if self._cdv == 1: 245 | return self._cmd(card, cmd, block, crc, response_buf=response_buf) 246 | 247 | # create and send the command 248 | buf = self._cmdbuf 249 | buf[0] = 0x40 | cmd 250 | # We address by byte because cdv is 512. Instead of multiplying, shift 251 | # the data to the correct spot so that we don't risk creating a long 252 | # int. 253 | buf[1] = (block >> 15) & 0xFF 254 | buf[2] = (block >> 7) & 0xFF 255 | buf[3] = (block << 1) & 0xFF 256 | buf[4] = 0 257 | 258 | if crc == 0: 259 | buf[5] = calculate_crc(buf[:-1]) 260 | else: 261 | buf[5] = crc 262 | 263 | result = -1 264 | self._wait_for_ready(card) 265 | 266 | card.write(buf) 267 | 268 | # wait for the response (response[7] == 0) 269 | for _ in range(_CMD_TIMEOUT): 270 | card.readinto(buf, end=1, write_value=0xFF) 271 | if not (buf[0] & 0x80): 272 | result = buf[0] 273 | break 274 | 275 | # pylint: disable=singleton-comparison 276 | # Disable should be removed when refactor can be tested. 277 | if response_buf != None and result == 0: 278 | self._readinto(card, response_buf) 279 | 280 | return result 281 | 282 | # pylint: enable-msg=too-many-arguments 283 | 284 | def _cmd_nodata(self, card: SPI, cmd: int, response: int = 0xFF) -> int: 285 | """ 286 | Issue a command to the card with no argument. 287 | :param busio.SPI card: The locked SPI bus. 288 | :param int cmd: The command number. 289 | :param int response: The expected response, default is ``0xFF`` 290 | """ 291 | buf = self._cmdbuf 292 | buf[0] = cmd 293 | buf[1] = 0xFF 294 | 295 | card.write(buf, end=2) 296 | for _ in range(_CMD_TIMEOUT): 297 | card.readinto(buf, end=1, write_value=0xFF) 298 | if buf[0] == response: 299 | return 0 # OK 300 | return 1 # timeout 301 | 302 | def _readinto( 303 | self, card: SPI, buf: WriteableBuffer, start: int = 0, end: Optional[int] = None 304 | ) -> None: 305 | """ 306 | Read a data block into buf. 307 | :param busio.SPI card: The locked SPI bus. 308 | :param WriteableBuffer buf: The buffer to write into 309 | :param int start: The first index to write data at 310 | :param int end: The index after the last byte to write to. 311 | """ 312 | if end is None: 313 | end = len(buf) 314 | 315 | # read until start byte (0xfe) 316 | buf[start] = 0xFF # busy 317 | while buf[start] != 0xFE: 318 | card.readinto(buf, start=start, end=start + 1, write_value=0xFF) 319 | 320 | card.readinto(buf, start=start, end=end, write_value=0xFF) 321 | 322 | # read checksum and throw it away 323 | card.readinto(self._cmdbuf, end=2, write_value=0xFF) 324 | 325 | # pylint: disable-msg=too-many-arguments 326 | def _write( 327 | self, 328 | card: SPI, 329 | token: int, 330 | buf: ReadableBuffer, 331 | start: int = 0, 332 | end: Optional[int] = None, 333 | ) -> int: 334 | """ 335 | Write a data block to the card. 336 | :param busio.SPI card: The locked SPI bus. 337 | :param int token: The start token 338 | :param ReadableBuffer buf: The buffer to write from 339 | :param int start: The first index to read data from 340 | :param int end: The index after the last byte to read from. 341 | """ 342 | cmd = self._cmdbuf 343 | if end is None: 344 | end = len(buf) 345 | 346 | self._wait_for_ready(card) 347 | 348 | # send: start of block, data, checksum 349 | cmd[0] = token 350 | card.write(cmd, end=1) 351 | card.write(buf, start=start, end=end) 352 | cmd[0] = 0xFF 353 | cmd[1] = 0xFF 354 | card.write(cmd, end=2) 355 | 356 | # check the response 357 | # pylint: disable=no-else-return 358 | # Disable should be removed when refactor can be tested 359 | for _ in range(_CMD_TIMEOUT): 360 | card.readinto(cmd, end=1, write_value=0xFF) 361 | if not (cmd[0] & 0x80): 362 | if (cmd[0] & 0x1F) != 0x05: 363 | return -1 364 | else: 365 | break 366 | 367 | # wait for write to finish 368 | card.readinto(cmd, end=1, write_value=0xFF) 369 | while cmd[0] == 0: 370 | card.readinto(cmd, end=1, write_value=0xFF) 371 | 372 | return 0 # worked 373 | 374 | # pylint: enable-msg=too-many-arguments 375 | 376 | def count(self) -> int: 377 | """ 378 | Returns the total number of sectors. 379 | :return: The number of 512-byte blocks 380 | :rtype: int 381 | """ 382 | return self._sectors 383 | 384 | def readblocks(self, start_block: int, buf: WriteableBuffer) -> int: 385 | """ 386 | Read one or more blocks from the card 387 | :param int start_block: The block to start reading from 388 | :param WriteableBuffer buf: The buffer to write into. Length must be multiple of 512. 389 | """ 390 | nblocks, err = divmod(len(buf), 512) 391 | assert nblocks and not err, "Buffer length is invalid" 392 | with self._spi as card: 393 | if nblocks == 1: 394 | # CMD17: set read address for single block 395 | # We use _block_cmd to read our data so that the chip select line 396 | # isn't toggled between the command, response and data. 397 | if self._block_cmd(card, 17, start_block, 0, response_buf=buf) != 0: 398 | return 1 399 | else: 400 | # CMD18: set read address for multiple blocks 401 | if self._block_cmd(card, 18, start_block, 0) != 0: 402 | return 1 403 | offset = 0 404 | while nblocks: 405 | self._readinto(card, buf, start=offset, end=(offset + 512)) 406 | offset += 512 407 | nblocks -= 1 408 | ret = self._cmd(card, 12, 0, 0x61, wait=False) 409 | # return first status 0 or last before card ready (0xff) 410 | while ret != 0: 411 | card.readinto(self._single_byte, write_value=0xFF) 412 | if self._single_byte[0] & 0x80: 413 | return ret 414 | ret = self._single_byte[0] 415 | return 0 416 | 417 | def writeblocks(self, start_block: int, buf: ReadableBuffer) -> int: 418 | """ 419 | Write one or more blocks to the card 420 | :param int start_block: The block to start writing to 421 | :param ReadableBuffer buf: The buffer to write into. Length must be multiple of 512. 422 | """ 423 | nblocks, err = divmod(len(buf), 512) 424 | assert nblocks and not err, "Buffer length is invalid" 425 | with self._spi as card: 426 | if nblocks == 1: 427 | # CMD24: set write address for single block 428 | if self._block_cmd(card, 24, start_block, 0) != 0: 429 | return 1 430 | 431 | # send the data 432 | self._write(card, _TOKEN_DATA, buf) 433 | else: 434 | # CMD25: set write address for first block 435 | if self._block_cmd(card, 25, start_block, 0) != 0: 436 | return 1 437 | # send the data 438 | offset = 0 439 | while nblocks: 440 | self._write( 441 | card, _TOKEN_CMD25, buf, start=offset, end=(offset + 512) 442 | ) 443 | offset += 512 444 | nblocks -= 1 445 | self._cmd_nodata(card, _TOKEN_STOP_TRAN, 0x0) 446 | return 0 447 | 448 | 449 | def _calculate_crc_table() -> bytearray: 450 | """Precompute the table used in calculate_crc.""" 451 | # Code converted from https://github.com/hazelnusse/crc7/blob/master/crc7.cc by devoh747 452 | # With permission from Dale Lukas Peterson 453 | # 8/6/2019 454 | 455 | crc_table = bytearray(256) 456 | crc_poly = const(0x89) # the value of our CRC-7 polynomial 457 | 458 | # generate a table value for all 256 possible byte values 459 | for i in range(256): 460 | if i & 0x80: 461 | crc_table[i] = i ^ crc_poly 462 | else: 463 | crc_table[i] = i 464 | for _ in range(1, 8): 465 | crc_table[i] = crc_table[i] << 1 466 | if crc_table[i] & 0x80: 467 | crc_table[i] = crc_table[i] ^ crc_poly 468 | return crc_table 469 | 470 | 471 | CRC_TABLE = _calculate_crc_table() 472 | 473 | 474 | def calculate_crc(message: ReadableBuffer) -> int: 475 | """ 476 | Calculate the CRC of message[0:5], using a precomputed table in CRC_TABLE. 477 | :param bytearray message: Where each index is a byte 478 | """ 479 | 480 | crc = 0 481 | # All messages in _cmd are 5 bytes including the cmd.. The 6th byte is the crc value. 482 | for i in range(0, 5): 483 | crc = CRC_TABLE[(crc << 1) ^ message[i]] 484 | 485 | return (crc << 1) | 1 486 | -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_st7789.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/examples/HID_example_circuitpython/lib/adafruit_st7789.mpy -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/adafruit_st7789.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2019 Melissa LeBlanc-Williams for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | """ 6 | `adafruit_st7789` 7 | ==================================================== 8 | 9 | Displayio driver for ST7789 based displays. 10 | 11 | * Author(s): Melissa LeBlanc-Williams 12 | 13 | Implementation Notes 14 | -------------------- 15 | 16 | **Hardware:** 17 | 18 | * Adafruit 1.3" 240x240 Wide Angle TFT LCD Display with MicroSD - ST7789: 19 | https://www.adafruit.com/product/4313 20 | 21 | * Adafruit 1.54" 240x240 Wide Angle TFT LCD Display with MicroSD - ST7789: 22 | https://www.adafruit.com/product/3787 23 | 24 | * Adafruit 1.14" 240x135 Color TFT Display + MicroSD Card Breakout - ST7789: 25 | https://www.adafruit.com/product/4383 26 | 27 | * Adafruit Mini PiTFT 1.3" - 240x240 TFT Add-on for Raspberry Pi: 28 | https://www.adafruit.com/product/4484 29 | 30 | * Adafruit 1.3" Color TFT Bonnet for Raspberry Pi - 240x240 TFT + Joystick Add-on 31 | https://www.adafruit.com/product/4506 32 | 33 | * Adafruit Mini PiTFT - 135x240 Color TFT Add-on for Raspberry Pi: 34 | https://www.adafruit.com/product/4393 35 | 36 | **Software and Dependencies:** 37 | 38 | * Adafruit CircuitPython firmware for the supported boards: 39 | https://github.com/adafruit/circuitpython/releases 40 | 41 | """ 42 | 43 | import displayio 44 | 45 | __version__ = "0.0.0+auto.0" 46 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ST7789.git" 47 | 48 | _INIT_SEQUENCE = ( 49 | b"\x01\x80\x96" # _SWRESET and Delay 150ms 50 | b"\x11\x80\xFF" # _SLPOUT and Delay 500ms 51 | b"\x3A\x81\x55\x0A" # _COLMOD and Delay 10ms 52 | b"\x36\x01\x08" # _MADCTL 53 | b"\x21\x80\x0A" # _INVON Hack and Delay 10ms 54 | b"\x13\x80\x0A" # _NORON and Delay 10ms 55 | b"\x36\x01\xC0" # _MADCTL 56 | b"\x29\x80\xFF" # _DISPON and Delay 500ms 57 | ) 58 | 59 | # pylint: disable=too-few-public-methods 60 | class ST7789(displayio.Display): 61 | """ST7789 driver""" 62 | 63 | def __init__(self, bus: displayio.FourWire, **kwargs) -> None: 64 | super().__init__(bus, _INIT_SEQUENCE, **kwargs) 65 | -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/lib/keyboard_layout_win_uk.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Neradoc NeraOnGit@ri1.fr 2 | # SPDX-License-Identifier: MIT 3 | """ 4 | This file was automatically generated using Circuitpython_Keyboard_Layouts 5 | """ 6 | from adafruit_hid.keyboard_layout_base import KeyboardLayoutBase 7 | 8 | 9 | __version__ = "0.0.1-alpha.0" 10 | __repo__ = "https://github.com/Neradoc/Circuitpython_Keyboard_Layouts.git" 11 | 12 | 13 | class KeyboardLayout(KeyboardLayoutBase): 14 | ASCII_TO_KEYCODE = ( 15 | b'\x00' 16 | b'\x00' 17 | b'\x00' 18 | b'\x00' 19 | b'\x00' 20 | b'\x00' 21 | b'\x00' 22 | b'\x00' 23 | b'\x2a' # BACKSPACE 24 | b'\x2b' # '\t' 25 | b'\x28' # '\n' 26 | b'\x00' 27 | b'\x00' 28 | b'\x00' 29 | b'\x00' 30 | b'\x00' 31 | b'\x00' 32 | b'\x00' 33 | b'\x00' 34 | b'\x00' 35 | b'\x00' 36 | b'\x00' 37 | b'\x00' 38 | b'\x00' 39 | b'\x00' 40 | b'\x00' 41 | b'\x00' 42 | b'\x29' # ESC 43 | b'\x00' 44 | b'\x00' 45 | b'\x00' 46 | b'\x00' 47 | b'\x2c' # ' ' 48 | b'\x9e' # '!' 49 | b'\x9f' # '"' 50 | b'\x31' # '#' 51 | b'\xa1' # '$' 52 | b'\xa2' # '%' 53 | b'\xa4' # '&' 54 | b'\x34' # "'" 55 | b'\xa6' # '(' 56 | b'\xa7' # ')' 57 | b'\xa5' # '*' 58 | b'\xae' # '+' 59 | b'\x36' # ',' 60 | b'\x2d' # '-' 61 | b'\x37' # '.' 62 | b'\x38' # '/' 63 | b'\x27' # '0' 64 | b'\x1e' # '1' 65 | b'\x1f' # '2' 66 | b'\x20' # '3' 67 | b'\x21' # '4' 68 | b'\x22' # '5' 69 | b'\x23' # '6' 70 | b'\x24' # '7' 71 | b'\x25' # '8' 72 | b'\x26' # '9' 73 | b'\xb3' # ':' 74 | b'\x33' # ';' 75 | b'\xb6' # '<' 76 | b'\x2e' # '=' 77 | b'\xb7' # '>' 78 | b'\xb8' # '?' 79 | b'\xb4' # '@' 80 | b'\x84' # 'A' 81 | b'\x85' # 'B' 82 | b'\x86' # 'C' 83 | b'\x87' # 'D' 84 | b'\x88' # 'E' 85 | b'\x89' # 'F' 86 | b'\x8a' # 'G' 87 | b'\x8b' # 'H' 88 | b'\x8c' # 'I' 89 | b'\x8d' # 'J' 90 | b'\x8e' # 'K' 91 | b'\x8f' # 'L' 92 | b'\x90' # 'M' 93 | b'\x91' # 'N' 94 | b'\x92' # 'O' 95 | b'\x93' # 'P' 96 | b'\x94' # 'Q' 97 | b'\x95' # 'R' 98 | b'\x96' # 'S' 99 | b'\x97' # 'T' 100 | b'\x98' # 'U' 101 | b'\x99' # 'V' 102 | b'\x9a' # 'W' 103 | b'\x9b' # 'X' 104 | b'\x9c' # 'Y' 105 | b'\x9d' # 'Z' 106 | b'\x2f' # '[' 107 | b'\x31' # '\\' 108 | b'\x30' # ']' 109 | b'\xa3' # '^' 110 | b'\xad' # '_' 111 | b'\x35' # '`' 112 | b'\x04' # 'a' 113 | b'\x05' # 'b' 114 | b'\x06' # 'c' 115 | b'\x07' # 'd' 116 | b'\x08' # 'e' 117 | b'\x09' # 'f' 118 | b'\x0a' # 'g' 119 | b'\x0b' # 'h' 120 | b'\x0c' # 'i' 121 | b'\x0d' # 'j' 122 | b'\x0e' # 'k' 123 | b'\x0f' # 'l' 124 | b'\x10' # 'm' 125 | b'\x11' # 'n' 126 | b'\x12' # 'o' 127 | b'\x13' # 'p' 128 | b'\x14' # 'q' 129 | b'\x15' # 'r' 130 | b'\x16' # 's' 131 | b'\x17' # 't' 132 | b'\x18' # 'u' 133 | b'\x19' # 'v' 134 | b'\x1a' # 'w' 135 | b'\x1b' # 'x' 136 | b'\x1c' # 'y' 137 | b'\x1d' # 'z' 138 | b'\xaf' # '{' 139 | b'\xe4' # '|' 140 | b'\xb0' # '}' 141 | b'\xb1' # '~' 142 | b'\x00' 143 | ) 144 | NEED_ALTGR = '\\¦áéíóú€' 145 | HIGHER_ASCII = { 146 | 0xa3: 0xa0, # '£' 147 | 0x20ac: 0x21, # '€' 148 | 0xe9: 0x08, # 'é' 149 | 0xfa: 0x18, # 'ú' 150 | 0xed: 0x0c, # 'í' 151 | 0xf3: 0x12, # 'ó' 152 | 0xe1: 0x04, # 'á' 153 | 0xac: 0xb5, # '¬' 154 | 0xa6: 0x35, # '¦' 155 | } 156 | COMBINED_KEYS = { 157 | } 158 | -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/password_feeder_gmail.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Demo code to insert gmail password on Pressing power button of TV remote 3 | ''' 4 | from adafruit_hid.keyboard import Keyboard, Keycode 5 | from keyboard_layout_win_uk import KeyboardLayout 6 | from adafruit_display_text import label 7 | from PiBeam import LCD,IR,LED 8 | import usb_hid 9 | import time 10 | 11 | tft_bg_color = 0xFFFF00 # Yellow 12 | txt_color = 0x0000ff 13 | txt_font = 3 14 | 15 | tft = LCD(tft_bg_color) 16 | tft.bl() #tft.bl(False) - tft backlight off 17 | 18 | led = LED() 19 | 20 | ir = IR() 21 | 22 | tft.printf("SB COMPONENTS",txt_font,txt_color, 5, 40) 23 | tft.printf("PiBeam",txt_font,txt_color, 60, 80) 24 | 25 | def passwordFeed(): 26 | keyboard = Keyboard(usb_hid.devices) 27 | keyboard_layout = KeyboardLayout(keyboard) 28 | 29 | ''' Modify password text and/or special characters ''' 30 | time.sleep(1) 31 | keyboard_layout.write("yourPasswordText") # initial text of password 32 | time.sleep(0.1) 33 | keyboard.send(Keycode.SHIFT, Keycode.TWO) #special character typing -> @ 34 | time.sleep(0.1) 35 | keyboard.send(Keycode.SHIFT, Keycode.THREE) #special character typing -> # 36 | time.sleep(0.1) 37 | keyboard_layout.write("sbcomponents") # terminal text of password 38 | time.sleep(0.2) 39 | keyboard.send(Keycode.TAB) 40 | time.sleep(0.2) 41 | keyboard.send(Keycode.TAB) 42 | time.sleep(0.2) 43 | keyboard.send(Keycode.ENTER) 44 | time.sleep(0.3) 45 | keyboard.release_all() 46 | 47 | 48 | while True: 49 | val = ir.Read() # read for IR data incoming from IR remote 50 | if val is not None: 51 | led.on() 52 | print(val) 53 | #when power button of remote pressed, switch ON camera 54 | #change operation as per requirement 55 | if val[0] == 13 and val[1] == 245 and val[2] == 191 and val[3] == 64: #(13, 245, 191, 64) - code received for power button of remote 56 | print("Password Enter...") 57 | tft.clear(tft_bg_color) 58 | tft.printf("Password..",txt_font,txt_color, 5, 40) 59 | passwordFeed() 60 | tft.clear(tft_bg_color) 61 | tft.printf("Login",txt_font,txt_color, 5, 40)() 62 | 63 | else: 64 | led.off() 65 | time.sleep(0.2) 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /examples/HID_example_circuitpython/readme.md: -------------------------------------------------------------------------------- 1 | To try above listed codes which gives ability to use PiBeam as HID device, you have to follow below instructions, 2 | 3 | ### Step 1: Boot Firmware installation 4 | - Change PiBeam default micropython firmware with CircuitPython based boot fimware. Download Firmware from here or you can also install via Thonny IDE. 5 | - Push and hold the BOOT button and plug your PiBeam into the USB port of your computer. Release the BOOT button after your PiBeam is connected to USB port. 6 | - It will mount as a Mass Storage Device called RPI-RP2. 7 | - Drag and drop the Firmware UF2 - [PiBeam_HID_firmware](https://github.com/sbcshop/PiBeam_Software/blob/main/examples/HID_example_circuitpython/PiBeam_HID_firmware.uf2) file provided here onto the RPI-RP2 volume. Your PiBeam will reboot. You are now running CircuitPython on PiBeam. 8 | 9 | ### Step 2: Libraries Setup 10 | - Once fimware step done, proceed to add complete [lib](https://github.com/sbcshop/PiBeam_Software/tree/main/examples/HID_example_circuitpython/lib) folder having various libraries inside PiBeam. 11 | - Either copy and paste complete lib directly inside PiBeam or transfer file as shown in [step 3](https://github.com/sbcshop/PiBeam_Software/blob/main/README.md#3-how-to-move-your-script-on-pibeam) of getting started section. 12 | 13 | ### Step 3: Testing Codes 14 | - Open code which you want to try into Thonny IDE, then click on Green Run button on top left corner. 15 | - To test any code examples provided here, save it as _**code.py**_ into PiBeam's pico for standalone execution. 16 | 17 | Examples: 18 | * [Demo_CameraOn_code.py](https://github.com/sbcshop/PiBeam_Software/blob/main/examples/HID_example_circuitpython/Demo_CameraOn_code.py) - Switch on Windows PC camera when power button pressed on TV Remote. 19 | * [password_feeder_gmail](https://github.com/sbcshop/PiBeam_Software/blob/main/examples/HID_example_circuitpython/password_feeder_gmail.py): To enter password in gmail for logging with operation control from TV remote 20 | * Similar other two examples for image display on TFT with and without SD card on PiBeam. 21 | -------------------------------------------------------------------------------- /examples/PiBeam.py: -------------------------------------------------------------------------------- 1 | from machine import Timer, Pin,PWM,SPI 2 | from array import array 3 | from utime import ticks_us 4 | from utime import ticks_us, ticks_diff 5 | from machine import Pin, freq 6 | from sys import platform 7 | import time,utime 8 | import st7789 9 | 10 | import rp2 11 | 12 | class LCD: 13 | def __init__(self): 14 | self.spi = SPI(1, baudrate=40000000, sck=Pin(10), mosi=Pin(11)) 15 | 16 | def display(self): 17 | self.tft = st7789.ST7789(self.spi,135,240,reset=Pin(12, Pin.OUT),cs=Pin(9, Pin.OUT),dc=Pin(8, Pin.OUT),backlight=Pin(13, Pin.OUT),rotation=1) 18 | return self.tft 19 | 20 | _CMD_TIMEOUT = const(100) 21 | _R1_IDLE_STATE = const(1 << 0) 22 | _R1_ILLEGAL_COMMAND = const(1 << 2) 23 | _TOKEN_CMD25 = const(0xFC) 24 | _TOKEN_STOP_TRAN = const(0xFD) 25 | _TOKEN_DATA = const(0xFE) 26 | 27 | class IR_Receiver: 28 | def __init__(self): 29 | self.IR_RX = self.IR_RX() 30 | 31 | class IR_RX(): 32 | # Result/error codes 33 | # Repeat button code 34 | REPEAT = -1 35 | # Error codes 36 | BADSTART = -2 37 | BADBLOCK = -3 38 | BADREP = -4 39 | OVERRUN = -5 40 | BADDATA = -6 41 | BADADDR = -7 42 | 43 | def __init__(self,nedges, tblock, callback, *args): # Optional args for callback 44 | self._pin_rx = Pin(1, Pin.IN) 45 | self._nedges = nedges 46 | self._tblock = tblock 47 | self.callback = callback 48 | self.args = args 49 | self._errf = lambda _ : None 50 | self.verbose = False 51 | 52 | self._times = array('i', (0 for _ in range(nedges + 1))) # +1 for overrun 53 | self._pin_rx.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING)) 54 | self.edge = 0 55 | self.tim = Timer(-1) # Sofware timer 56 | self.cb = self.decode 57 | 58 | # Pin interrupt. Save time of each edge for later decode. 59 | def _cb_pin(self, line): 60 | t = ticks_us() 61 | # On overrun ignore pulses until software timer times out 62 | if self.edge <= self._nedges: # Allow 1 extra pulse to record overrun 63 | if not self.edge: # First edge received 64 | self.tim.init(period=self._tblock , mode=Timer.ONE_SHOT, callback=self.cb) 65 | self._times[self.edge] = t 66 | self.edge += 1 67 | 68 | def do_callback(self, cmd, addr, ext, thresh=0): 69 | self.edge = 0 70 | if cmd >= thresh: 71 | self.callback(cmd, addr, ext, *self.args) 72 | else: 73 | self._errf(cmd) 74 | 75 | def error_function(self, func): 76 | self._errf = func 77 | 78 | def close(self): 79 | self._pin_rx.irq(handler = None) 80 | self.tim.deinit() 81 | 82 | class IR_GET(IR_RX): 83 | def __init__(self, pin_rx, nedges=100, twait=100, display=True): 84 | self.display = display 85 | super().__init__(pin_rx, nedges, twait, lambda *_ : None) 86 | self.data = None 87 | 88 | def decode(self, _): 89 | def near(v, target): 90 | return target * 0.8 < v < target * 1.2 91 | lb = self.edge - 1 # Possible length of burst 92 | if lb < 3: 93 | return # Noise 94 | burst = [] 95 | for x in range(lb): 96 | dt = ticks_diff(self._times[x + 1], self._times[x]) 97 | if x > 0 and dt > 10000: # Reached gap between repeats 98 | break 99 | burst.append(dt) 100 | lb = len(burst) # Actual length 101 | # Duration of pulse train 24892 for RC-5 22205 for RC-6 102 | duration = ticks_diff(self._times[lb - 1], self._times[0]) 103 | 104 | if self.display: 105 | for x, e in enumerate(burst): 106 | print('{:03d} {:5d}'.format(x, e)) 107 | print() 108 | # Attempt to determine protocol 109 | ok = False # Protocol not yet found 110 | if near(burst[0], 9000) and lb == 67: 111 | print('NEC') 112 | ok = True 113 | 114 | if not ok and near(burst[0], 2400) and near(burst[1], 600): # Maybe Sony 115 | try: 116 | nbits = {25:12, 31:15, 41:20}[lb] 117 | except KeyError: 118 | pass 119 | else: 120 | ok = True 121 | print('Sony {}bit'.format(nbits)) 122 | 123 | if not ok and near(burst[0], 889): # Maybe RC-5 124 | if near(duration, 24892) and near(max(burst), 1778): 125 | print('Philps RC-5') 126 | ok = True 127 | 128 | if not ok and near(burst[0], 2666) and near(burst[1], 889): # RC-6? 129 | if near(duration, 22205) and near(burst[1], 889) and near(burst[2], 444): 130 | print('Philips RC-6 mode 0') 131 | ok = True 132 | 133 | if not ok and near(burst[0], 2000) and near(burst[1], 1000): 134 | if near(duration, 19000): 135 | print('Microsoft MCE edition protocol.') 136 | # Constant duration, variable burst length, presumably bi-phase 137 | print('Protocol start {} {} Burst length {} duration {}'.format(burst[0], burst[1], lb, duration)) 138 | ok = True 139 | 140 | if not ok and near(burst[0], 4500) and near(burst[1], 4500) and lb == 67: # Samsung 141 | print('Samsung') 142 | ok = True 143 | 144 | if not ok and near(burst[0], 3500) and near(burst[1], 1680): # Panasonic? 145 | print('Unsupported protocol. Panasonic?') 146 | ok = True 147 | 148 | if not ok: 149 | print('Unknown protocol start {} {} Burst length {} duration {}'.format(burst[0], burst[1], lb, duration)) 150 | 151 | print() 152 | self.data = burst 153 | # Set up for new data burst. Run null callback 154 | self.do_callback(0, 0, 0) 155 | 156 | def acquire(self): 157 | while self.data is None: 158 | sleep_ms(5) 159 | self.close() 160 | return self.data 161 | 162 | ######################## MEC ###################################### 163 | class MCE(IR_RX): 164 | init_cs = 4 165 | def __init__(self,callback, *args): 166 | # Block lasts ~19ms and has <= 34 edges 167 | super().__init__(34, 25, callback, *args) 168 | 169 | def decode(self, _): 170 | def check(v): 171 | if self.init_cs == -1: 172 | return True 173 | csum = v >> 12 174 | cs = self.init_cs 175 | for _ in range(12): 176 | if v & 1: 177 | cs += 1 178 | v >>= 1 179 | return cs == csum 180 | 181 | try: 182 | t0 = ticks_diff(self._times[1], self._times[0]) # 2000μs mark 183 | t1 = ticks_diff(self._times[2], self._times[1]) # 1000μs space 184 | if not ((1800 < t0 < 2200) and (800 < t1 < 1200)): 185 | raise RuntimeError(self.BADSTART) 186 | nedges = self.edge # No. of edges detected 187 | if not 14 <= nedges <= 34: 188 | raise RuntimeError(self.OVERRUN if nedges > 28 else self.BADSTART) 189 | # Manchester decode 190 | mask = 1 191 | bit = 1 192 | v = 0 193 | x = 2 194 | for _ in range(16): 195 | # -1 convert count to index, -1 because we look ahead 196 | if x > nedges - 2: 197 | raise RuntimeError(self.BADBLOCK) 198 | # width is 500/1000 nominal 199 | width = ticks_diff(self._times[x + 1], self._times[x]) 200 | if not 250 < width < 1350: 201 | self.verbose and print('Bad block 3 Width', width, 'x', x) 202 | raise RuntimeError(self.BADBLOCK) 203 | short = int(width < 750) 204 | bit ^= short ^ 1 205 | v |= mask if bit else 0 206 | mask <<= 1 207 | x += 1 + short 208 | 209 | self.verbose and print(bin(v)) 210 | if not check(v): 211 | raise RuntimeError(self.BADDATA) 212 | val = (v >> 6) & 0x3f 213 | addr = v & 0xf # Constant for all buttons on my remote 214 | ctrl = (v >> 4) & 3 215 | 216 | except RuntimeError as e: 217 | val, addr, ctrl = e.args[0], 0, 0 218 | # Set up for new data burst and run user callback/error function 219 | self.do_callback(val, addr, ctrl) 220 | 221 | ######################## NEC ###################################### 222 | class NEC(IR_RX): 223 | def __init__(self, extended, samsung, callback, *args): 224 | # Block lasts <= 80ms (extended mode) and has 68 edges 225 | super().__init__(68, 80, callback, *args) 226 | self._extended = extended 227 | self._addr = 0 228 | self._leader = 2500 if samsung else 4000 # 4.5ms for Samsung else 9ms 229 | 230 | def decode(self, _): 231 | try: 232 | if self.edge > 68: 233 | raise RuntimeError(self.OVERRUN) 234 | width = ticks_diff(self._times[1], self._times[0]) 235 | if width < self._leader: # 9ms leading mark for all valid data 236 | raise RuntimeError(self.BADSTART) 237 | width = ticks_diff(self._times[2], self._times[1]) 238 | if width > 3000: # 4.5ms space for normal data 239 | if self.edge < 68: # Haven't received the correct number of edges 240 | raise RuntimeError(self.BADBLOCK) 241 | # Time spaces only (marks are always 562.5µs) 242 | # Space is 1.6875ms (1) or 562.5µs (0) 243 | # Skip last bit which is always 1 244 | val = 0 245 | for edge in range(3, 68 - 2, 2): 246 | val >>= 1 247 | if ticks_diff(self._times[edge + 1], self._times[edge]) > 1120: 248 | val |= 0x80000000 249 | elif width > 1700: # 2.5ms space for a repeat code. Should have exactly 4 edges. 250 | raise RuntimeError(self.REPEAT if self.edge == 4 else self.BADREP) # Treat REPEAT as error. 251 | else: 252 | raise RuntimeError(self.BADSTART) 253 | addr = val & 0xff # 8 bit addr 254 | cmd = (val >> 16) & 0xff 255 | if cmd != (val >> 24) ^ 0xff: 256 | raise RuntimeError(self.BADDATA) 257 | if addr != ((val >> 8) ^ 0xff) & 0xff: # 8 bit addr doesn't match check 258 | if not self._extended: 259 | raise RuntimeError(self.BADADDR) 260 | addr |= val & 0xff00 # pass assumed 16 bit address to callback 261 | self._addr = addr 262 | except RuntimeError as e: 263 | cmd = e.args[0] 264 | addr = self._addr if cmd == self.REPEAT else 0 # REPEAT uses last address 265 | # Set up for new data burst and run user callback 266 | self.do_callback(cmd, addr, 0, self.REPEAT) 267 | 268 | class NEC_8(NEC): 269 | def __init__(self,callback, *args): 270 | super().__init__(False, False, callback, *args) 271 | 272 | class NEC_16(NEC): 273 | def __init__(self, callback, *args): 274 | super().__init__(True, False, callback, *args) 275 | 276 | class SAMSUNG(NEC): 277 | def __init__(self,callback, *args): 278 | super().__init__(True, True, callback, *args) 279 | 280 | 281 | ######################### PHILIPS RC ########################3 282 | class RC5_IR(IR_RX): 283 | def __init__(self,callback, *args): 284 | # Block lasts <= 30ms and has <= 28 edges 285 | super().__init__(28, 30, callback, *args) 286 | 287 | def decode(self, _): 288 | try: 289 | nedges = self.edge # No. of edges detected 290 | if not 14 <= nedges <= 28: 291 | raise RuntimeError(self.OVERRUN if nedges > 28 else self.BADSTART) 292 | # Regenerate bitstream 293 | bits = 1 294 | bit = 1 295 | v = 1 # 14 bit bitstream, MSB always 1 296 | x = 0 297 | while bits < 14: 298 | # -1 convert count to index, -1 because we look ahead 299 | if x > nedges - 2: 300 | print('Bad block 1 edges', nedges, 'x', x) 301 | raise RuntimeError(self.BADBLOCK) 302 | # width is 889/1778 nominal 303 | width = ticks_diff(self._times[x + 1], self._times[x]) 304 | if not 500 < width < 2100: 305 | self.verbose and print('Bad block 3 Width', width, 'x', x) 306 | raise RuntimeError(self.BADBLOCK) 307 | short = width < 1334 308 | if not short: 309 | bit ^= 1 310 | v <<= 1 311 | v |= bit 312 | bits += 1 313 | x += 1 + int(short) 314 | self.verbose and print(bin(v)) 315 | # Split into fields (val, addr, ctrl) 316 | val = (v & 0x3f) | (0 if ((v >> 12) & 1) else 0x40) # Correct the polarity of S2 317 | addr = (v >> 6) & 0x1f 318 | ctrl = (v >> 11) & 1 319 | 320 | except RuntimeError as e: 321 | val, addr, ctrl = e.args[0], 0, 0 322 | # Set up for new data burst and run user callback 323 | self.do_callback(val, addr, ctrl) 324 | 325 | 326 | class RC6_M0(IR_RX): 327 | # Even on Pyboard D the 444μs nominal pulses can be recorded as up to 705μs 328 | # Scope shows 360-520 μs (-84μs +76μs relative to nominal) 329 | # Header nominal 2666, 889, 444, 889, 444, 444, 444, 444 carrier ON at end 330 | hdr = ((1800, 4000), (593, 1333), (222, 750), (593, 1333), (222, 750), (222, 750), (222, 750), (222, 750)) 331 | def __init__(self,callback, *args): 332 | # Block lasts 23ms nominal and has <=44 edges 333 | super().__init__(44, 30, callback, *args) 334 | 335 | def decode(self, _): 336 | try: 337 | nedges = self.edge # No. of edges detected 338 | if not 22 <= nedges <= 44: 339 | raise RuntimeError(self.OVERRUN if nedges > 28 else self.BADSTART) 340 | for x, lims in enumerate(self.hdr): 341 | width = ticks_diff(self._times[x + 1], self._times[x]) 342 | if not (lims[0] < width < lims[1]): 343 | self.verbose and print('Bad start', x, width, lims) 344 | raise RuntimeError(self.BADSTART) 345 | x += 1 346 | width = ticks_diff(self._times[x + 1], self._times[x]) 347 | # 2nd bit of last 0 is 444μs (0) or 1333μs (1) 348 | if not 222 < width < 1555: 349 | self.verbose and print('Bad block 1 Width', width, 'x', x) 350 | raise RuntimeError(self.BADBLOCK) 351 | short = width < 889 352 | v = int(not short) 353 | bit = v 354 | bits = 1 # Bits decoded 355 | x += 1 + int(short) 356 | width = ticks_diff(self._times[x + 1], self._times[x]) 357 | if not 222 < width < 1555: 358 | self.verbose and print('Bad block 2 Width', width, 'x', x) 359 | raise RuntimeError(self.BADBLOCK) 360 | short = width < 1111 361 | if not short: 362 | bit ^= 1 363 | x += 1 + int(short) # If it's short, we know width of next 364 | v <<= 1 365 | v |= bit # MSB of result 366 | bits += 1 367 | # Decode bitstream 368 | while bits < 17: 369 | # -1 convert count to index, -1 because we look ahead 370 | if x > nedges - 2: 371 | raise RuntimeError(self.BADBLOCK) 372 | # width is 444/889 nominal 373 | width = ticks_diff(self._times[x + 1], self._times[x]) 374 | if not 222 < width < 1111: 375 | self.verbose and print('Bad block 3 Width', width, 'x', x) 376 | raise RuntimeError(self.BADBLOCK) 377 | short = width < 666 378 | if not short: 379 | bit ^= 1 380 | v <<= 1 381 | v |= bit 382 | bits += 1 383 | x += 1 + int(short) 384 | 385 | if self.verbose: 386 | ss = '20-bit format {:020b} x={} nedges={} bits={}' 387 | print(ss.format(v, x, nedges, bits)) 388 | 389 | val = v & 0xff 390 | addr = (v >> 8) & 0xff 391 | ctrl = (v >> 16) & 1 392 | except RuntimeError as e: 393 | val, addr, ctrl = e.args[0], 0, 0 394 | # Set up for new data burst and run user callback 395 | self.do_callback(val, addr, ctrl) 396 | #################################################################### 397 | 398 | ######################## SONY ###################################### 399 | class SONY(IR_RX): # Abstract base class 400 | def __init__(self,bits, callback, *args): 401 | # 20 bit block has 42 edges and lasts <= 39ms nominal. Add 4ms to time 402 | # for tolerances except in 20 bit case where timing is tight with a 403 | # repeat period of 45ms. 404 | t = int(3 + bits * 1.8) + (1 if bits == 20 else 4) 405 | super().__init__(2 + bits * 2, t, callback, *args) 406 | self._addr = 0 407 | self._bits = 20 408 | 409 | def decode(self, _): 410 | try: 411 | nedges = self.edge # No. of edges detected 412 | self.verbose and print('nedges', nedges) 413 | if nedges > 42: 414 | raise RuntimeError(self.OVERRUN) 415 | bits = (nedges - 2) // 2 416 | if nedges not in (26, 32, 42) or bits > self._bits: 417 | raise RuntimeError(self.BADBLOCK) 418 | self.verbose and print('SIRC {}bit'.format(bits)) 419 | width = ticks_diff(self._times[1], self._times[0]) 420 | if not 1800 < width < 3000: # 2.4ms leading mark for all valid data 421 | raise RuntimeError(self.BADSTART) 422 | width = ticks_diff(self._times[2], self._times[1]) 423 | if not 350 < width < 1000: # 600μs space 424 | raise RuntimeError(self.BADSTART) 425 | 426 | val = 0 # Data received, LSB 1st 427 | x = 2 428 | bit = 1 429 | while x <= nedges - 2: 430 | if ticks_diff(self._times[x + 1], self._times[x]) > 900: 431 | val |= bit 432 | bit <<= 1 433 | x += 2 434 | cmd = val & 0x7f # 7 bit command 435 | val >>= 7 436 | if nedges < 42: 437 | addr = val & 0xff # 5 or 8 bit addr 438 | val = 0 439 | else: 440 | addr = val & 0x1f # 5 bit addr 441 | val >>= 5 # 8 bit extended 442 | except RuntimeError as e: 443 | cmd = e.args[0] 444 | addr = 0 445 | val = 0 446 | self.do_callback(cmd, addr, val) 447 | 448 | class SONY_12(SONY): 449 | def __init__(self,callback, *args): 450 | super().__init__(12, callback, *args) 451 | 452 | class SONY_15(SONY): 453 | def __init__(self,callback, *args): 454 | super().__init__(15, callback, *args) 455 | 456 | class SONY_20(SONY): 457 | def __init__(self,callback, *args): 458 | super().__init__(20, callback, *args) 459 | 460 | 461 | 462 | @rp2.asm_pio(set_init=rp2.PIO.OUT_LOW, autopull=True, pull_thresh=32) 463 | def pulsetrain(): 464 | wrap_target() 465 | out(x, 32) # No of 1MHz ticks. Block if FIFO MT at end. 466 | irq(rel(0)) 467 | set(pins, 1) # Set pin high 468 | label('loop') 469 | jmp(x_dec,'loop') 470 | irq(rel(0)) 471 | set(pins, 0) # Set pin low 472 | out(y, 32) # Low time. 473 | label('loop_lo') 474 | jmp(y_dec,'loop_lo') 475 | wrap() 476 | 477 | @rp2.asm_pio(autopull=True, pull_thresh=32) 478 | def irqtrain(): 479 | wrap_target() 480 | out(x, 32) # No of 1MHz ticks. Block if FIFO MT at end. 481 | irq(rel(0)) 482 | label('loop') 483 | jmp(x_dec,'loop') 484 | wrap() 485 | 486 | class DummyPWM: 487 | def duty_u16(self, _): 488 | pass 489 | 490 | class RP2_RMT: 491 | 492 | def __init__(self, pin_pulse=None, carrier=None, sm_no=0, sm_freq=1_000_000): 493 | if carrier is None: 494 | self.pwm = DummyPWM() 495 | self.duty = (0, 0) 496 | else: 497 | pin_car, freq, duty = carrier 498 | self.pwm = PWM(pin_car) # Set up PWM with carrier off. 499 | self.pwm.freq(freq) 500 | self.pwm.duty_u16(0) 501 | self.duty = (int(0xffff * duty // 100), 0) 502 | if pin_pulse is None: 503 | self.sm = rp2.StateMachine(sm_no, irqtrain, freq=sm_freq) 504 | else: 505 | self.sm = rp2.StateMachine(sm_no, pulsetrain, freq=sm_freq, set_base=pin_pulse) 506 | self.apt = 0 # Array index 507 | self.arr = None # Array 508 | self.ict = None # Current IRQ count 509 | self.icm = 0 # End IRQ count 510 | self.reps = 0 # 0 == forever n == no. of reps 511 | rp2.PIO(0).irq(self._cb) 512 | 513 | # IRQ callback. Because of FIFO IRQ's keep arriving after STOP. 514 | def _cb(self, pio): 515 | self.pwm.duty_u16(self.duty[self.ict & 1]) 516 | self.ict += 1 517 | if d := self.arr[self.apt]: # If data available feed FIFO 518 | self.sm.put(d) 519 | self.apt += 1 520 | else: 521 | if r := self.reps != 1: # All done if reps == 1 522 | if r: # 0 == run forever 523 | self.reps -= 1 524 | self.sm.put(self.arr[0]) 525 | self.apt = 1 # Set pointer and count to state 526 | self.ict = 1 # after 1st IRQ 527 | 528 | # Arg is an array of times in μs terminated by 0. 529 | def send(self, ar, reps=1, check=True): 530 | self.sm.active(0) 531 | self.reps = reps 532 | ar[-1] = 0 # Ensure at least one STOP 533 | for x, d in enumerate(ar): # Find 1st STOP 534 | if d == 0: 535 | break 536 | if check: 537 | # Pulse train must end with a space otherwise we leave carrier on. 538 | # So, if it ends with a mark, append a space. Note __init__.py 539 | # ensures that there is room in array. 540 | if (x & 1): 541 | ar[x] = 1 # space. Duration doesn't matter. 542 | x += 1 543 | ar[x] = 0 # STOP 544 | self.icm = x # index of 1st STOP 545 | mv = memoryview(ar) 546 | n = min(x, 4) # Fill FIFO if there are enough data points. 547 | self.sm.put(mv[0 : n]) 548 | self.arr = ar # Initial conditions for ISR 549 | self.apt = n # Point to next data value 550 | self.ict = 0 # IRQ count 551 | self.sm.active(1) 552 | 553 | def busy(self): 554 | if self.ict is None: 555 | return False # Just instantiated 556 | return self.ict < self.icm 557 | 558 | def cancel(self): 559 | self.reps = 1 560 | 561 | 562 | class IR_Transmitter: 563 | # Shared by NEC 564 | STOP = const(0) # End of data 565 | 566 | # IR abstract base class. Array holds periods in μs between toggling 36/38KHz 567 | # carrier on or off. Physical transmission occurs in an ISR context controlled 568 | # by timer 2 and timer 5. See TRANSMITTER.md for details of operation. 569 | def __init__(self): 570 | ## instantiating the 'Inner' class 571 | self.IR = self.IR() 572 | 573 | class IR_TX: 574 | _active_high = True # Hardware turns IRLED on if pin goes high. 575 | _space = 0 # Duty ratio that causes IRLED to be off 576 | timeit = False # Print timing info 577 | 578 | @classmethod 579 | def active_low(cls): 580 | if ESP32: 581 | raise ValueError('Cannot set active low on ESP32') 582 | cls._active_high = False 583 | cls._space = 100 584 | 585 | def __init__(self,cfreq, asize, duty, verbose): 586 | self.pin_tx = Pin(0,Pin.OUT, value = 1) 587 | self._rmt = RP2_RMT(pin_pulse=None, carrier=(self.pin_tx, cfreq, duty)) # 1μs resolution 588 | asize += 1 # Allow for possible extra space pulse 589 | 590 | self._tcb = self._cb # Pre-allocate 591 | self._arr = array('H', 0 for _ in range(asize)) # on/off times (μs) 592 | self._mva = memoryview(self._arr) 593 | # Subclass interface 594 | self.verbose = verbose 595 | self.carrier = False # Notional carrier state while encoding biphase 596 | self.aptr = 0 # Index into array 597 | 598 | def _cb(self, t): # T5 callback, generate a carrier mark or space 599 | t.deinit() 600 | p = self.aptr 601 | v = self._arr[p] 602 | if v == STOP: 603 | self._ch.pulse_width_percent(self._space) # Turn off IR LED. 604 | return 605 | self._ch.pulse_width_percent(self._space if p & 1 else self._duty) 606 | self._tim.init(prescaler=84, period=v, callback=self._tcb) 607 | self.aptr += 1 608 | 609 | # Public interface 610 | # Before populating array, zero pointer, set notional carrier state (off). 611 | def transmit(self, addr, data, toggle=0, validate=False): # NEC: toggle is unused 612 | t = ticks_us() 613 | if validate: 614 | if addr > self.valid[0] or addr < 0: 615 | raise ValueError('Address out of range', addr) 616 | if data > self.valid[1] or data < 0: 617 | raise ValueError('Data out of range', data) 618 | if toggle > self.valid[2] or toggle < 0: 619 | raise ValueError('Toggle out of range', toggle) 620 | self.aptr = 0 # Inital conditions for tx: index into array 621 | self.carrier = False 622 | self.tx(addr, data, toggle) # Subclass populates ._arr 623 | self.trigger() # Initiate transmission 624 | if self.timeit: 625 | dt = ticks_diff(ticks_us(), t) 626 | print('Time = {}μs'.format(dt)) 627 | 628 | # Subclass interface 629 | def trigger(self): # Used by NEC to initiate a repeat frame 630 | self.append(STOP) 631 | self._rmt.send(self._arr) 632 | 633 | 634 | def append(self, *times): # Append one or more time peiods to ._arr 635 | for t in times: 636 | self._arr[self.aptr] = t 637 | self.aptr += 1 638 | self.carrier = not self.carrier # Keep track of carrier state 639 | self.verbose and print('append', t, 'carrier', self.carrier) 640 | 641 | def add(self, t): # Increase last time value (for biphase) 642 | assert t > 0 643 | self.verbose and print('add', t) 644 | # .carrier unaffected 645 | self._arr[self.aptr - 1] += t 646 | 647 | 648 | # Given an iterable (e.g. list or tuple) of times, emit it as an IR stream. 649 | class Player(IR_TX): 650 | 651 | def __init__(self,freq=38000, verbose=False): # NEC specifies 38KHz 652 | super().__init__(freq, 68, 33, verbose) # Measured duty ratio 33% 653 | 654 | def play(self, lst): 655 | for x, t in enumerate(lst): 656 | self._arr[x] = t 657 | self.aptr = x + 1 658 | self.trigger() 659 | 660 | _TBIT = const(500) # Time (μs) for pulse of carrier 661 | 662 | 663 | class MCE(IR_TX): 664 | valid = (0xf, 0x3f, 3) # Max addr, data, toggle 665 | init_cs = 4 # http://www.hifi-remote.com/johnsfine/DecodeIR.html#OrtekMCE says 3 666 | 667 | def __init__(self,freq=38000, verbose=False): 668 | super().__init__(freq, 34, 30, verbose) 669 | 670 | def tx(self, addr, data, toggle): 671 | def checksum(v): 672 | cs = self.init_cs 673 | for _ in range(12): 674 | if v & 1: 675 | cs += 1 676 | v >>= 1 677 | return cs 678 | 679 | self.append(2000, 1000, _TBIT) 680 | d = ((data & 0x3f) << 6) | (addr & 0xf) | ((toggle & 3) << 4) 681 | d |= checksum(d) << 12 682 | self.verbose and print(bin(d)) 683 | 684 | mask = 1 685 | while mask < 0x10000: 686 | bit = bool(d & mask) 687 | if bit ^ self.carrier: 688 | self.add(_TBIT) 689 | self.append(_TBIT) 690 | else: 691 | self.append(_TBIT, _TBIT) 692 | mask <<= 1 693 | 694 | _TBURST = const(563) 695 | _T_ONE = const(1687) 696 | 697 | class NEC(IR_TX): 698 | valid = (0xffff, 0xff, 0) # Max addr, data, toggle 699 | samsung = False 700 | 701 | def __init__(self,freq=38000, verbose=False): # NEC specifies 38KHz also Samsung 702 | super().__init__(freq, 68, 33, verbose) # Measured duty ratio 33% 703 | 704 | def _bit(self, b): 705 | self.append(_TBURST, _T_ONE if b else _TBURST) 706 | 707 | def tx(self, addr, data, _): # Ignore toggle 708 | if self.samsung: 709 | self.append(4500, 4500) 710 | else: 711 | self.append(9000, 4500) 712 | if addr < 256: # Short address: append complement 713 | if self.samsung: 714 | addr |= addr << 8 715 | else: 716 | addr |= ((addr ^ 0xff) << 8) 717 | for _ in range(16): 718 | self._bit(addr & 1) 719 | addr >>= 1 720 | data |= ((data ^ 0xff) << 8) 721 | for _ in range(16): 722 | self._bit(data & 1) 723 | data >>= 1 724 | self.append(_TBURST) 725 | 726 | def repeat(self): 727 | self.aptr = 0 728 | self.append(9000, 2250, _TBURST) 729 | self.trigger() # Initiate physical transmission. 730 | 731 | # Philips RC5 protocol 732 | _T_RC5 = const(889) # Time for pulse of carrier 733 | 734 | 735 | class RC5(IR_TX): 736 | valid = (0x1f, 0x7f, 1) # Max addr, data, toggle 737 | 738 | def __init__(self,freq=36000, verbose=False): 739 | super().__init__( freq, 28, 30, verbose) 740 | 741 | def tx(self, addr, data, toggle): # Fix RC5X S2 bit polarity 742 | d = (data & 0x3f) | ((addr & 0x1f) << 6) | (((data & 0x40) ^ 0x40) << 6) | ((toggle & 1) << 11) 743 | self.verbose and print(bin(d)) 744 | mask = 0x2000 745 | while mask: 746 | if mask == 0x2000: 747 | self.append(_T_RC5) 748 | else: 749 | bit = bool(d & mask) 750 | if bit ^ self.carrier: 751 | self.add(_T_RC5) 752 | self.append(_T_RC5) 753 | else: 754 | self.append(_T_RC5, _T_RC5) 755 | mask >>= 1 756 | 757 | # Philips RC6 mode 0 protocol 758 | _T_RC6 = const(444) 759 | _T2_RC6 = const(889) 760 | 761 | class RC6_M0(IR_TX): 762 | valid = (0xff, 0xff, 1) # Max addr, data, toggle 763 | 764 | def __init__(self,freq=36000, verbose=False): 765 | super().__init__(freq, 44, 30, verbose) 766 | 767 | def tx(self, addr, data, toggle): 768 | # leader, 1, 0, 0, 0 769 | self.append(2666, _T2_RC6, _T_RC6, _T2_RC6, _T_RC6, _T_RC6, _T_RC6, _T_RC6, _T_RC6) 770 | # Append a single bit of twice duration 771 | if toggle: 772 | self.add(_T2_RC6) 773 | self.append(_T2_RC6) 774 | else: 775 | self.append(_T2_RC6, _T2_RC6) 776 | d = (data & 0xff) | ((addr & 0xff) << 8) 777 | mask = 0x8000 778 | self.verbose and print('toggle', toggle, self.carrier, bool(d & mask)) 779 | while mask: 780 | bit = bool(d & mask) 781 | if bit ^ self.carrier: 782 | self.append(_T_RC6, _T_RC6) 783 | else: 784 | self.add(_T_RC6) 785 | self.append(_T_RC6) 786 | mask >>= 1 787 | 788 | class SONY_1(IR_TX): 789 | 790 | def __init__(self,bits, freq, verbose): 791 | super().__init__(freq, 3 + bits * 2, 30, verbose) 792 | if bits not in (12, 15, 20): 793 | raise ValueError('bits must be 12, 15 or 20.') 794 | self.bits = bits 795 | 796 | def tx(self, addr, data, ext): 797 | self.append(2400, 600) 798 | bits = self.bits 799 | v = data & 0x7f 800 | if bits == 12: 801 | v |= (addr & 0x1f) << 7 802 | elif bits == 15: 803 | v |= (addr & 0xff) << 7 804 | else: 805 | v |= (addr & 0x1f) << 7 806 | v |= (ext & 0xff) << 12 807 | for _ in range(bits): 808 | self.append(1200 if v & 1 else 600, 600) 809 | v >>= 1 810 | 811 | # Sony specifies 40KHz 812 | class SONY_12(SONY_1): 813 | valid = (0x1f, 0x7f, 0) # Max addr, data, toggle 814 | def __init__(self,freq=40000, verbose=False): 815 | super().__init__( 12, freq, verbose) 816 | 817 | class SONY_15(SONY_1): 818 | valid = (0xff, 0x7f, 0) # Max addr, data, toggle 819 | def __init__(self,freq=40000, verbose=False): 820 | super().__init__(15, freq, verbose) 821 | 822 | class SONY_20(SONY_1): 823 | valid = (0x1f, 0x7f, 0xff) # Max addr, data, toggle 824 | def __init__(self,freq=40000, verbose=False): 825 | super().__init__(0, freq, verbose) 826 | 827 | 828 | class BUTTON(): 829 | def __init__(self, button_pin_number): 830 | """Initialize BUTTON. 831 | Args: 832 | button_pin_number (int): 1, 2, 3 for onboard Buttons, 833 | and pass GPIOs number for interfacing external buttons 834 | """ 835 | if button_pin_number == 1: 836 | self.button_pin = Pin(7, Pin.IN, Pin.PULL_UP) #input mode setup for read operation 837 | elif button_pin_number == 2: 838 | self.button_pin = Pin(28, Pin.IN, Pin.PULL_UP) 839 | elif button_pin_number == 3: 840 | self.button_pin = Pin(20, Pin.IN,Pin.PULL_UP) 841 | else : 842 | self.button_pin = Pin(button_pin_number, Pin.IN) 843 | 844 | def read(self): 845 | """ provides button status value -> 0 or 1 846 | """ 847 | return self.button_pin.value() 848 | 849 | class LED: 850 | def __init__(self): 851 | self.led_pin = Pin(25, Pin.OUT) 852 | 853 | def on(self): 854 | self.led_pin.value(1) 855 | 856 | def off(self): 857 | self.led_pin.value(0) 858 | 859 | 860 | class SDCard: 861 | def __init__(self): 862 | spi=SPI(0,sck=Pin(18),mosi=Pin(19),miso=Pin(16)) 863 | cs = Pin(17) 864 | self.spi = spi 865 | self.cs = cs 866 | 867 | self.cmdbuf = bytearray(6) 868 | self.dummybuf = bytearray(512) 869 | self.tokenbuf = bytearray(1) 870 | for i in range(512): 871 | self.dummybuf[i] = 0xFF 872 | self.dummybuf_memoryview = memoryview(self.dummybuf) 873 | # initialise the card 874 | self.init_card() 875 | 876 | def init_spi(self, baudrate): 877 | try: 878 | master = self.spi.MASTER 879 | except AttributeError: 880 | # on ESP8266 881 | self.spi.init(baudrate=baudrate, phase=0, polarity=0) 882 | else: 883 | # on pyboard 884 | self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) 885 | 886 | def init_card(self): 887 | # init CS pin 888 | self.cs.init(self.cs.OUT, value=1) 889 | 890 | # init SPI bus; use low data rate for initialisation 891 | self.init_spi(100000) 892 | 893 | # clock card at least 100 cycles with cs high 894 | for i in range(16): 895 | self.spi.write(b"\xff") 896 | 897 | # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) 898 | for _ in range(5): 899 | if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: 900 | break 901 | else: 902 | raise OSError("no SD card") 903 | 904 | # CMD8: determine card version 905 | r = self.cmd(8, 0x01AA, 0x87, 4) 906 | if r == _R1_IDLE_STATE: 907 | self.init_card_v2() 908 | elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): 909 | self.init_card_v1() 910 | else: 911 | raise OSError("couldn't determine SD card version") 912 | 913 | # get the number of sectors 914 | # CMD9: response R2 (R1 byte + 16-byte block read) 915 | if self.cmd(9, 0, 0, 0, False) != 0: 916 | raise OSError("no response from SD card") 917 | csd = bytearray(16) 918 | self.readinto(csd) 919 | if csd[0] & 0xC0 == 0x40: # CSD version 2.0 920 | self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 921 | elif csd[0] & 0xC0 == 0x00: # CSD version 1.0 (old, <=2GB) 922 | c_size = csd[6] & 0b11 | csd[7] << 2 | (csd[8] & 0b11000000) << 4 923 | c_size_mult = ((csd[9] & 0b11) << 1) | csd[10] >> 7 924 | self.sectors = (c_size + 1) * (2 ** (c_size_mult + 2)) 925 | else: 926 | raise OSError("SD card CSD format not supported") 927 | # print('sectors', self.sectors) 928 | 929 | # CMD16: set block length to 512 bytes 930 | if self.cmd(16, 512, 0) != 0: 931 | raise OSError("can't set 512 block size") 932 | 933 | # set to high data rate now that it's initialised 934 | self.init_spi(1320000) 935 | 936 | def init_card_v1(self): 937 | for i in range(_CMD_TIMEOUT): 938 | self.cmd(55, 0, 0) 939 | if self.cmd(41, 0, 0) == 0: 940 | self.cdv = 512 941 | # print("[SDCard] v1 card") 942 | return 943 | raise OSError("timeout waiting for v1 card") 944 | 945 | def init_card_v2(self): 946 | for i in range(_CMD_TIMEOUT): 947 | time.sleep_ms(50) 948 | self.cmd(58, 0, 0, 4) 949 | self.cmd(55, 0, 0) 950 | if self.cmd(41, 0x40000000, 0) == 0: 951 | self.cmd(58, 0, 0, 4) 952 | self.cdv = 1 953 | # print("[SDCard] v2 card") 954 | return 955 | raise OSError("timeout waiting for v2 card") 956 | 957 | def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): 958 | self.cs(0) 959 | 960 | # create and send the command 961 | buf = self.cmdbuf 962 | buf[0] = 0x40 | cmd 963 | buf[1] = arg >> 24 964 | buf[2] = arg >> 16 965 | buf[3] = arg >> 8 966 | buf[4] = arg 967 | buf[5] = crc 968 | self.spi.write(buf) 969 | 970 | if skip1: 971 | self.spi.readinto(self.tokenbuf, 0xFF) 972 | 973 | # wait for the response (response[7] == 0) 974 | for i in range(_CMD_TIMEOUT): 975 | self.spi.readinto(self.tokenbuf, 0xFF) 976 | response = self.tokenbuf[0] 977 | if not (response & 0x80): 978 | # this could be a big-endian integer that we are getting here 979 | for j in range(final): 980 | self.spi.write(b"\xff") 981 | if release: 982 | self.cs(1) 983 | self.spi.write(b"\xff") 984 | return response 985 | 986 | # timeout 987 | self.cs(1) 988 | self.spi.write(b"\xff") 989 | return -1 990 | 991 | def readinto(self, buf): 992 | self.cs(0) 993 | 994 | # read until start byte (0xff) 995 | for i in range(_CMD_TIMEOUT): 996 | self.spi.readinto(self.tokenbuf, 0xFF) 997 | if self.tokenbuf[0] == _TOKEN_DATA: 998 | break 999 | time.sleep_ms(1) 1000 | else: 1001 | self.cs(1) 1002 | raise OSError("timeout waiting for response") 1003 | 1004 | # read data 1005 | mv = self.dummybuf_memoryview 1006 | if len(buf) != len(mv): 1007 | mv = mv[: len(buf)] 1008 | self.spi.write_readinto(mv, buf) 1009 | 1010 | # read checksum 1011 | self.spi.write(b"\xff") 1012 | self.spi.write(b"\xff") 1013 | 1014 | self.cs(1) 1015 | self.spi.write(b"\xff") 1016 | 1017 | def write(self, token, buf): 1018 | self.cs(0) 1019 | 1020 | # send: start of block, data, checksum 1021 | self.spi.read(1, token) 1022 | self.spi.write(buf) 1023 | self.spi.write(b"\xff") 1024 | self.spi.write(b"\xff") 1025 | 1026 | # check the response 1027 | if (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05: 1028 | self.cs(1) 1029 | self.spi.write(b"\xff") 1030 | return 1031 | 1032 | # wait for write to finish 1033 | while self.spi.read(1, 0xFF)[0] == 0: 1034 | pass 1035 | 1036 | self.cs(1) 1037 | self.spi.write(b"\xff") 1038 | 1039 | def write_token(self, token): 1040 | self.cs(0) 1041 | self.spi.read(1, token) 1042 | self.spi.write(b"\xff") 1043 | # wait for write to finish 1044 | while self.spi.read(1, 0xFF)[0] == 0x00: 1045 | pass 1046 | 1047 | self.cs(1) 1048 | self.spi.write(b"\xff") 1049 | 1050 | def readblocks(self, block_num, buf): 1051 | nblocks = len(buf) // 512 1052 | assert nblocks and not len(buf) % 512, "Buffer length is invalid" 1053 | if nblocks == 1: 1054 | # CMD17: set read address for single block 1055 | if self.cmd(17, block_num * self.cdv, 0, release=False) != 0: 1056 | # release the card 1057 | self.cs(1) 1058 | raise OSError(5) # EIO 1059 | # receive the data and release card 1060 | self.readinto(buf) 1061 | else: 1062 | # CMD18: set read address for multiple blocks 1063 | if self.cmd(18, block_num * self.cdv, 0, release=False) != 0: 1064 | # release the card 1065 | self.cs(1) 1066 | raise OSError(5) # EIO 1067 | offset = 0 1068 | mv = memoryview(buf) 1069 | while nblocks: 1070 | # receive the data and release card 1071 | self.readinto(mv[offset : offset + 512]) 1072 | offset += 512 1073 | nblocks -= 1 1074 | if self.cmd(12, 0, 0xFF, skip1=True): 1075 | raise OSError(5) # EIO 1076 | 1077 | def writeblocks(self, block_num, buf): 1078 | nblocks, err = divmod(len(buf), 512) 1079 | assert nblocks and not err, "Buffer length is invalid" 1080 | if nblocks == 1: 1081 | # CMD24: set write address for single block 1082 | if self.cmd(24, block_num * self.cdv, 0) != 0: 1083 | raise OSError(5) # EIO 1084 | 1085 | # send the data 1086 | self.write(_TOKEN_DATA, buf) 1087 | else: 1088 | # CMD25: set write address for first block 1089 | if self.cmd(25, block_num * self.cdv, 0) != 0: 1090 | raise OSError(5) # EIO 1091 | # send the data 1092 | offset = 0 1093 | mv = memoryview(buf) 1094 | while nblocks: 1095 | self.write(_TOKEN_CMD25, mv[offset : offset + 512]) 1096 | offset += 512 1097 | nblocks -= 1 1098 | self.write_token(_TOKEN_STOP_TRAN) 1099 | 1100 | def ioctl(self, op, arg): 1101 | if op == 4: # get number of blocks 1102 | return self.sectors 1103 | -------------------------------------------------------------------------------- /examples/Receiver_LCD_sdcard_demo.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Demo code to test receive funciton along with display of PiBeam 3 | ____________________________________________________________________________________________________________ 4 | NEC PROTOCOL | SONY PROTOCOL | PHILIPS RC PROTOCOL | Microsoft Vista MCE PROTOCOL | 5 | _______________________|__________________________|__________________________|_______________________________| 6 | rx = NEC_8 (callback) | rx = SONY_12 (callback) | rx = RC5_IR (callback) | rx = MCE (callback) | 7 | rx = NEC_16(callback) | rx = SONY_15 (callback) | rx = RC6_M0 (callback) | | 8 | rx = SAMSUNG(callback) | rx = SONY_20 (callback) | | | 9 | _______________________|__________________________|__________________________|_______________________________| 10 | ''' 11 | from PiBeam import IR_Receiver,LCD,LED,SDCard 12 | import vga1_16x16 as font2 13 | import vga1_16x32 as font 14 | import vga1_8x16 as font1 15 | import vga2_8x8 as font3 16 | import time,utime 17 | import st7789 18 | import os 19 | 20 | #create display object to use available methods 21 | tft = LCD().display() 22 | 23 | led = LED() 24 | 25 | rx = IR_Receiver 26 | 27 | sd=SDCard() 28 | vfs = os.VfsFat(sd) 29 | 30 | def sd_card(data,address): 31 | os.mount(vfs, "/fc") 32 | #print("Filesystem check") 33 | #print(os.listdir("/fc")) # check the files in sd card 34 | fn = "/fc/File.txt" 35 | 36 | #print("Single block read/write") 37 | 38 | dat = data + " , "+ address 39 | 40 | with open(fn, "a") as f: # append data to file 41 | n = f.write(dat+ '\n') 42 | print(n, "bytes written") 43 | 44 | with open(fn, "r") as f: # read data from file 45 | result = f.read() 46 | #print(result) 47 | #print(len(result), "bytes read") 48 | os.umount("/fc") 49 | 50 | def info(): 51 | tft.init() #initialize display 52 | utime.sleep(0.2) 53 | tft.text(font,"SB COMPONENTS", 10,20,st7789.YELLOW) #display text with provided font, co-ordinates and color on TFT 54 | tft.fill_rect(10, 60, 210,10, st7789.RED) # param (x, y, rectangle_length, rectangle_breadth, color) 55 | tft.text(font,"PiBeam", 10,75,st7789.YELLOW) 56 | time.sleep(1) 57 | tft.fill(0) 58 | tft.text(font,"RECEIVE DATA", 10,10,st7789.WHITE) 59 | tft.fill_rect(10, 40, 210,10, st7789.RED) 60 | 61 | info() 62 | 63 | def callback(data, addr, ctrl): 64 | led.on() 65 | tft.text(font,'Data {:02x}'.format(data), 10,55,st7789.YELLOW) 66 | tft.text(font,'Addr {:04x}'.format(addr), 10,90,st7789.YELLOW) 67 | print('Addr {:04x}'.format(addr),'Data {:02x}'.format(data)) 68 | 69 | dat = 'Data = {:02x}'.format(data) 70 | add = 'Addr = {:04x}'.format(addr) 71 | 72 | sd_card(dat,add)# save data to sd card 73 | 74 | utime.sleep(0.1) 75 | 76 | tft.text(font,'Data {:02x}'.format(data), 10,55,st7789.BLACK) 77 | tft.text(font,'Addr {:04x}'.format(addr), 10,90,st7789.BLACK) 78 | time.sleep(0.1) 79 | led.off() 80 | 81 | rx = rx.NEC_16(callback) 82 | 83 | while True: 84 | time.sleep(0.2) 85 | -------------------------------------------------------------------------------- /examples/button_demo.py: -------------------------------------------------------------------------------- 1 | '''Demo code to test programmable buttons of PiBeam''' 2 | 3 | # Importing the BUTTON and LED modules from the PiBeam library 4 | from PiBeam import BUTTON, LED 5 | import time 6 | 7 | # Creating an instance of the LED class 8 | led = LED() 9 | 10 | # Creating instances of the BUTTON class for three different buttons 11 | bt1 = BUTTON(1) 12 | bt2 = BUTTON(2) 13 | bt3 = BUTTON(3) 14 | 15 | while True: 16 | # Checking if any of the buttons are pressed 17 | if bt1.read() == 0 or bt2.read() == 0 or bt3.read() == 0: 18 | print("BUTTON PRESS") 19 | time.sleep(0.1) # Introducing a 100ms delay 20 | led.on() 21 | time.sleep(0.1) 22 | led.off() 23 | 24 | 25 | -------------------------------------------------------------------------------- /examples/onboardLED_demo.py: -------------------------------------------------------------------------------- 1 | '''Demo code to test onboard programmable Status LED of PiBeam''' 2 | 3 | from PiBeam import LED #libray module import for LED 4 | import time 5 | 6 | led = LED() #create object for LED 7 | 8 | while True: 9 | led.on() #turn ON Status LED 10 | time.sleep(0.5) #wait for half second 11 | led.off() #turn OFF Status LED 12 | time.sleep(0.5) 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/readme: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /examples/receiver_demo.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Demo code to testing receive funciton of PiBeam 3 | Below provided various protocol options we have, for demo will use one of them 4 | ____________________________________________________________________________________________________________ 5 | NEC PROTOCOL | SONY PROTOCOL | PHILIPS RC PROTOCOL | Microsoft Vista MCE PROTOCOL | 6 | _______________________|__________________________|__________________________|_______________________________| 7 | rx = NEC_8 (callback) | rx = SONY_12 (callback) | rx = RC5_IR (callback) | rx = MCE (callback) | 8 | rx = NEC_16(callback) | rx = SONY_15 (callback) | rx = RC6_M0 (callback) | | 9 | rx = SAMSUNG(callback) | rx = SONY_20 (callback) | | | 10 | _______________________|__________________________|__________________________|_______________________________| 11 | ''' 12 | from PiBeam import IR_Receiver,LED 13 | import time,utime 14 | 15 | 16 | rx = IR_Receiver 17 | 18 | led = LED() 19 | 20 | def callback(data, addr, ctrl): 21 | led.on() 22 | print('Addr {:04x}'.format(addr),'Data {:02x}'.format(data)) 23 | utime.sleep(0.2)#wait 200ms 24 | led.off() 25 | 26 | rx = rx.NEC_16(callback) 27 | 28 | while True: 29 | time.sleep_ms(200) 30 | -------------------------------------------------------------------------------- /examples/sdcard_demo.py: -------------------------------------------------------------------------------- 1 | '''Demo code for read and write on microSD card''' 2 | 3 | from PiBeam import LED,SDCard #import required sdcard module 4 | import os 5 | 6 | led = LED() 7 | sd = SDCard() 8 | vfs = os.VfsFat(sd) 9 | os.mount(vfs, "/fc") 10 | print("Filesystem check") 11 | print(os.listdir("/fc")) # check the files in sd card 12 | 13 | fn = "/fc/File.txt" 14 | 15 | print("Single block read/write") 16 | 17 | data = "SB COMPONENTS" 18 | ################################################# 19 | 20 | with open(fn, "a") as f: # append data to file 21 | led.on() 22 | n = f.write(data) 23 | print(n, "bytes written") 24 | led.off() 25 | ################################################# 26 | 27 | ################################################# 28 | with open(fn, "r") as f: # read data from file 29 | led.on() 30 | result = f.read() 31 | print(result) 32 | print(len(result), "bytes read") 33 | led.off() 34 | 35 | os.umount("/fc") 36 | ################################################# 37 | 38 | 39 | -------------------------------------------------------------------------------- /examples/transmitter_LCD_sdcard_demo.py: -------------------------------------------------------------------------------- 1 | ''' 2 | _________________________________________________________________________ 3 | NEC PROTOCOL | SONY PROTOCOL | PHILIPS RC PROTOCOL | 4 | ___________________|__________________________|__________________________| 5 | rx = NEC() | rx = SONY_12 () | rx = RC5_IR () | 6 | | rx = SONY_15 () | rx = RC6_M0 () | 7 | | rx = SONY_20 () | | 8 | ___________________|__________________________|__________________________| 9 | ''' 10 | from PiBeam import IR_Transmitter,LCD,LED 11 | import vga1_8x16 as font1 12 | import vga1_16x32 as font 13 | import vga1_16x16 as font2 14 | import vga2_8x8 as font3 15 | import time,utime 16 | import st7789 17 | 18 | led = LED() 19 | led.off() 20 | 21 | tft = LCD().display() 22 | 23 | tx = IR_Transmitter 24 | 25 | def info(): 26 | tft.init() 27 | utime.sleep(0.2) 28 | tft.text(font,"SB BCOMPONENTS", 10,20) 29 | tft.fill_rect(10, 60, 210,10, st7789.RED) 30 | tft.text(font,"PiBeam", 10,75,st7789.YELLOW) 31 | time.sleep(1) 32 | tft.fill(0) #clear screen 33 | tft.text(font,"TRANSMIT DATA", 10,10,st7789.WHITE) 34 | tft.fill_rect(10, 40, 210,10, st7789.RED) 35 | 36 | info() 37 | 38 | tx = tx.SONY_12() 39 | 40 | data = 02 41 | address = 0004 42 | 43 | while True: 44 | tx.transmit(address,data) # address == 0004, data == 02 45 | tft.text(font,'Data {:02x}'.format(data), 10,55,st7789.YELLOW) 46 | tft.text(font,'Addr {:04x}'.format(address), 10,90,st7789.YELLOW) 47 | led.on() 48 | time.sleep(0.2) # delay 80ms 49 | led.off() 50 | time.sleep(0.2) 51 | 52 | 53 | -------------------------------------------------------------------------------- /examples/transmitter_demo.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Demo code to test IR trasmission application of PiBeam 3 | Below provided various protocol options we have, for demo will use one of them 4 | _________________________________________________________________________ 5 | NEC PROTOCOL | SONY PROTOCOL | PHILIPS RC PROTOCOL | 6 | ___________________|__________________________|__________________________| 7 | tx = NEC() | tx = SONY_12 () | tx = RC5_IR () | 8 | | tx = SONY_15 () | tx = RC6_M0 () | 9 | | tx = SONY_20 () | | 10 | ___________________|__________________________|__________________________| 11 | ''' 12 | 13 | from PiBeam import IR_Transmitter,LED 14 | import time,utime 15 | 16 | led = LED() 17 | led.off() 18 | 19 | #create instance for IR Transmitter 20 | tx = IR_Transmitter 21 | tx = tx.NEC() #selecting NEC transmission protocol 22 | 23 | data = 02 24 | address = 0004 25 | 26 | while True: 27 | tx.transmit(address,data) # address == 0004, data == 02, change value as per requirement 28 | print('Addr {:04x}'.format(address),'Data {:02x}'.format(data)) 29 | led.on() 30 | time.sleep(0.08) # delay 80ms 31 | led.off() 32 | time.sleep(0.08) 33 | 34 | 35 | -------------------------------------------------------------------------------- /images/LED_blink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/images/LED_blink.png -------------------------------------------------------------------------------- /images/pibeampinout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbcshop/PiBeam_Software/d07f11364d3dc57ca0e8437f48f3557a05eb387b/images/pibeampinout.jpg -------------------------------------------------------------------------------- /images/readme: -------------------------------------------------------------------------------- 1 | 2 | --------------------------------------------------------------------------------