├── 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 |
--------------------------------------------------------------------------------