├── README.md ├── ScoutMakes Azul ├── Azul CircuitPython images │ ├── README.txt │ ├── adafruit-circuitpython-tinkeringtech_scoutmakes_azul-en_US-6.3.0.uf2 │ └── adafruit-circuitpython-tinkeringtech_scoutmakes_azul-en_US-8.0.2.uf2 ├── README.md ├── ScoutMakes_Azul.brd ├── ScoutMakes_Azul.sch ├── assets │ ├── background_only.png │ ├── pic1.jpg │ ├── pic2.jpg │ └── pic3.jpg ├── examples │ ├── Azul test NEOPIXEL change with control pad arrows.txt │ ├── Azul test NEOPIXEL only.txt │ ├── Azul test OLED only.py │ ├── Azul test OLED only.txt │ └── Azul test gyro and neopixel.txt ├── feather_nrf52840_express_bootloader-0.3.2_s140_6.1.1.hex └── license.txt ├── ScoutMakes FM Breakout StemmaQT ├── README.md ├── ScoutMakes_FM_StemmaQT.brd ├── ScoutMakes_FM_StemmaQT.sch ├── examples │ ├── Arduino_RDA5807M_FMradio │ │ ├── LICENSE │ │ ├── examples │ │ │ └── SerialRadio │ │ │ │ └── SerialRadio.ino │ │ └── src │ │ │ ├── RDA5807M.cpp │ │ │ ├── RDA5807M.h │ │ │ ├── RDSParser.cpp │ │ │ ├── RDSParser.h │ │ │ ├── newchip.cpp │ │ │ ├── newchip.h │ │ │ ├── radio.cpp │ │ │ └── radio.h │ └── CircuitPython_RDA5807M_FMradio │ │ ├── code.py │ │ ├── lib │ │ ├── tinkeringtech_rda5807m.mpy │ │ └── tinkeringtech_rda5807m.py │ │ └── rda5807m_simpletest.py └── license.txt ├── ScoutMakes FM Kit ├── FM kit pictures │ ├── fmkit_1.jpg │ ├── fmkit_2.jpg │ └── fmkit_3.jpg ├── README.md ├── ScoutMakes_FM_Kit.brd ├── ScoutMakes_FM_Kit.sch ├── examples │ ├── Bluetooth_diagnostics.py │ ├── FM_radio_demo.py │ ├── OLED_Neopixel_diagnostics.py │ ├── code.py │ └── lib │ │ └── adafruit_ble │ │ ├── adafruit_ble │ │ ├── advertising │ │ │ ├── __init__.mpy │ │ │ ├── adafruit.mpy │ │ │ ├── apple.mpy │ │ │ └── standard.mpy │ │ ├── attributes │ │ │ └── __init__.mpy │ │ ├── characteristics │ │ │ ├── __init__.mpy │ │ │ ├── float.mpy │ │ │ ├── int.mpy │ │ │ ├── stream.mpy │ │ │ └── string.mpy │ │ └── services │ │ │ └── circuitpython.mpy │ │ ├── adafruit_ble_radio.mpy │ │ ├── adafruit_display_text │ │ ├── bitmap_label.mpy │ │ └── label.mpy │ │ ├── adafruit_displayio_ssd1306.mpy │ │ ├── advertising │ │ ├── __init__.mpy │ │ ├── adafruit.mpy │ │ ├── apple.mpy │ │ └── standard.mpy │ │ ├── attributes │ │ └── __init__.mpy │ │ ├── characteristics │ │ ├── __init__.mpy │ │ ├── float.mpy │ │ ├── int.mpy │ │ ├── stream.mpy │ │ └── string.mpy │ │ ├── neopixel.mpy │ │ ├── services │ │ └── circuitpython.mpy │ │ ├── simpleio.mpy │ │ ├── tinkeringtech_rda5807m.mpy │ │ └── tinkeringtech_rda5807m.py └── license.txt ├── ScoutMakes Robot Kit ├── README.md ├── Robot Kit 3D print files │ ├── Final ScoutMakes RobotKit Chassis v2.stl │ ├── Final ScoutMakes RobotKit Support v2.stl │ ├── ScoutMakes RobotKit Chassis v2.gcode │ ├── ScoutMakes RobotKit Support v2.gcode │ └── TinkerCad 3D print project ├── Robot-kit-pictures │ ├── robotkit_1.JPG │ ├── robotkit_2.jpg │ └── robotkit_3.jpg ├── examples │ ├── Bluetooth_diagnostics.py │ ├── FM_Radio_Demo.py │ ├── OLED_Neopixel_diagnostics.py │ ├── Robot_Demo.py │ ├── code.py │ └── lib │ │ └── adafruit_ble │ │ ├── adafruit_ble │ │ ├── __init__.mpy │ │ ├── advertising │ │ │ ├── __init__.mpy │ │ │ ├── adafruit.mpy │ │ │ ├── apple.mpy │ │ │ └── standard.mpy │ │ ├── attributes │ │ │ └── __init__.mpy │ │ ├── characteristics │ │ │ ├── __init__.mpy │ │ │ ├── float.mpy │ │ │ ├── int.mpy │ │ │ ├── stream.mpy │ │ │ └── string.mpy │ │ ├── services │ │ │ └── circuitpython.mpy │ │ └── uuid │ │ │ └── __init__.mpy │ │ ├── adafruit_ble_radio.mpy │ │ ├── adafruit_bluefruit_connect │ │ ├── __init__.mpy │ │ ├── _xyz_packet.mpy │ │ ├── accelerometer_packet.mpy │ │ ├── button_packet.mpy │ │ ├── color_packet.mpy │ │ ├── gyro_packet.mpy │ │ ├── location_packet.mpy │ │ ├── magnetometer_packet.mpy │ │ ├── packet.mpy │ │ └── quaternion_packet.mpy │ │ ├── adafruit_bus_device │ │ ├── i2c_device.mpy │ │ └── spi_device.mpy │ │ ├── adafruit_displayio_ssd1306.mpy │ │ ├── neopixel.mpy │ │ ├── simpleio.mpy │ │ ├── tinkeringtech_rda5807m.mpy │ │ └── tinkeringtech_rda5807m.py ├── license.txt ├── scoutmakes_robot_kit.brd └── scoutmakes_robot_kit.sch ├── assets ├── FM_Robot_kit_combo.png └── license.JPG └── license.txt /README.md: -------------------------------------------------------------------------------- 1 | **ScoutMakes STEM Electronic Kits** 2 | 3 | ![ScoutMakes](/assets/FM_Robot_kit_combo.png) 4 | 5 | These are the source design files for the ScoutMakes Electronic Kits 6 | - ScoutMakes FM Kit 7 | - ScoutMakes Robot Kit 8 | - ScoutMakes Azul 9 | 10 | The kits can be bought at https://www.scoutmakes.com. 11 | Please support this educational company by buying our products focused on cultivating more engineers! 12 | 13 | Designed by TinkeringTech. 14 | 15 | Hardware and documentation license: Creative Commons ShareAlike 3.0 United States (CC BY-SA 3.0 US) 16 | 17 | Software License: MIT License 18 | 19 | Check license.txt for more information. 20 | 21 | All text above must be included in any redistribution. 22 | 23 | ![ScoutMakes](/assets/license.JPG) 24 | -------------------------------------------------------------------------------- /ScoutMakes Azul/Azul CircuitPython images/README.txt: -------------------------------------------------------------------------------- 1 | The CircuitPython images contained in this directory are special builds to accomodate for a change in the make and model of the on-board flash memory chip on the Azul due to the chip shortage. The image at https://circuitpython.org/board/tinkeringtech_scoutmakes_azul/ is the original image based on the GD25Q16C whereas the new memory chip is the W25Q16JVxQ. 2 | 3 | Instructions on building CircuitPython from Adafruit https://learn.adafruit.com/building-circuitpython/linux 4 | 5 | In order to accomodate this change, the below change was made to the CircuitPython source code prior to building. Note the change in EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" for this new chip. 6 | 7 | circuitpython/ports/nrf/boards/tinkeringtech_scoutmakes_azul/mpconfigboard.mk 8 | 9 | USB_VID = 0x239A 10 | USB_PID = 0x80BE 11 | USB_PRODUCT = "TinkeringTech ScoutMakes Azul" 12 | USB_MANUFACTURER = "TinkeringTech LLC" 13 | 14 | MCU_CHIP = nrf52840 15 | 16 | QSPI_FLASH_FILESYSTEM = 1 17 | EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" 18 | 19 | 20 | -------------------------------------------------------------------------------- /ScoutMakes Azul/Azul CircuitPython images/adafruit-circuitpython-tinkeringtech_scoutmakes_azul-en_US-6.3.0.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Azul/Azul CircuitPython images/adafruit-circuitpython-tinkeringtech_scoutmakes_azul-en_US-6.3.0.uf2 -------------------------------------------------------------------------------- /ScoutMakes Azul/Azul CircuitPython images/adafruit-circuitpython-tinkeringtech_scoutmakes_azul-en_US-8.0.2.uf2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Azul/Azul CircuitPython images/adafruit-circuitpython-tinkeringtech_scoutmakes_azul-en_US-8.0.2.uf2 -------------------------------------------------------------------------------- /ScoutMakes Azul/README.md: -------------------------------------------------------------------------------- 1 | **ScoutMakes Azul Bluetooth BLE STEM Electronic Kit** 2 | 3 | **Open Source Hardware Association certified OSHWA UID US000652** 4 | 5 | These are the source design files for the ScoutMakes Azul Bluetooth BLE Electronic Kit. 6 | 7 | The kits can be bought at https://www.scoutmakes.com or https://www.tindie.com/products/tinkeringtech/scoutmakes-azul-nrf52840-bluetooth-maker-platform/ 8 | 9 | Please support this eduactiional company by buying our products focused on cultivating more engineers! 10 | 11 | Designed by TinkeringTech. 12 | 13 | Hardware and documentation license: Creative Commons ShareAlike 3.0 United States (CC BY-SA 3.0 US) 14 | 15 | Software License: MIT License 16 | 17 | Check license.txt for more information. 18 | 19 | All text above must be included in any redistribution. 20 | 21 | Features: 22 | 23 | - ARM Cortex M4F (with HW floating point acceleration) running at 64MHz 24 | - Raytac MDBT50Q-1MV2 BLE module. FCC / IC / TELEC certified module 25 | - 1MB flash and 256KB SRAM 26 | - Native Open Source USB stack – pre-programmed with UF2 bootloader and CircuitPython 27 | - 128×32 OLED display 28 | - USB type-C 29 | - On/off power switch 30 | - Bluetooth Low Energy compatible 2.4GHz radio (Details available in the nRF52840 product specification) 31 | - BT5.1 & BT5 Bluetooth Specification Certified 32 | - Supports BT5 Long Range Feature 33 | - 1.7v to 3.3v operation with internal linear and DC/DC voltage regulators 34 | - 21 GPIO, 6 x 12-bit ADC pins, up to 12 PWM outputs (3 PWM modules with 4 outputs each) 35 | - Pin #3 red LED for general purpose blinking, 36 | - Programmable NeoPixel for colorful feedback = 4 mounting holes 37 | - Reset button 38 | - Works out of the box with Adafruit feather wings. 39 | -------------------------------------------------------------------------------- /ScoutMakes Azul/assets/background_only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Azul/assets/background_only.png -------------------------------------------------------------------------------- /ScoutMakes Azul/assets/pic1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Azul/assets/pic1.jpg -------------------------------------------------------------------------------- /ScoutMakes Azul/assets/pic2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Azul/assets/pic2.jpg -------------------------------------------------------------------------------- /ScoutMakes Azul/assets/pic3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Azul/assets/pic3.jpg -------------------------------------------------------------------------------- /ScoutMakes Azul/examples/Azul test NEOPIXEL change with control pad arrows.txt: -------------------------------------------------------------------------------- 1 | """ 2 | This test will initialize the BLE module and accept commands from the Bluetooth app controller arrows and manipulate 3 | the onboard NEOPIXEL colors. 4 | 5 | To use: 6 | - Open the BLE app 7 | - Connect to the CIRCUITPYTHON board 8 | - Select the controller 9 | - Selcect control 10 | - Press the arrows to see the NEOPIXEL change color according to the following commands: 11 | RIGHT = RED 12 | LEFT = BLUE 13 | UP = GREEN 14 | DOWN = WHITE 15 | """ 16 | 17 | from adafruit_ble import BLERadio 18 | from adafruit_ble.advertising.standard import ProvideServicesAdvertisement 19 | from adafruit_ble.services.nordic import UARTService 20 | from adafruit_bluefruit_connect.packet import Packet 21 | # Only the packet classes that are imported will be known to Packet. 22 | from adafruit_bluefruit_connect.button_packet import ButtonPacket 23 | 24 | import time 25 | import board 26 | import pulseio 27 | 28 | import neopixel 29 | 30 | pixel_pin = board.NEOPIXEL 31 | num_pixels = 1 32 | 33 | pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False) 34 | 35 | RED = (255, 0, 0) 36 | YELLOW = (255, 150, 0) 37 | GREEN = (0, 255, 0) 38 | CYAN = (0, 255, 255) 39 | BLUE = (0, 0, 255) 40 | PURPLE = (180, 0, 255) 41 | WHITE = (255,255,255) 42 | 43 | ble = BLERadio() 44 | uart_service = UARTService() 45 | advertisement = ProvideServicesAdvertisement(uart_service) 46 | 47 | while True: 48 | ble.start_advertising(advertisement) 49 | while not ble.connected: 50 | pass 51 | 52 | # Now we're connected 53 | 54 | while ble.connected: 55 | if uart_service.in_waiting: 56 | # Packet is arriving. 57 | packet = Packet.from_stream(uart_service) 58 | if isinstance(packet, ButtonPacket) and packet.pressed: 59 | if packet.button == ButtonPacket.RIGHT: # RIGHT button pressed 60 | pixels.fill(RED) 61 | pixels.show() 62 | # Increase or decrease to change the speed of the solid color change. 63 | time.sleep(1) 64 | elif packet.button == ButtonPacket.LEFT: # LEFT button pressed 65 | pixels.fill(BLUE) 66 | pixels.show() 67 | time.sleep(1) 68 | elif packet.button == ButtonPacket.UP: # UP button pressed 69 | pixels.fill(GREEN) 70 | pixels.show() 71 | time.sleep(1) 72 | elif packet.button == ButtonPacket.DOWN: # DOWN button pressed 73 | pixels.fill(WHITE) 74 | pixels.show() 75 | time.sleep(1) -------------------------------------------------------------------------------- /ScoutMakes Azul/examples/Azul test NEOPIXEL only.txt: -------------------------------------------------------------------------------- 1 | """ 2 | This test will illuminate the onboard NEOPIXEL and cycle through colors red, green, blue followed by chasing pattern and rainbow 3 | """ 4 | 5 | import time 6 | import board 7 | import neopixel 8 | 9 | pixel_pin = board.NEOPIXEL 10 | num_pixels = 1 11 | 12 | pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False) 13 | 14 | 15 | def wheel(pos): 16 | # Input a value 0 to 255 to get a color value. 17 | # The colours are a transition r - g - b - back to r. 18 | if pos < 0 or pos > 255: 19 | return (0, 0, 0) 20 | if pos < 85: 21 | return (255 - pos * 3, pos * 3, 0) 22 | if pos < 170: 23 | pos -= 85 24 | return (0, 255 - pos * 3, pos * 3) 25 | pos -= 170 26 | return (pos * 3, 0, 255 - pos * 3) 27 | 28 | 29 | def color_chase(color, wait): 30 | for i in range(num_pixels): 31 | pixels[i] = color 32 | time.sleep(wait) 33 | pixels.show() 34 | time.sleep(0.5) 35 | 36 | 37 | def rainbow_cycle(wait): 38 | for j in range(255): 39 | for i in range(num_pixels): 40 | rc_index = (i * 256 // num_pixels) + j 41 | pixels[i] = wheel(rc_index & 255) 42 | pixels.show() 43 | time.sleep(wait) 44 | 45 | 46 | RED = (255, 0, 0) 47 | YELLOW = (255, 150, 0) 48 | GREEN = (0, 255, 0) 49 | CYAN = (0, 255, 255) 50 | BLUE = (0, 0, 255) 51 | PURPLE = (180, 0, 255) 52 | 53 | while True: 54 | pixels.fill(RED) 55 | pixels.show() 56 | # Increase or decrease to change the speed of the solid color change. 57 | time.sleep(1) 58 | pixels.fill(GREEN) 59 | pixels.show() 60 | time.sleep(1) 61 | pixels.fill(BLUE) 62 | pixels.show() 63 | time.sleep(1) 64 | 65 | color_chase(RED, 0.1) # Increase the number to slow down the color chase 66 | color_chase(YELLOW, 0.1) 67 | color_chase(GREEN, 0.1) 68 | color_chase(CYAN, 0.1) 69 | color_chase(BLUE, 0.1) 70 | color_chase(PURPLE, 0.1) 71 | 72 | rainbow_cycle(0) # Increase the number to slow down the rainbow 73 | -------------------------------------------------------------------------------- /ScoutMakes Azul/examples/Azul test OLED only.py: -------------------------------------------------------------------------------- 1 | """ 2 | This test will initialize the display using displayio and draw a solid white 3 | background, a smaller black rectangle, and white text saying ScoutMakes Azul. 4 | """ 5 | 6 | import board 7 | import displayio 8 | import terminalio 9 | from adafruit_display_text import label 10 | import adafruit_displayio_ssd1306 11 | 12 | displayio.release_displays() 13 | 14 | oled_reset = board.D9 15 | 16 | # Use for I2C 17 | i2c = board.I2C() 18 | display_bus = displayio.I2CDisplay(i2c, device_address=0x3C, reset=oled_reset) 19 | 20 | # Use for SPI 21 | # spi = board.SPI() 22 | # oled_cs = board.D5 23 | # oled_dc = board.D6 24 | # display_bus = displayio.FourWire(spi, command=oled_dc, chip_select=oled_cs, 25 | # reset=oled_reset, baudrate=1000000) 26 | 27 | WIDTH = 128 28 | HEIGHT = 32 # Change to 64 if needed 29 | BORDER = 5 30 | 31 | display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=WIDTH, height=HEIGHT) 32 | 33 | # Make the display context 34 | splash = displayio.Group(max_size=10) 35 | display.show(splash) 36 | 37 | color_bitmap = displayio.Bitmap(WIDTH, HEIGHT, 1) 38 | color_palette = displayio.Palette(1) 39 | color_palette[0] = 0xFFFFFF # White 40 | 41 | bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) 42 | splash.append(bg_sprite) 43 | 44 | # Draw a smaller inner rectangle 45 | inner_bitmap = displayio.Bitmap(WIDTH - BORDER * 2, HEIGHT - BORDER * 2, 1) 46 | inner_palette = displayio.Palette(1) 47 | inner_palette[0] = 0x000000 # Black 48 | inner_sprite = displayio.TileGrid( 49 | inner_bitmap, pixel_shader=inner_palette, x=BORDER, y=BORDER 50 | ) 51 | splash.append(inner_sprite) 52 | 53 | # Draw a label 54 | text = "ScoutMakes Azul" 55 | text_area = label.Label( 56 | terminalio.FONT, text=text, color=0xFFFFFF, x=28, y=HEIGHT // 2 - 1 57 | ) 58 | splash.append(text_area) 59 | 60 | while True: 61 | pass -------------------------------------------------------------------------------- /ScoutMakes Azul/examples/Azul test OLED only.txt: -------------------------------------------------------------------------------- 1 | """ 2 | This test will initialize the display using displayio and draw a solid white 3 | background, a smaller black rectangle, and white text saying ScoutMakes Azul. 4 | """ 5 | 6 | import board 7 | import displayio 8 | import terminalio 9 | from adafruit_display_text import label 10 | import adafruit_displayio_ssd1306 11 | 12 | displayio.release_displays() 13 | 14 | oled_reset = board.D9 15 | 16 | # Use for I2C 17 | i2c = board.I2C() 18 | display_bus = displayio.I2CDisplay(i2c, device_address=0x3C, reset=oled_reset) 19 | 20 | # Use for SPI 21 | # spi = board.SPI() 22 | # oled_cs = board.D5 23 | # oled_dc = board.D6 24 | # display_bus = displayio.FourWire(spi, command=oled_dc, chip_select=oled_cs, 25 | # reset=oled_reset, baudrate=1000000) 26 | 27 | WIDTH = 128 28 | HEIGHT = 32 # Change to 64 if needed 29 | BORDER = 5 30 | 31 | display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=WIDTH, height=HEIGHT) 32 | 33 | # Make the display context 34 | splash = displayio.Group(max_size=10) 35 | display.show(splash) 36 | 37 | color_bitmap = displayio.Bitmap(WIDTH, HEIGHT, 1) 38 | color_palette = displayio.Palette(1) 39 | color_palette[0] = 0xFFFFFF # White 40 | 41 | bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) 42 | splash.append(bg_sprite) 43 | 44 | # Draw a smaller inner rectangle 45 | inner_bitmap = displayio.Bitmap(WIDTH - BORDER * 2, HEIGHT - BORDER * 2, 1) 46 | inner_palette = displayio.Palette(1) 47 | inner_palette[0] = 0x000000 # Black 48 | inner_sprite = displayio.TileGrid( 49 | inner_bitmap, pixel_shader=inner_palette, x=BORDER, y=BORDER 50 | ) 51 | splash.append(inner_sprite) 52 | 53 | # Draw a label 54 | text = "ScoutMakes Azul" 55 | text_area = label.Label( 56 | terminalio.FONT, text=text, color=0xFFFFFF, x=28, y=HEIGHT // 2 - 1 57 | ) 58 | splash.append(text_area) 59 | 60 | while True: 61 | pass -------------------------------------------------------------------------------- /ScoutMakes Azul/examples/Azul test gyro and neopixel.txt: -------------------------------------------------------------------------------- 1 | from adafruit_ble import BLERadio 2 | from adafruit_ble.advertising.standard import ProvideServicesAdvertisement 3 | from adafruit_ble.services.nordic import UARTService 4 | 5 | from adafruit_bluefruit_connect.packet import Packet 6 | from adafruit_bluefruit_connect.accelerometer_packet import AccelerometerPacket 7 | 8 | import time 9 | import board 10 | import pulseio 11 | 12 | import neopixel 13 | 14 | pixel_pin = board.NEOPIXEL 15 | num_pixels = 1 16 | 17 | pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False) 18 | 19 | RED = (255, 0, 0) 20 | YELLOW = (255, 150, 0) 21 | GREEN = (0, 255, 0) 22 | CYAN = (0, 255, 255) 23 | BLUE = (0, 0, 255) 24 | PURPLE = (180, 0, 255) 25 | WHITE = (255,255,255) 26 | 27 | ble = BLERadio() 28 | uart = UARTService() 29 | advertisement = ProvideServicesAdvertisement(uart) 30 | 31 | while True: 32 | ble.start_advertising(advertisement) 33 | while not ble.connected: 34 | pass 35 | 36 | # Now we're connected 37 | 38 | while ble.connected: 39 | if uart.in_waiting: 40 | packet = Packet.from_stream(uart) 41 | if isinstance(packet, AccelerometerPacket): 42 | x = packet.x 43 | y = packet.y 44 | #print (y) 45 | if x<-1.5: 46 | pixels.fill(RED) 47 | pixels.show() 48 | # Increase or decrease to change the speed of the solid color change. 49 | time.sleep(1) 50 | elif x>1.5: 51 | pixels.fill(GREEN) 52 | pixels.show() 53 | time.sleep(1) 54 | elif y<-1.5: 55 | pixels.fill(BLUE) 56 | pixels.show() 57 | time.sleep(1) 58 | #time.sleep(0.01) 59 | #print ("less") 60 | elif y>1.5: 61 | pixels.fill(YELLOW) 62 | pixels.show() 63 | time.sleep(1) 64 | #time.sleep(0.01) 65 | #print ("less") 66 | elif y<1.5 and y>-1.5: 67 | pixels.fill(WHITE) 68 | pixels.show() 69 | time.sleep(1) 70 | #time.sleep(0.01) 71 | #print ("less") 72 | elif x<1.5 and x>-1.5: 73 | pixels.fill(WHITE) 74 | pixels.show() 75 | time.sleep(1) 76 | #time.sleep(0.01) 77 | #print ("less") -------------------------------------------------------------------------------- /ScoutMakes FM Breakout StemmaQT/README.md: -------------------------------------------------------------------------------- 1 | **ScoutMakes FM breakout STEMMA QT/QWIIC I2C** 2 | 3 | These are the source design files for the ScoutMakes FM Radio Board STEMMA/Qwiic I2C. 4 | 5 | The kits can be bought at https://www.scoutmakes.com. 6 | Please support this educational company by buying our products focused on cultivating more engineers! 7 | 8 | Designed by TinkeringTech. 9 | License: Creative Commons ShareAlike 3.0 United States (CC BY-SA 3.0 US) 10 | License: MIT License 11 | Check license.txt for more information All text above must be included in any redistribution. 12 | 13 | **FM Radio Kit Features & Specifications** 14 | - Open hardware & open source software 15 | - RDA5807M single-chip FM receiver 16 | - High-quality stereo audio output 17 | - Built-in volume and bass control 18 | - Received signal strength indicator (RSSI) information 19 | - Station scanning and presets are supported in code 20 | - Radio Data Service (RDS) information available for display 21 | - Received signal strength (RSSI) indication 22 | - Adafruit CircuitPython library 23 | - Adafruit STEMMA QT and SparkFun Qwiic connectors for easy, solderless attachment of other I²C devices 24 | - 3.5 mm audio jack 25 | - Power LED indicator 26 | -------------------------------------------------------------------------------- /ScoutMakes FM Breakout StemmaQT/examples/Arduino_RDA5807M_FMradio/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2005-2020, Matthias Hertel, http://www.mathertel.de/ 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | 3. Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /ScoutMakes FM Breakout StemmaQT/examples/Arduino_RDA5807M_FMradio/examples/SerialRadio/SerialRadio.ino: -------------------------------------------------------------------------------- 1 | /// 2 | /// \file SerialRadio.ino 3 | /// \brief Radio implementation using the Serial communication. 4 | /// 5 | /// \author Matthias Hertel, http://www.mathertel.de 6 | /// \copyright Copyright (c) by Matthias Hertel.\n 7 | /// This work is licensed under a BSD 3-Clause license.\n 8 | /// See http://www.mathertel.de/License.aspx 9 | /// 10 | /// \details 11 | /// This is a Arduino sketch radio implementation that can be controlled using commands on the Serial input. 12 | /// It can be used with various chips after adjusting the radio object definition.\n 13 | /// Open the Serial console with 115200 baud to see current radio information and change various settings. 14 | /// 15 | /// Wiring 16 | /// ------ 17 | /// The necessary wiring of the various chips are described in the Testxxx example sketches. 18 | /// No additional components are required because all is done through the serial interface. 19 | /// 20 | /// More documentation and source code is available at http://www.mathertel.de/Arduino 21 | /// 22 | /// History: 23 | /// -------- 24 | /// * 05.08.2014 created. 25 | /// * 04.10.2014 working. 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | // all possible radio chips included. 33 | #include 34 | #include 35 | 36 | 37 | // Define some stations available at your locations here: 38 | // 89.40 MHz as 8940 or 100.10MHz as 10010 39 | 40 | RADIO_FREQ preset[] = { 41 | 8770, 42 | 8810, 43 | 8820, 44 | 9950, 45 | 10010, 46 | 8930, 47 | 8980 48 | }; 49 | 50 | int i_sidx = 3; ///< Start at Station with index=3 51 | 52 | RDA5807M radio; ///< Create an instance of a RDA5807 chip radio 53 | 54 | /// get a RDS parser 55 | RDSParser rds; 56 | 57 | 58 | /// State of Keyboard input for this radio implementation. 59 | enum RADIO_STATE { 60 | STATE_PARSECOMMAND, ///< waiting for a new command character. 61 | STATE_PARSEINT, ///< waiting for digits for the parameter. 62 | STATE_EXEC ///< executing the command. 63 | }; 64 | 65 | RADIO_STATE kbState; ///< The state of parsing input characters. 66 | char kbCommand; 67 | int16_t kbValue; 68 | 69 | bool lowLevelDebug = false; 70 | 71 | 72 | /// Update the Frequency on the LCD display. 73 | void DisplayFrequency(RADIO_FREQ f) 74 | { 75 | char s[12]; 76 | radio.formatFrequency(s, sizeof(s)); 77 | Serial.print("FREQ:"); 78 | Serial.println(s); 79 | } // DisplayFrequency() 80 | 81 | 82 | /// Update the ServiceName text on the LCD display. 83 | void DisplayServiceName(char *name) 84 | { 85 | Serial.print("RDS:"); 86 | Serial.println(name); 87 | } // DisplayServiceName() 88 | 89 | 90 | // - - - - - - - - - - - - - - - - - - - - - - - - - - 91 | 92 | 93 | void RDS_process(uint16_t block1, uint16_t block2, uint16_t block3, uint16_t block4) 94 | { 95 | rds.processData(block1, block2, block3, block4); 96 | } 97 | 98 | 99 | /// Execute a command identified by a character and an optional number. 100 | /// See the "?" command for available commands. 101 | /// \param cmd The command character. 102 | /// \param value An optional parameter for the command. 103 | void runSerialCommand(char cmd, int16_t value) 104 | { 105 | if (cmd == '?') { 106 | Serial.println(); 107 | Serial.println("? Help"); 108 | Serial.println("+ increase volume"); 109 | Serial.println("- decrease volume"); 110 | Serial.println("> next preset"); 111 | Serial.println("< previous preset"); 112 | Serial.println(". scan up : scan up to next sender"); 113 | Serial.println(", scan down ; scan down to next sender"); 114 | Serial.println("fnnnnn: direct frequency input"); 115 | Serial.println("i station status"); 116 | Serial.println("s mono/stereo mode"); 117 | Serial.println("b bass boost"); 118 | Serial.println("u mute/unmute"); 119 | } 120 | 121 | // ----- control the volume and audio output ----- 122 | 123 | else if (cmd == '+') { 124 | // increase volume 125 | int v = radio.getVolume(); 126 | if (v < 15) 127 | radio.setVolume(++v); 128 | } else if (cmd == '-') { 129 | // decrease volume 130 | int v = radio.getVolume(); 131 | if (v > 0) 132 | radio.setVolume(--v); 133 | } 134 | 135 | else if (cmd == 'u') { 136 | // toggle mute mode 137 | radio.setMute(!radio.getMute()); 138 | } 139 | 140 | // toggle stereo mode 141 | else if (cmd == 's') { 142 | radio.setMono(!radio.getMono()); 143 | } 144 | 145 | // toggle bass boost 146 | else if (cmd == 'b') { 147 | radio.setBassBoost(!radio.getBassBoost()); 148 | } 149 | 150 | // ----- control the frequency ----- 151 | 152 | else if (cmd == '>') { 153 | // next preset 154 | if (i_sidx < (sizeof(preset) / sizeof(RADIO_FREQ)) - 1) { 155 | i_sidx++; 156 | radio.setFrequency(preset[i_sidx]); 157 | } // if 158 | } else if (cmd == '<') { 159 | // previous preset 160 | if (i_sidx > 0) { 161 | i_sidx--; 162 | radio.setFrequency(preset[i_sidx]); 163 | } // if 164 | 165 | } else if (cmd == 'f') { 166 | radio.setFrequency(value); 167 | } 168 | 169 | else if (cmd == '.') { 170 | radio.seekUp(false); 171 | } else if (cmd == ':') { 172 | radio.seekUp(true); 173 | } else if (cmd == ',') { 174 | radio.seekDown(false); 175 | } else if (cmd == ';') { 176 | radio.seekDown(true); 177 | } 178 | 179 | 180 | else if (cmd == '!') { 181 | // not in help 182 | RADIO_FREQ f = radio.getFrequency(); 183 | if (value == 0) { 184 | radio.term(); 185 | } else if (value == 1) { 186 | radio.init(); 187 | radio.setBandFrequency(RADIO_BAND_FM, f); 188 | } 189 | 190 | } else if (cmd == 'i') { 191 | // info 192 | char s[12]; 193 | radio.formatFrequency(s, sizeof(s)); 194 | Serial.print("Station:"); 195 | Serial.println(s); 196 | Serial.print("Radio:"); 197 | radio.debugRadioInfo(); 198 | Serial.print("Audio:"); 199 | radio.debugAudioInfo(); 200 | 201 | } else if (cmd == 'x') { 202 | radio.debugStatus(); // print chip specific data. 203 | 204 | } else if (cmd == '*') { 205 | lowLevelDebug = !lowLevelDebug; 206 | radio._wireDebug(lowLevelDebug); 207 | } 208 | } // runSerialCommand() 209 | 210 | 211 | /// Setup a FM only radio configuration with I/O for commands and debugging on the Serial port. 212 | void setup() 213 | { 214 | // open the Serial port 215 | Serial.begin(115200); 216 | Serial.print("Radio..."); 217 | delay(500); 218 | 219 | #ifdef ESP8266 220 | // For ESP8266 boards (like NodeMCU) the I2C GPIO pins in use 221 | // need to be specified. 222 | Wire.begin(D2, D1); // a common GPIO pin setting for I2C 223 | #endif 224 | 225 | // Enable information to the Serial port 226 | radio.debugEnable(true); 227 | radio._wireDebug(lowLevelDebug); 228 | 229 | // Initialize the Radio 230 | radio.init(); 231 | 232 | radio.setBandFrequency(RADIO_BAND_FM, preset[i_sidx]); // 5. preset. 233 | 234 | // delay(100); 235 | 236 | radio.setMono(false); 237 | radio.setMute(false); 238 | radio.setVolume(10); 239 | 240 | Serial.write('>'); 241 | 242 | // setup the information chain for RDS data. 243 | radio.attachReceiveRDS(RDS_process); 244 | rds.attachServicenNameCallback(DisplayServiceName); 245 | 246 | runSerialCommand('?', 0); 247 | kbState = STATE_PARSECOMMAND; 248 | } // Setup 249 | 250 | 251 | /// Constantly check for serial input commands and trigger command execution. 252 | void loop() 253 | { 254 | int newPos; 255 | unsigned long now = millis(); 256 | static unsigned long nextFreqTime = 0; 257 | static unsigned long nextRadioInfoTime = 0; 258 | 259 | // some internal static values for parsing the input 260 | static RADIO_FREQ lastf = 0; 261 | RADIO_FREQ f = 0; 262 | 263 | if (Serial.available() > 0) { 264 | // read the next char from input. 265 | char c = Serial.peek(); 266 | 267 | if ((kbState == STATE_PARSECOMMAND) && (c < 0x20)) { 268 | // ignore unprintable chars 269 | Serial.read(); 270 | 271 | } else if (kbState == STATE_PARSECOMMAND) { 272 | // read a command. 273 | kbCommand = Serial.read(); 274 | kbState = STATE_PARSEINT; 275 | 276 | } else if (kbState == STATE_PARSEINT) { 277 | if ((c >= '0') && (c <= '9')) { 278 | // build up the value. 279 | c = Serial.read(); 280 | kbValue = (kbValue * 10) + (c - '0'); 281 | } else { 282 | // not a value -> execute 283 | runSerialCommand(kbCommand, kbValue); 284 | kbCommand = ' '; 285 | kbState = STATE_PARSECOMMAND; 286 | kbValue = 0; 287 | } // if 288 | } // if 289 | } // if 290 | 291 | // check for RDS data 292 | radio.checkRDS(); 293 | 294 | // update the display from time to time 295 | if (now > nextFreqTime) { 296 | f = radio.getFrequency(); 297 | if (f != lastf) { 298 | // print current tuned frequency 299 | DisplayFrequency(f); 300 | lastf = f; 301 | } // if 302 | nextFreqTime = now + 400; 303 | } // if 304 | 305 | } // loop 306 | 307 | // End. 308 | -------------------------------------------------------------------------------- /ScoutMakes FM Breakout StemmaQT/examples/Arduino_RDA5807M_FMradio/src/RDA5807M.cpp: -------------------------------------------------------------------------------- 1 | /// \file RDA5807M.cpp 2 | /// \brief Implementation for the radio library to control the RDA5807M radio chip. 3 | /// 4 | /// \author Matthias Hertel, http://www.mathertel.de 5 | /// \copyright Copyright (c) 2014-2015 by Matthias Hertel.\n 6 | /// This work is licensed under a BSD style license.\n 7 | /// See http://www.mathertel.de/License.aspx 8 | /// 9 | /// This library enables the use of the radio chip RDA5807M from http://www.rdamicro.com/. 10 | /// 11 | /// More documentation and source code is available at http://www.mathertel.de/Arduino 12 | /// 13 | /// History: 14 | /// -------- 15 | /// * 05.08.2014 created. 16 | 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | // ----- Register Definitions ----- 25 | 26 | // this chip only supports FM mode 27 | #define FREQ_STEPS 10 28 | 29 | #define RADIO_REG_CHIPID 0x00 30 | 31 | #define RADIO_REG_CTRL 0x02 32 | #define RADIO_REG_CTRL_OUTPUT 0x8000 33 | #define RADIO_REG_CTRL_UNMUTE 0x4000 34 | #define RADIO_REG_CTRL_MONO 0x2000 35 | #define RADIO_REG_CTRL_BASS 0x1000 36 | #define RADIO_REG_CTRL_SEEKUP 0x0200 37 | #define RADIO_REG_CTRL_SEEK 0x0100 38 | #define RADIO_REG_CTRL_RDS 0x0008 39 | #define RADIO_REG_CTRL_NEW 0x0004 40 | #define RADIO_REG_CTRL_RESET 0x0002 41 | #define RADIO_REG_CTRL_ENABLE 0x0001 42 | 43 | #define RADIO_REG_CHAN 0x03 44 | #define RADIO_REG_CHAN_SPACE 0x0003 45 | #define RADIO_REG_CHAN_SPACE_100 0x0000 46 | #define RADIO_REG_CHAN_BAND 0x000C 47 | #define RADIO_REG_CHAN_BAND_FM 0x0000 48 | #define RADIO_REG_CHAN_BAND_FMWORLD 0x0008 49 | #define RADIO_REG_CHAN_TUNE 0x0010 50 | // RADIO_REG_CHAN_TEST 0x0020 51 | #define RADIO_REG_CHAN_NR 0x7FC0 52 | 53 | #define RADIO_REG_R4 0x04 54 | #define RADIO_REG_R4_EM50 0x0800 55 | // RADIO_REG_R4_RES 0x0400 56 | #define RADIO_REG_R4_SOFTMUTE 0x0200 57 | #define RADIO_REG_R4_AFC 0x0100 58 | 59 | 60 | #define RADIO_REG_VOL 0x05 61 | #define RADIO_REG_VOL_VOL 0x000F 62 | 63 | 64 | #define RADIO_REG_RA 0x0A 65 | #define RADIO_REG_RA_RDS 0x8000 66 | #define RADIO_REG_RA_RDSBLOCK 0x0800 67 | #define RADIO_REG_RA_STEREO 0x0400 68 | #define RADIO_REG_RA_NR 0x03FF 69 | 70 | #define RADIO_REG_RB 0x0B 71 | #define RADIO_REG_RB_FMTRUE 0x0100 72 | #define RADIO_REG_RB_FMREADY 0x0080 73 | 74 | 75 | #define RADIO_REG_RDSA 0x0C 76 | #define RADIO_REG_RDSB 0x0D 77 | #define RADIO_REG_RDSC 0x0E 78 | #define RADIO_REG_RDSD 0x0F 79 | 80 | // I2C-Address RDA Chip for sequential Access 81 | #define I2C_SEQ 0x10 82 | 83 | // I2C-Address RDA Chip for Index Access 84 | #define I2C_INDX 0x11 85 | 86 | 87 | // ----- implement 88 | 89 | // initialize the extra variables in RDA5807M 90 | RDA5807M::RDA5807M() { 91 | // t.b.d. ??? 92 | } 93 | 94 | // initialize all internals. 95 | bool RDA5807M::init() { 96 | bool result = false; // no chip found yet. 97 | DEBUG_FUNC0("init"); 98 | 99 | Wire.begin(); 100 | Wire.beginTransmission(I2C_INDX); 101 | result = Wire.endTransmission(); 102 | if (result == 0) { 103 | DEBUG_STR("radio found."); 104 | result = true; 105 | 106 | // initialize all registers 107 | registers[RADIO_REG_CHIPID] = 0x5804; // 00 id 108 | registers[1] = 0x0000; // 01 not used 109 | registers[RADIO_REG_CTRL] = (RADIO_REG_CTRL_RESET | RADIO_REG_CTRL_ENABLE); 110 | setBand(RADIO_BAND_FM); 111 | registers[RADIO_REG_R4] = RADIO_REG_R4_EM50;// 0x1800; // 04 DE ? SOFTMUTE 112 | registers[RADIO_REG_VOL] = 0x9081; // 0x81D1; // 0x82D1 / INT_MODE, SEEKTH=0110,????, Volume=1 113 | registers[6] = 0x0000; 114 | registers[7] = 0x0000; 115 | registers[8] = 0x0000; 116 | registers[9] = 0x0000; 117 | 118 | // reset the chip 119 | _saveRegisters(); 120 | 121 | registers[RADIO_REG_CTRL] = RADIO_REG_CTRL_ENABLE; 122 | _saveRegister(RADIO_REG_CTRL); 123 | } // if 124 | return(result); 125 | } // init() 126 | 127 | 128 | // switch the power off 129 | void RDA5807M::term() 130 | { 131 | DEBUG_FUNC0("term"); 132 | setVolume(0); 133 | registers[RADIO_REG_CTRL] = 0x0000; // all bits off 134 | _saveRegisters(); 135 | } // term 136 | 137 | 138 | // ----- Volume control ----- 139 | 140 | void RDA5807M::setVolume(uint8_t newVolume) 141 | { 142 | RADIO::setVolume(newVolume); 143 | newVolume &= RADIO_REG_VOL_VOL; 144 | registers[RADIO_REG_VOL] &= (~RADIO_REG_VOL_VOL); 145 | registers[RADIO_REG_VOL] |= newVolume; 146 | _saveRegister(RADIO_REG_VOL); 147 | } // setVolume() 148 | 149 | 150 | void RDA5807M::setBassBoost(bool switchOn) 151 | { 152 | RADIO::setBassBoost(switchOn); 153 | uint16_t regCtrl = registers[RADIO_REG_CTRL]; 154 | if (switchOn) 155 | regCtrl |= RADIO_REG_CTRL_BASS; 156 | else 157 | regCtrl &= (~RADIO_REG_CTRL_BASS); 158 | registers[RADIO_REG_CTRL] = regCtrl; 159 | _saveRegister(RADIO_REG_CTRL); 160 | } // setBassBoost() 161 | 162 | 163 | // Mono / Stereo 164 | void RDA5807M::setMono(bool switchOn) 165 | { 166 | RADIO::setMono(switchOn); 167 | 168 | registers[RADIO_REG_CTRL] &= (~RADIO_REG_CTRL_SEEK); 169 | if (switchOn) { 170 | registers[RADIO_REG_CTRL] |= RADIO_REG_CTRL_MONO; 171 | } 172 | else { 173 | registers[RADIO_REG_CTRL] &= ~RADIO_REG_CTRL_MONO; 174 | } 175 | _saveRegister(RADIO_REG_CTRL); 176 | } // setMono 177 | 178 | 179 | // Switch mute mode. 180 | void RDA5807M::setMute(bool switchOn) 181 | { 182 | RADIO::setMute(switchOn); 183 | 184 | if (switchOn) { 185 | // now don't unmute 186 | registers[RADIO_REG_CTRL] &= (~RADIO_REG_CTRL_UNMUTE); 187 | } 188 | else { 189 | // now unmute 190 | registers[RADIO_REG_CTRL] |= RADIO_REG_CTRL_UNMUTE; 191 | } // if 192 | _saveRegister(RADIO_REG_CTRL); 193 | } // setMute() 194 | 195 | 196 | // Switch softmute mode. 197 | void RDA5807M::setSoftMute(bool switchOn) 198 | { 199 | RADIO::setSoftMute(switchOn); 200 | 201 | if (switchOn) { 202 | registers[RADIO_REG_R4] |= (RADIO_REG_R4_SOFTMUTE); 203 | } 204 | else { 205 | registers[RADIO_REG_R4] &= (~RADIO_REG_R4_SOFTMUTE); 206 | } // if 207 | _saveRegister(RADIO_REG_R4); 208 | } // setSoftMute() 209 | 210 | 211 | // ----- Band and frequency control methods ----- 212 | 213 | // tune to new band. 214 | void RDA5807M::setBand(RADIO_BAND newBand) { 215 | uint16_t r; 216 | RADIO::setBand(newBand); 217 | 218 | if (newBand == RADIO_BAND_FM) 219 | r = RADIO_REG_CHAN_BAND_FM; 220 | else if (newBand == RADIO_BAND_FMWORLD) 221 | r = RADIO_REG_CHAN_BAND_FMWORLD; 222 | registers[RADIO_REG_CHAN] = (r | RADIO_REG_CHAN_SPACE_100); 223 | _saveRegister(RADIO_REG_CHAN); 224 | } // setBand() 225 | 226 | 227 | // retrieve the real frequency from the chip after automatic tuning. 228 | RADIO_FREQ RDA5807M::getFrequency() { 229 | // check register A 230 | Wire.requestFrom (I2C_SEQ, 2); 231 | registers[RADIO_REG_RA] = _read16(); 232 | 233 | uint16_t ch = registers[RADIO_REG_RA] & RADIO_REG_RA_NR; 234 | 235 | _freq = _freqLow + (ch * 10); // assume 100 kHz spacing 236 | return (_freq); 237 | } // getFrequency 238 | 239 | 240 | void RDA5807M::setFrequency(RADIO_FREQ newF) { 241 | DEBUG_FUNC1("setFrequency", newF); 242 | uint16_t newChannel; 243 | uint16_t regChannel = registers[RADIO_REG_CHAN] & (RADIO_REG_CHAN_SPACE | RADIO_REG_CHAN_BAND); 244 | 245 | if (newF < _freqLow) newF = _freqLow; 246 | if (newF > _freqHigh) newF = _freqHigh; 247 | newChannel = (newF - _freqLow) / 10; 248 | 249 | regChannel += RADIO_REG_CHAN_TUNE; // enable tuning 250 | regChannel |= newChannel << 6; 251 | 252 | // enable output and unmute 253 | registers[RADIO_REG_CTRL] |= RADIO_REG_CTRL_OUTPUT | RADIO_REG_CTRL_UNMUTE | RADIO_REG_CTRL_RDS | RADIO_REG_CTRL_ENABLE; // | RADIO_REG_CTRL_NEW 254 | _saveRegister(RADIO_REG_CTRL); 255 | 256 | registers[RADIO_REG_CHAN] = regChannel; 257 | _saveRegister(RADIO_REG_CHAN); 258 | 259 | // adjust Volume 260 | _saveRegister(RADIO_REG_VOL); 261 | } // setFrequency() 262 | 263 | 264 | // start seek mode upwards 265 | void RDA5807M::seekUp(bool toNextSender) { 266 | // start seek mode 267 | registers[RADIO_REG_CTRL] |= RADIO_REG_CTRL_SEEKUP; 268 | registers[RADIO_REG_CTRL] |= RADIO_REG_CTRL_SEEK; 269 | _saveRegister(RADIO_REG_CTRL); 270 | 271 | registers[RADIO_REG_CTRL] &= (~RADIO_REG_CTRL_SEEK); // clear seekmode 272 | if (! toNextSender) { 273 | // stop scanning right now 274 | //registers[RADIO_REG_CTRL] &= (~RADIO_REG_CTRL_SEEK); 275 | _saveRegister(RADIO_REG_CTRL); 276 | } // if 277 | } // seekUp() 278 | 279 | 280 | // start seek mode downwards 281 | void RDA5807M::seekDown(bool toNextSender) { 282 | registers[RADIO_REG_CTRL] &= (~RADIO_REG_CTRL_SEEKUP); 283 | registers[RADIO_REG_CTRL] |= RADIO_REG_CTRL_SEEK; 284 | _saveRegister(RADIO_REG_CTRL); 285 | 286 | registers[RADIO_REG_CTRL] &= (~RADIO_REG_CTRL_SEEK); // clear seekmode 287 | if (! toNextSender) { 288 | // stop scanning right now 289 | _saveRegister(RADIO_REG_CTRL); 290 | } // if 291 | } // seekDown() 292 | 293 | 294 | // Load all status registers from to the chip 295 | // registers 0A through 0F 296 | // using the sequential read access mode. 297 | void RDA5807M::_readRegisters() 298 | { 299 | Wire.requestFrom (I2C_SEQ, (6 * 2) ); 300 | for (int i = 0; i < 6; i++) { 301 | registers[0xA+i] = _read16(); 302 | } 303 | } // _readRegisters() 304 | 305 | 306 | // Save writable registers back to the chip 307 | // The registers 02 through 06, containing the configuration 308 | // using the sequential write access mode. 309 | void RDA5807M::_saveRegisters() 310 | { 311 | DEBUG_FUNC0("-saveRegisters"); 312 | Wire.beginTransmission(I2C_SEQ); 313 | for (int i = 2; i <= 6; i++) 314 | _write16(registers[i]); 315 | Wire.endTransmission(); 316 | } // _saveRegisters 317 | 318 | 319 | // Save one register back to the chip 320 | void RDA5807M::_saveRegister(byte regNr) 321 | { 322 | DEBUG_FUNC2X("-_saveRegister", regNr, registers[regNr]); 323 | 324 | Wire.beginTransmission(I2C_INDX); 325 | Wire.write(regNr); 326 | _write16(registers[regNr]); 327 | Wire.endTransmission(); 328 | } // _saveRegister 329 | 330 | 331 | 332 | // write a register value using 2 bytes into the Wire. 333 | void RDA5807M::_write16(uint16_t val) 334 | { 335 | Wire.write(val >> 8); Wire.write(val & 0xFF); 336 | } // _write16 337 | 338 | 339 | // read a register value using 2 bytes in a row 340 | uint16_t RDA5807M::_read16(void) 341 | { 342 | uint8_t hiByte = Wire.read(); 343 | uint8_t loByte = Wire.read(); 344 | return(256*hiByte + loByte); 345 | } // _read16 346 | 347 | 348 | // return current Radio Station Strength Information 349 | // uint8_t RDA5807M::getRSSI() { 350 | // _readRegisters(); 351 | // uint8_t rssi = registers[RADIO_REG_RB] >> 10; 352 | // return(rssi); 353 | // } // getRSSI 354 | 355 | 356 | void RDA5807M::checkRDS() 357 | { 358 | // DEBUG_FUNC0("checkRDS"); 359 | 360 | // check RDS data if there is a listener ! 361 | if (_sendRDS) { 362 | 363 | // check register A 364 | Wire.requestFrom (I2C_SEQ, 2); 365 | registers[RADIO_REG_RA] = _read16(); 366 | 367 | if (registers[RADIO_REG_RA] & RADIO_REG_RA_RDSBLOCK) { 368 | DEBUG_STR("BLOCK_E found."); 369 | } // if 370 | 371 | if (registers[RADIO_REG_RA] & RADIO_REG_RA_RDS) { 372 | // check for new RDS data available 373 | uint16_t newData; 374 | bool result = false; 375 | 376 | Wire.beginTransmission(I2C_INDX); // Device 0x11 for random access 377 | Wire.write(RADIO_REG_RDSA); // Start at Register 0x0C 378 | Wire.endTransmission(0); // restart condition 379 | 380 | Wire.requestFrom(I2C_INDX, 8, 1); // Retransmit device address with READ, followed by 8 bytes 381 | newData = _read16(); 382 | if (newData != registers[RADIO_REG_RDSA]) { registers[RADIO_REG_RDSA] = newData; result = true; } 383 | 384 | newData = _read16(); 385 | if (newData != registers[RADIO_REG_RDSB]) { registers[RADIO_REG_RDSB] = newData; result = true; } 386 | 387 | newData = _read16(); 388 | if (newData != registers[RADIO_REG_RDSC]) { registers[RADIO_REG_RDSC] = newData; result = true; } 389 | 390 | newData = _read16(); 391 | if (newData != registers[RADIO_REG_RDSD]) { registers[RADIO_REG_RDSD] = newData; result = true; } 392 | 393 | // _printHex(registers[RADIO_REG_RDSA]); _printHex(registers[RADIO_REG_RDSB]); 394 | // _printHex(registers[RADIO_REG_RDSC]); _printHex(registers[RADIO_REG_RDSD]); 395 | // Serial.println(); 396 | 397 | if (result) { 398 | // new data in the registers 399 | // send to RDS decoder 400 | _sendRDS(registers[RADIO_REG_RDSA], registers[RADIO_REG_RDSB], registers[RADIO_REG_RDSC], registers[RADIO_REG_RDSD]); 401 | } // if 402 | } // if 403 | } 404 | } 405 | 406 | 407 | /// Retrieve all the information related to the current radio receiving situation. 408 | void RDA5807M::getRadioInfo(RADIO_INFO *info) { 409 | 410 | RADIO::getRadioInfo(info); 411 | 412 | // read data from registers A .. F of the chip into class memory 413 | _readRegisters(); 414 | info->active = true; // ??? 415 | if (registers[RADIO_REG_RA] & RADIO_REG_RA_STEREO) info->stereo = true; 416 | if (registers[RADIO_REG_RA] & RADIO_REG_RA_RDS) info->rds = true; 417 | info->rssi = registers[RADIO_REG_RB] >> 10; 418 | if (registers[RADIO_REG_RB] & RADIO_REG_RB_FMTRUE) info->tuned = true; 419 | if (registers[RADIO_REG_CTRL] & RADIO_REG_CTRL_MONO) info->mono = true; 420 | } // getRadioInfo() 421 | 422 | 423 | // ----- Debug functions ----- 424 | 425 | void RDA5807M::debugScan() 426 | { 427 | DEBUG_FUNC0("debugScan"); 428 | uint16_t regChannel = registers[RADIO_REG_CHAN] & (RADIO_REG_CHAN_SPACE | RADIO_REG_CHAN_BAND); 429 | RADIO_FREQ f = _freqLow; 430 | int channel = 0; 431 | 432 | while (f < _freqHigh) { 433 | registers[RADIO_REG_CHAN] = regChannel | RADIO_REG_CHAN_TUNE | (channel << 6); 434 | _saveRegister(RADIO_REG_CHAN); 435 | 436 | delay(500); 437 | debugStatus(); 438 | 439 | f += _freqSteps; 440 | channel += 1; 441 | } // while 442 | } // debugScan 443 | 444 | 445 | // send a status report to the serial port 446 | // dump all registers to Serial output 447 | void RDA5807M::debugStatus() 448 | { 449 | char s[12]; 450 | 451 | // read data from registers A .. F of the chip into class memory 452 | _readRegisters(); 453 | 454 | formatFrequency(s, sizeof(s)); 455 | Serial.print("Frequency="); Serial.print(s); 456 | 457 | uint16_t pi = registers[RADIO_REG_RDSA]; 458 | Serial.print(" PI="); _printHex4(pi); 459 | 460 | Serial.print((registers[RADIO_REG_RA] & RADIO_REG_RA_STEREO) ? " Stereo" : " Mono "); 461 | Serial.print((registers[RADIO_REG_RA] & RADIO_REG_RA_RDS) ? " ---" : " RDS"); 462 | 463 | int rssi = registers[RADIO_REG_RB] >> 10; 464 | 465 | Serial.print(" Sig="); if (rssi < 10) Serial.write(' '); 466 | Serial.print(rssi); 467 | Serial.print(' '); 468 | for(int i = 0;i < rssi - 15;i++) {Serial.write('*');} // Empfangspegel ab 15. Zeichen 469 | Serial.println(); 470 | 471 | // ruler 472 | Serial.println("0 1 2 3 4 5 6 7 8 9 A B C D E F"); 473 | // variables 474 | for (int n = 0; n < 16; n++) { _printHex4(registers[n]); } 475 | Serial.println(); 476 | 477 | // registers 478 | Wire.beginTransmission(I2C_INDX); // Device 0x11 for random access 479 | Wire.write(0x00); // Start at Register 0x0C 480 | Wire.endTransmission(0); // restart condition 481 | Wire.requestFrom(I2C_INDX,32,1); // Retransmit device address with READ, followed by 8 bytes 482 | for (int n = 0; n < 16; n++) { 483 | _printHex4(_read16()); 484 | } 485 | Serial.println(); 486 | 487 | // clear text information in Registers 488 | if (getBassBoost()) Serial.print("BassBoost "); 489 | if (getMono()) Serial.print("Mono "); 490 | int v = getVolume(); 491 | Serial.print("Volume="); Serial.print(v); Serial.print(' '); 492 | Serial.println(); 493 | 494 | } // debugStatus 495 | 496 | 497 | // ----- internal functions ----- 498 | 499 | 500 | // The End. 501 | 502 | 503 | -------------------------------------------------------------------------------- /ScoutMakes FM Breakout StemmaQT/examples/Arduino_RDA5807M_FMradio/src/RDA5807M.h: -------------------------------------------------------------------------------- 1 | /// 2 | /// \file RDA5807M.h 3 | /// \brief Library header file for the radio library to control the RDA5807M radio chip. 4 | /// 5 | /// \author Matthias Hertel, http://www.mathertel.de 6 | /// \copyright Copyright (c) 2014-2015 by Matthias Hertel.\n 7 | /// This work is licensed under a BSD style license.\n 8 | /// See http://www.mathertel.de/License.aspx 9 | /// 10 | /// \details 11 | /// This library enables the use of the Radio Chip RDA5807M from http://www.rdamicro.com/ that supports FM radio bands and RDS data. 12 | /// 13 | /// More documentation and source code is available at http://www.mathertel.de/Arduino 14 | /// 15 | /// History: 16 | /// -------- 17 | /// * 12.05.2014 creation of the RDA5807M library. 18 | /// * 28.06.2014 running simple radio 19 | /// * 08.07.2014 RDS data receive function can be registered. 20 | 21 | // multi-Band enabled 22 | 23 | // - - - - - 24 | // help from: http://arduino.vom-kuhberg.de/index.php 25 | // http://projects.qi-hardware.com/index.php/p/qi-kernel/source/tree/144e9c2530f863e32a3538b06c63484401bbe314/drivers/media/radio/radio-rda5807.c 26 | 27 | 28 | #ifndef RDA5807M_h 29 | #define RDA5807M_h 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | // ----- library definition ----- 36 | 37 | /// Library to control the RDA5807M radio chip. 38 | class RDA5807M : public RADIO { 39 | public: 40 | // ----- RDA5807M specific implementations ----- 41 | const uint8_t MAXVOLUME = 15; ///< max volume level for radio implementations. 42 | 43 | RDA5807M(); 44 | 45 | bool init(); 46 | void term(); 47 | 48 | // ----- Audio features ----- 49 | 50 | void setVolume(uint8_t newVolume); 51 | void setBassBoost(bool switchOn); 52 | void setMono(bool switchOn); 53 | void setMute(bool switchOn); 54 | void setSoftMute(bool switchOn); ///< Set the soft mute mode (mute on low signals) on or off. 55 | 56 | // ----- Receiver features ----- 57 | void setBand(RADIO_BAND newBand); 58 | void setFrequency(RADIO_FREQ newF); 59 | RADIO_FREQ getFrequency(void); 60 | 61 | void seekUp(bool toNextSender = true); // start seek mode upwards 62 | void seekDown(bool toNextSender = true); // start seek mode downwards 63 | 64 | // ----- Supporting RDS for RADIO_BAND_FM and RADIO_BAND_FMWORLD 65 | 66 | void checkRDS(); 67 | 68 | // ----- combined status functions ----- 69 | 70 | virtual void getRadioInfo(RADIO_INFO *info); ///< Retrieve some information about the current radio function of the chip. 71 | 72 | // ----- Supporting RDS for RADIO_BAND_FM and RADIO_BAND_FMWORLD 73 | 74 | // ----- debug Helpers send information to Serial port 75 | 76 | void debugScan(); // Scan all frequencies and report a status 77 | void debugStatus(); // DebugInfo about actual chip data available 78 | 79 | private: 80 | // ----- local variables 81 | uint16_t registers[16]; // memory representation of the registers 82 | 83 | // ----- low level communication to the chip using I2C bus 84 | 85 | void _readRegisters(); // read all status & data registers 86 | void _saveRegisters(); // Save writable registers back to the chip 87 | void _saveRegister(byte regNr); // Save one register back to the chip 88 | 89 | void _write16(uint16_t val); // Write 16 Bit Value on I2C-Bus 90 | uint16_t _read16(void); 91 | }; 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /ScoutMakes FM Breakout StemmaQT/examples/Arduino_RDA5807M_FMradio/src/RDSParser.cpp: -------------------------------------------------------------------------------- 1 | /// 2 | /// \file RDSParser.cpp 3 | /// \brief RDS Parser class implementation. 4 | /// 5 | /// \author Matthias Hertel, http://www.mathertel.de 6 | /// \copyright Copyright (c) 2014 by Matthias Hertel.\n 7 | /// This work is licensed under a BSD style license.\n 8 | /// See http://www.mathertel.de/License.aspx 9 | /// 10 | /// \details 11 | /// 12 | /// More documentation and source code is available at http://www.mathertel.de/Arduino 13 | /// 14 | /// ChangeLog see RDSParser.h. 15 | 16 | #include "RDSParser.h" 17 | 18 | #define DEBUG_FUNC0(fn) { Serial.print(fn); Serial.println("()"); } 19 | 20 | /// Setup the RDS object and initialize private variables to 0. 21 | RDSParser::RDSParser() { 22 | memset(this, 0, sizeof(RDSParser)); 23 | } // RDSParser() 24 | 25 | 26 | void RDSParser::init() { 27 | strcpy(_PSName1, "--------"); 28 | strcpy(_PSName2, _PSName1); 29 | strcpy(programServiceName, " "); 30 | memset(_RDSText, 0, sizeof(_RDSText)); 31 | _lastTextIDX = 0; 32 | } // init() 33 | 34 | 35 | void RDSParser::attachServicenNameCallback(receiveServicenNameFunction newFunction) 36 | { 37 | _sendServiceName = newFunction; 38 | } // attachServicenNameCallback 39 | 40 | void RDSParser::attachTextCallback(receiveTextFunction newFunction) 41 | { 42 | _sendText = newFunction; 43 | } // attachTextCallback 44 | 45 | 46 | void RDSParser::attachTimeCallback(receiveTimeFunction newFunction) 47 | { 48 | _sendTime = newFunction; 49 | } // attachTimeCallback 50 | 51 | 52 | void RDSParser::processData(uint16_t block1, uint16_t block2, uint16_t block3, uint16_t block4) 53 | { 54 | // DEBUG_FUNC0("process"); 55 | uint8_t idx; // index of rdsText 56 | char c1, c2; 57 | char *p; 58 | 59 | uint16_t mins; ///< RDS time in minutes 60 | uint8_t off; ///< RDS time offset and sign 61 | 62 | // Serial.print('('); Serial.print(block1, HEX); Serial.print(' '); Serial.print(block2, HEX); Serial.print(' '); Serial.print(block3, HEX); Serial.print(' '); Serial.println(block4, HEX); 63 | 64 | if (block1 == 0) { 65 | // reset all the RDS info. 66 | init(); 67 | // Send out empty data 68 | if (_sendServiceName) _sendServiceName(programServiceName); 69 | if (_sendText) _sendText(""); 70 | return; 71 | } // if 72 | 73 | // analyzing Block 2 74 | rdsGroupType = 0x0A | ((block2 & 0xF000) >> 8) | ((block2 & 0x0800) >> 11); 75 | rdsTP = (block2 & 0x0400); 76 | rdsPTY = (block2 & 0x0400); 77 | 78 | switch (rdsGroupType) { 79 | case 0x0A: 80 | case 0x0B: 81 | // The data received is part of the Service Station Name 82 | idx = 2 * (block2 & 0x0003); 83 | 84 | // new data is 2 chars from block 4 85 | c1 = block4 >> 8; 86 | c2 = block4 & 0x00FF; 87 | 88 | // check that the data was received successfully twice 89 | // before publishing the station name 90 | 91 | if ((_PSName1[idx] == c1) && (_PSName1[idx + 1] == c2)) { 92 | // retrieved the text a second time: store to _PSName2 93 | _PSName2[idx] = c1; 94 | _PSName2[idx + 1] = c2; 95 | _PSName2[8] = '\0'; 96 | 97 | if ((idx == 6) && strcmp(_PSName1, _PSName2) == 0) { 98 | if (strcmp(_PSName2, programServiceName) != 0) { 99 | // publish station name 100 | strcpy(programServiceName, _PSName2); 101 | if (_sendServiceName) 102 | _sendServiceName(programServiceName); 103 | } // if 104 | } // if 105 | } // if 106 | 107 | if ((_PSName1[idx] != c1) || (_PSName1[idx + 1] != c2)) { 108 | _PSName1[idx] = c1; 109 | _PSName1[idx + 1] = c2; 110 | _PSName1[8] = '\0'; 111 | // Serial.println(_PSName1); 112 | } // if 113 | break; 114 | 115 | case 0x2A: 116 | // The data received is part of the RDS Text. 117 | _textAB = (block2 & 0x0010); 118 | idx = 4 * (block2 & 0x000F); 119 | 120 | if (idx < _lastTextIDX) { 121 | // the existing text might be complete because the index is starting at the beginning again. 122 | // now send it to the possible listener. 123 | if (_sendText) 124 | _sendText(_RDSText); 125 | } 126 | _lastTextIDX = idx; 127 | 128 | if (_textAB != _last_textAB) { 129 | // when this bit is toggled the whole buffer should be cleared. 130 | _last_textAB = _textAB; 131 | memset(_RDSText, 0, sizeof(_RDSText)); 132 | // Serial.println("T>CLEAR"); 133 | } // if 134 | 135 | 136 | // new data is 2 chars from block 3 137 | _RDSText[idx] = (block3 >> 8); idx++; 138 | _RDSText[idx] = (block3 & 0x00FF); idx++; 139 | 140 | // new data is 2 chars from block 4 141 | _RDSText[idx] = (block4 >> 8); idx++; 142 | _RDSText[idx] = (block4 & 0x00FF); idx++; 143 | 144 | // Serial.print(' '); Serial.println(_RDSText); 145 | // Serial.print("T>"); Serial.println(_RDSText); 146 | break; 147 | 148 | case 0x4A: 149 | // Clock time and date 150 | off = (block4)& 0x3F; // 6 bits 151 | mins = (block4 >> 6) & 0x3F; // 6 bits 152 | mins += 60 * (((block3 & 0x0001) << 4) | ((block4 >> 12) & 0x0F)); 153 | 154 | // adjust offset 155 | if (off & 0x20) { 156 | mins -= 30 * (off & 0x1F); 157 | } else { 158 | mins += 30 * (off & 0x1F); 159 | } 160 | 161 | if ((_sendTime) && (mins != _lastRDSMinutes)) { 162 | _lastRDSMinutes = mins; 163 | _sendTime(mins / 60, mins % 60); 164 | } // if 165 | break; 166 | 167 | case 0x6A: 168 | // IH 169 | break; 170 | 171 | case 0x8A: 172 | // TMC 173 | break; 174 | 175 | case 0xAA: 176 | // TMC 177 | break; 178 | 179 | case 0xCA: 180 | // TMC 181 | break; 182 | 183 | case 0xEA: 184 | // IH 185 | break; 186 | 187 | default: 188 | // Serial.print("RDS_GRP:"); Serial.println(rdsGroupType, HEX); 189 | break; 190 | } 191 | } // processData() 192 | 193 | // End. -------------------------------------------------------------------------------- /ScoutMakes FM Breakout StemmaQT/examples/Arduino_RDA5807M_FMradio/src/RDSParser.h: -------------------------------------------------------------------------------- 1 | /// 2 | /// \file RDSParser.h 3 | /// \brief RDS Parser class definition. 4 | /// 5 | /// \author Matthias Hertel, http://www.mathertel.de 6 | /// \copyright Copyright (c) 2014 by Matthias Hertel.\n 7 | /// This work is licensed under a BSD style license.\n 8 | /// See http://www.mathertel.de/License.aspx 9 | /// 10 | /// \details 11 | /// 12 | /// More documentation and source code is available at http://www.mathertel.de/Arduino 13 | /// 14 | /// History: 15 | /// -------- 16 | /// * 01.09.2014 created and RDS sender name working. 17 | /// * 01.11.2014 RDS time added. 18 | /// * 27.03.2015 Reset RDS data by sending a 0 in blockA in the case the frequency changes. 19 | /// 20 | 21 | 22 | #ifndef __RDSPARSER_H__ 23 | #define __RDSPARSER_H__ 24 | 25 | #include 26 | 27 | /// callback function for passing a ServicenName 28 | extern "C" { 29 | typedef void(*receiveServicenNameFunction)(char *name); 30 | typedef void(*receiveTextFunction)(char *name); 31 | typedef void(*receiveTimeFunction)(uint8_t hour, uint8_t minute); 32 | } 33 | 34 | 35 | /// Library for parsing RDS data values and extracting information. 36 | class RDSParser 37 | { 38 | public: 39 | RDSParser(); ///< create a new object from this class. 40 | 41 | /// Initialize internal variables before starting or after a change to another channel. 42 | void init(); 43 | 44 | /// Pass all available RDS data through this function. 45 | void processData(uint16_t block1, uint16_t block2, uint16_t block3, uint16_t block4); 46 | 47 | void attachServicenNameCallback(receiveServicenNameFunction newFunction); ///< Register function for displaying a new Service Name. 48 | void attachTextCallback(receiveTextFunction newFunction); ///< Register the function for displaying a rds text. 49 | void attachTimeCallback(receiveTimeFunction newFunction); ///< Register function for displaying a new time 50 | 51 | private: 52 | // ----- actual RDS values 53 | uint8_t rdsGroupType, rdsTP, rdsPTY; 54 | uint8_t _textAB, _last_textAB, _lastTextIDX; 55 | 56 | // Program Service Name 57 | char _PSName1[10]; // including trailing '\00' character. 58 | char _PSName2[10]; // including trailing '\00' character. 59 | char programServiceName[10]; // found station name or empty. Is max. 8 character long. 60 | 61 | receiveServicenNameFunction _sendServiceName; ///< Registered ServiceName function. 62 | receiveTimeFunction _sendTime; ///< Registered Time function. 63 | receiveTextFunction _sendText; 64 | 65 | uint16_t _lastRDSMinutes; ///< last RDS time send to callback. 66 | 67 | char _RDSText[64 + 2]; 68 | 69 | }; //RDSParser 70 | 71 | #endif //__RDSPARSER_H__ 72 | -------------------------------------------------------------------------------- /ScoutMakes FM Breakout StemmaQT/examples/Arduino_RDA5807M_FMradio/src/newchip.cpp: -------------------------------------------------------------------------------- 1 | /// \file newchip.cpp 2 | /// \brief Implementation for the radio library to control the newchip radio chip. 3 | /// 4 | /// \author Matthias Hertel, http://www.mathertel.de 5 | /// \copyright Copyright (c) 2014-2015 by Matthias Hertel.\n 6 | /// This work is licensed under a BSD style license.\n 7 | /// See http://www.mathertel.de/License.aspx 8 | /// 9 | /// This library enables the use of the Radio Chip newchip. 10 | /// 11 | /// More documentation and source code is available at http://www.mathertel.de/Arduino 12 | /// 13 | /// History: 14 | /// -------- 15 | /// * 05.08.2014 created. 16 | 17 | #include 18 | #include // The chip is controlled via the standard Arduiino Wire library and the IIC/I2C bus. 19 | 20 | #include // Include the common radio library interface 21 | #include 22 | 23 | // ----- Definitions for the Wire communication 24 | 25 | #define newchip_ADR 0x10 // I2C address of newchip 26 | 27 | // ----- Radio chip specific definitions including the registers 28 | 29 | // // Use this define to setup European FM specific settings in the chip. 30 | // #define IN_EUROPE 31 | // 32 | // // int STATUS_LED = 13; 33 | // #define resetPin 2 34 | // // SDA/A4 on Arduino 35 | // #define SDIO A4 36 | // // int SCLK = A5; //SCL/A5 on Arduino 37 | // 38 | // // Register Definitions ----- 39 | // 40 | // //Define the register names 41 | // #define DEVICEID 0x00 42 | // #define CHIPID 0x01 43 | // #define POWERCFG 0x02 44 | // #define CHANNEL 0x03 45 | // #define SYSCONFIG1 0x04 46 | // #define SYSCONFIG2 0x05 47 | // #define STATUSRSSI 0x0A 48 | // #define READCHAN 0x0B 49 | // #define RDSA 0x0C 50 | // #define RDSB 0x0D 51 | // #define RDSC 0x0E 52 | // #define RDSD 0x0F 53 | // 54 | // //Register 0x02 - POWERCFG 55 | // #define SMUTE 15 56 | // #define DMUTE 14 57 | // #define SKMODE 10 58 | // #define SEEKUP 9 59 | // #define SEEK 8 60 | // 61 | // //Register 0x03 - CHANNEL 62 | // #define TUNE 15 63 | // 64 | // //Register 0x04 - SYSCONFIG1 65 | // #define RDS 12 66 | // #define DE 11 67 | // 68 | // #define DE 11 69 | // 70 | // 71 | // //Register 0x05 - SYSCONFIG2 72 | // #define SPACE1 5 73 | // #define SPACE0 4 74 | // 75 | // //Register 0x0A - STATUSRSSI 76 | // #define RDSR 15 77 | // #define STC 14 78 | // #define SFBL 13 79 | // #define AFCRL 12 80 | // #define RDSS 11 81 | // #define STEREO 8 82 | 83 | // ----- implement 84 | 85 | // initialize the extra variables in SI4703 86 | newchip::newchip() { 87 | } 88 | 89 | // initialize all internals. 90 | bool newchip::init() { 91 | bool result = false; // no chip found yet. 92 | DEBUG_FUNC0("init"); 93 | 94 | return(result); 95 | } // init() 96 | 97 | 98 | // switch the power off 99 | void newchip::term() 100 | { 101 | DEBUG_FUNC0("term"); 102 | } // term 103 | 104 | 105 | // ----- Volume control ----- 106 | 107 | void newchip::setVolume(uint8_t newVolume) 108 | { 109 | DEBUG_FUNC0("setVolume"); 110 | } // setVolume() 111 | 112 | 113 | void newchip::setBassBoost(bool switchOn) 114 | { 115 | DEBUG_FUNC0("setBassBoost"); 116 | } // setBassBoost() 117 | 118 | 119 | // Mono / Stereo 120 | void newchip::setMono(bool switchOn) 121 | { 122 | DEBUG_FUNC0("setMono"); 123 | } // setMono 124 | 125 | 126 | // Switch mute mode. 127 | void newchip::setMute(bool switchOn) 128 | { 129 | DEBUG_FUNC0("setMute"); 130 | } // setMute() 131 | 132 | 133 | // ----- Band and frequency control methods ----- 134 | 135 | // tune to new band. 136 | void newchip::setBand(RADIO_BAND newBand) { 137 | } // setBand() 138 | 139 | 140 | /** 141 | * @brief Retrieve the real frequency from the chip after automatic tuning. 142 | * @return RADIO_FREQ the current frequency. 143 | */ 144 | RADIO_FREQ newchip::getFrequency() { 145 | return (_freq); 146 | } // getFrequency 147 | 148 | 149 | /** 150 | * @brief Change the frequency in the chip. 151 | * @param newF 152 | * @return void 153 | */ 154 | void newchip::setFrequency(RADIO_FREQ newF) { 155 | DEBUG_FUNC1("setFrequency", newF); 156 | } // setFrequency() 157 | 158 | 159 | // start seek mode upwards 160 | void newchip::seekUp(bool toNextSender) { 161 | DEBUG_FUNC0("seekUp"); 162 | _seek(true); 163 | } // seekUp() 164 | 165 | 166 | // start seek mode downwards 167 | void newchip::seekDown(bool toNextSender) { 168 | _seek(false); 169 | } // seekDown() 170 | 171 | 172 | 173 | // Load all status registers from to the chip 174 | void newchip::_readRegisters() 175 | { 176 | } 177 | 178 | 179 | // Save writable registers back to the chip 180 | // using the sequential write access mode. 181 | void newchip::_saveRegisters() 182 | { 183 | } // _saveRegisters 184 | 185 | 186 | // write a register value using 2 bytes into the Wire. 187 | void newchip::_write16(uint16_t val) 188 | { 189 | Wire.write(val >> 8); Wire.write(val & 0xFF); 190 | } // _write16 191 | 192 | 193 | // read a register value using 2 bytes in a row 194 | uint16_t newchip::_read16(void) 195 | { 196 | uint8_t hiByte = Wire.read(); 197 | uint8_t loByte = Wire.read(); 198 | return((hiByte << 8) + loByte); 199 | } // _read16 200 | 201 | 202 | void newchip::getRadioInfo(RADIO_INFO *info) { 203 | RADIO::getRadioInfo(info); 204 | } // getRadioInfo() 205 | 206 | 207 | void newchip::getAudioInfo(AUDIO_INFO *info) { 208 | RADIO::getAudioInfo(info); 209 | } // getAudioInfo() 210 | 211 | 212 | void newchip::checkRDS() 213 | { 214 | // DEBUG_FUNC0("checkRDS"); 215 | } // checkRDS 216 | 217 | // ----- Debug functions ----- 218 | 219 | /// Send the current values of all registers to the Serial port. 220 | void newchip::debugStatus() 221 | { 222 | RADIO::debugStatus(); 223 | } // debugStatus 224 | 225 | 226 | /// Seeks out the next available station 227 | void newchip::_seek(bool seekUp) { 228 | DEBUG_FUNC0("_seek"); 229 | } // _seek 230 | 231 | 232 | /// wait until the current seek and tune operation is over. 233 | void newchip::_waitEnd() { 234 | DEBUG_FUNC0("_waitEnd"); 235 | 236 | } // _waitEnd() 237 | 238 | 239 | 240 | // ----- internal functions ----- 241 | 242 | // The End. 243 | 244 | 245 | -------------------------------------------------------------------------------- /ScoutMakes FM Breakout StemmaQT/examples/Arduino_RDA5807M_FMradio/src/newchip.h: -------------------------------------------------------------------------------- 1 | /// 2 | /// \file newchip.h 3 | /// \brief Library header file for the radio library to control the newchip radio chip. 4 | /// 5 | /// \author Matthias Hertel, http://www.mathertel.de 6 | /// \copyright Copyright (c) 2014-2015 by Matthias Hertel.\n 7 | /// This work is licensed under a BSD style license.\n 8 | /// See http://www.mathertel.de/License.aspx 9 | /// 10 | /// This library can be used as a starting point to implement a new radio chip for the radio library. 11 | /// 12 | /// More documentation and source code is available at http://www.mathertel.de/Arduino 13 | /// 14 | /// History: 15 | /// -------- 16 | /// * 05.08.2014 created. 17 | 18 | 19 | #ifndef newchip_h 20 | #define newchip_h 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | // ----- library definition ----- 28 | 29 | 30 | /// Template library control a new radio chip. 31 | class newchip : public RADIO { 32 | public: 33 | const uint8_t MAXVOLUME = 15; ///< max volume level for radio implementations. 34 | newchip(); 35 | 36 | bool init(); // initialize library and the chip. 37 | void term(); // terminate all radio functions. 38 | 39 | // Control of the audio features 40 | 41 | // Control the volume output of the radio chip 42 | void setVolume(uint8_t newVolume); // set volume to 0..15 43 | 44 | // Control the bass boost function of the radio chip 45 | void setBassBoost(bool switchOn); 46 | 47 | // Control mono/stereo mode of the radio chip 48 | void setMono(bool switchOn); // Switch to mono mode. 49 | 50 | // Control the mute function of the radio chip 51 | void setMute(bool switchOn); // Switch to mute mode. 52 | 53 | // Control of the core receiver 54 | 55 | // Control the frequency 56 | void setBand(RADIO_BAND newBand); 57 | 58 | void setFrequency(RADIO_FREQ newF); 59 | RADIO_FREQ getFrequency(void); 60 | 61 | void seekUp(bool toNextSender = true); // start seek mode upwards 62 | void seekDown(bool toNextSender = true); // start seek mode downwards 63 | 64 | void checkRDS(); // read RDS data from the current station and process when data available. 65 | 66 | void getRadioInfo(RADIO_INFO *info); 67 | void getAudioInfo(AUDIO_INFO *info); 68 | 69 | // ----- debug Helpers send information to Serial port 70 | 71 | void debugScan(); // Scan all frequencies and report a status 72 | void debugStatus(); // Report Info about actual Station 73 | 74 | // ----- read/write registers of the chip 75 | 76 | void _readRegisters(); // read all status & data registers 77 | void _saveRegisters(); // Save writable registers back to the chip 78 | 79 | private: 80 | // ----- local variables 81 | 82 | // store the current values of the 16 chip internal 16-bit registers 83 | // uint16_t registers[16]; 84 | 85 | // ----- low level communication to the chip using I2C bus 86 | 87 | void _write16(uint16_t val); // Write 16 Bit Value on I2C-Bus 88 | uint16_t _read16(void); 89 | 90 | void _seek(bool seekUp = true); 91 | void _waitEnd(); 92 | }; 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /ScoutMakes FM Breakout StemmaQT/examples/Arduino_RDA5807M_FMradio/src/radio.cpp: -------------------------------------------------------------------------------- 1 | /// \file Radio.cpp 2 | /// \brief Library implementation for the radio libraries to control radio chips. 3 | /// 4 | /// \author Matthias Hertel, http://www.mathertel.de 5 | /// \copyright Copyright (c) 2014 by Matthias Hertel.\n 6 | /// This work is licensed under a BSD style license.\n 7 | /// See http://www.mathertel.de/License.aspx 8 | /// 9 | /// \details 10 | /// This library enables the use of diverse radio chips by sharing the same class definition. 11 | /// Implementation for the following Radio Chips are available: 12 | /// * RDA5807M 13 | /// * SI4703 14 | /// 15 | /// The following chip is planned to be supported too: 16 | /// * TEA5767 17 | /// 18 | /// More documentation and source code is available at http://www.mathertel.de/Arduino 19 | /// 20 | /// ChangeLog see: radio.h 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | 27 | // ----- Register Definitions ----- 28 | 29 | // no chip-registers without a chip. 30 | 31 | // ----- implement 32 | 33 | /// Setup the radio object and initialize private variables to 0. 34 | /// Don't change the radio chip (yet). 35 | RADIO::RADIO() 36 | { 37 | memset(this, 0, sizeof(RADIO)); 38 | } // RADIO() 39 | 40 | 41 | void RADIO::setup(int feature, int value) 42 | { 43 | if (feature == RADIO_RESETPIN) { 44 | _resetPin = value; 45 | } else if ((feature == RADIO_I2CADDRESS) && (value > 0)) { 46 | _i2caddr = value; 47 | } else if ((feature == RADIO_ANTENNA) && (value > 0)) { 48 | _antennaOption = value; 49 | } 50 | 51 | } // setup() 52 | 53 | 54 | /// The RADIO class doesn't implement a concrete chip so nothing has to be initialized. 55 | bool RADIO::initWire(TwoWire &port) 56 | { 57 | DEBUG_FUNC0("RADIO::initWire"); 58 | 59 | _i2cPort = &port; 60 | return (this->init()); 61 | } // initWire() 62 | 63 | 64 | /// The RADIO class doesn't implement a concrete chip so nothing has to be initialized. 65 | bool RADIO::init() 66 | { 67 | if (_resetPin >= 0) { 68 | // create a reset impulse 69 | pinMode(_resetPin, OUTPUT); 70 | digitalWrite(_resetPin, LOW); // Put chip into reset 71 | delay(5); 72 | digitalWrite(_resetPin, HIGH); // Bring chip out of reset 73 | delay(5); 74 | } 75 | return (false); 76 | } // init() 77 | 78 | 79 | /// The RADIO class doesn't implement a concrete chip so nothing has to be initialized. 80 | void RADIO::term() 81 | { 82 | } // term() 83 | 84 | 85 | // ----- Volume control ----- 86 | 87 | void RADIO::setVolume(uint8_t newVolume) 88 | { 89 | _volume = newVolume; 90 | } // setVolume() 91 | 92 | 93 | uint8_t RADIO::getVolume() 94 | { 95 | return (_volume); 96 | } // getVolume() 97 | 98 | 99 | // ----- bass boost control ----- 100 | 101 | /// Control the bass boost mode of the radio chip. 102 | /// The base implementation ony stores the value to the internal variable. 103 | /// @param switchOn true to switch bassBoost mode on, false to switch bassBoost mode off. 104 | void RADIO::setBassBoost(bool switchOn) 105 | { 106 | DEBUG_FUNC1("setBassBoost", switchOn); 107 | _bassBoost = switchOn; 108 | } // setBassBoost() 109 | 110 | 111 | /// Retrieve the current bass boost mode setting. 112 | /// The base implementation returns only the value in the internal variable. 113 | bool RADIO::getBassBoost() 114 | { 115 | return (_bassBoost); 116 | } // getBassBoost() 117 | 118 | 119 | // ----- mono control ----- 120 | 121 | /// The base implementation ony stores the value to the internal variable. 122 | void RADIO::setMono(bool switchOn) 123 | { 124 | DEBUG_FUNC1("setMono", switchOn); 125 | _mono = switchOn; 126 | } // setMono() 127 | 128 | 129 | /// The base implementation returns only the value in the internal variable. 130 | bool RADIO::getMono() 131 | { 132 | return (_mono); 133 | } // getMono() 134 | 135 | 136 | // ----- mute control ----- 137 | 138 | /// The base implementation ony stores the value to the internal variable. 139 | void RADIO::setMute(bool switchOn) 140 | { 141 | _mute = switchOn; 142 | } // setMute() 143 | 144 | 145 | /// The base implementation returns only the value in the internal variable. 146 | bool RADIO::getMute() 147 | { 148 | return (_mute); 149 | } // getMute() 150 | 151 | 152 | // ----- softmute control ----- 153 | 154 | /// The base implementation ony stores the value to the internal variable. 155 | void RADIO::setSoftMute(bool switchOn) 156 | { 157 | DEBUG_FUNC1("setSoftMute", switchOn); 158 | _softMute = switchOn; 159 | } // setSoftMute() 160 | 161 | 162 | /// The base implementation returns only the value in the internal variable. 163 | bool RADIO::getSoftMute() 164 | { 165 | return (_softMute); 166 | } // getSoftMute() 167 | 168 | 169 | // ----- receiver control ----- 170 | 171 | // some implementations to return internal variables if used by concrete chip implementations 172 | 173 | /// Start using the new band for receiving. 174 | void RADIO::setBand(RADIO_BAND newBand) 175 | { 176 | DEBUG_FUNC1("setBand", newBand); 177 | _band = newBand; 178 | if (newBand == RADIO_BAND_FM) { 179 | _freqLow = 8700; 180 | _freqHigh = 10800; 181 | _freqSteps = 10; // 20 in USA ??? 182 | 183 | } else if (newBand == RADIO_BAND_FMWORLD) { 184 | _freqLow = 7600; 185 | _freqHigh = 10800; 186 | _freqSteps = 10; 187 | } // if 188 | } // setBand() 189 | 190 | 191 | /// Start using the new frequency for receiving. 192 | /// The new frequency is stored for later retrieval. 193 | void RADIO::setFrequency(RADIO_FREQ newFreq) 194 | { 195 | DEBUG_FUNC1("setFrequency", newFreq); 196 | _freq = newFreq; 197 | } // setFrequency() 198 | 199 | 200 | void RADIO::setBandFrequency(RADIO_BAND newBand, RADIO_FREQ newFreq) 201 | { 202 | setBand(newBand); 203 | setFrequency(newFreq); 204 | } // setBandFrequency() 205 | 206 | 207 | void RADIO::seekUp(bool) {} 208 | void RADIO::seekDown(bool) {} 209 | 210 | RADIO_BAND RADIO::getBand() 211 | { 212 | return (_band); 213 | } 214 | RADIO_FREQ RADIO::getFrequency() 215 | { 216 | return (_freq); 217 | } 218 | RADIO_FREQ RADIO::getMinFrequency() 219 | { 220 | return (_freqLow); 221 | } 222 | RADIO_FREQ RADIO::getMaxFrequency() 223 | { 224 | return (_freqHigh); 225 | } 226 | RADIO_FREQ RADIO::getFrequencyStep() 227 | { 228 | return (_freqSteps); 229 | } 230 | 231 | 232 | /// Return all the Radio settings. 233 | /// This implementation only knows some values from the last settings. 234 | void RADIO::getRadioInfo(RADIO_INFO *info) 235 | { 236 | // set everything to false and 0. 237 | memset(info, 0, sizeof(RADIO_INFO)); 238 | // info->tuned = false; 239 | // info->rds = false; 240 | // info->stereo = false; 241 | 242 | // use current settings 243 | info->mono = _mono; 244 | 245 | } // getRadioInfo() 246 | 247 | 248 | /// Return current settings as far as no chip is required. 249 | /// When using the radio::setXXX methods, no chip specific implementation is needed. 250 | void RADIO::getAudioInfo(AUDIO_INFO *info) 251 | { 252 | // set everything to false and 0. 253 | memset(info, 0, sizeof(AUDIO_INFO)); 254 | 255 | // use current settings 256 | info->volume = _volume; 257 | info->mute = _mute; 258 | info->softmute = _softMute; 259 | info->bassBoost = _bassBoost; 260 | } // getAudioInfo() 261 | 262 | 263 | /// In the general radio implementation there is no chip for RDS. 264 | /// This function needs to be implemented for radio chips with RDS receiving functionality. 265 | void RADIO::checkRDS() 266 | { /* no chip : nothing to check */ 267 | } 268 | 269 | 270 | /// Send a 0.0.0.0 to the RDS receiver if there is any attached. 271 | /// This is to point out that there is a new situation and all existing data should be invalid from now on. 272 | void RADIO::clearRDS() 273 | { 274 | if (_sendRDS) 275 | _sendRDS(0, 0, 0, 0); 276 | } // clearRDS() 277 | 278 | 279 | // send valid and good data to the RDS processor via newFunction 280 | // remember the RDS function 281 | void RADIO::attachReceiveRDS(receiveRDSFunction newFunction) 282 | { 283 | _sendRDS = newFunction; 284 | } // attachReceiveRDS() 285 | 286 | 287 | // format the current frequency for display and printing 288 | void RADIO::formatFrequency(char *s, uint8_t length) 289 | { 290 | RADIO_BAND b = getBand(); 291 | RADIO_FREQ f = getFrequency(); 292 | 293 | if ((s != NULL) && (length > 10)) { 294 | *s = '\0'; 295 | 296 | if ((b == RADIO_BAND_FM) || (b == RADIO_BAND_FMWORLD)) { 297 | // " ff.ff MHz" or "fff.ff MHz" 298 | int16_to_s(s, (uint16_t)f); 299 | 300 | // insert decimal point 301 | s[5] = s[4]; 302 | s[4] = s[3]; 303 | s[3] = '.'; 304 | 305 | // append units 306 | strcpy(s + 6, " MHz"); 307 | } // if 308 | 309 | // f = _freqLow + (channel * _bandSteps); 310 | // if (f < 10000) Serial.write(' '); 311 | // Serial.print(f / 100); Serial.print('.'); Serial.print(f % 100); Serial.print(" MHz "); 312 | } // if 313 | 314 | } // formatFrequency() 315 | 316 | 317 | /** 318 | * Enable debugging information on Serial port. 319 | * This is for logging on a higher level than i2c data transport. 320 | * @param enable true to switch logging on. 321 | */ 322 | void RADIO::debugEnable(bool enable) 323 | { 324 | _debugEnabled = enable; 325 | } // debugEnable() 326 | 327 | 328 | // print out all radio information 329 | void RADIO::debugRadioInfo() 330 | { 331 | RADIO_INFO info; 332 | this->getRadioInfo(&info); 333 | 334 | Serial.print(info.rds ? " RDS" : " ---"); 335 | Serial.print(info.tuned ? " TUNED" : " -----"); 336 | Serial.print(info.stereo ? " STEREO" : " MONO "); 337 | Serial.print(" RSSI: "); 338 | Serial.print(info.rssi); 339 | Serial.print(" SNR: "); 340 | Serial.print(info.snr); 341 | Serial.println(); 342 | } // debugRadioInfo() 343 | 344 | 345 | // print out all audio information 346 | void RADIO::debugAudioInfo() 347 | { 348 | AUDIO_INFO info; 349 | this->getAudioInfo(&info); 350 | 351 | Serial.print(info.mute ? " MUTE" : " ----"); 352 | Serial.print(info.softmute ? " SOFTMUTE" : " --------"); 353 | Serial.print(info.bassBoost ? " BASS" : " ----"); 354 | Serial.println(); 355 | } // debugAudioInfo() 356 | 357 | 358 | /// The RADIO class doesn't have interesting status information so nothing is sent. 359 | void RADIO::debugStatus() 360 | { 361 | // no output. 362 | } // debugStatus 363 | 364 | 365 | /// This is a special format routine used to format frequencies as strings with leading blanks. 366 | /// up to 5 digits only (" 0".."99999") 367 | /// *s MUST be able to hold the characters 368 | void RADIO::int16_to_s(char *s, uint16_t val) 369 | { 370 | uint8_t n = 5; 371 | 372 | while (n > 0) { 373 | n--; 374 | if ((n == 4) || (val > 0)) { 375 | s[n] = '0' + (val % 10); 376 | val = val / 10; 377 | } else { 378 | s[n] = ' '; 379 | } 380 | } // while 381 | } // int16_to_s() 382 | 383 | 384 | // ===== Wire Utilities ===== 385 | 386 | bool RADIO::_wireDebugFlag = false; 387 | 388 | /** 389 | * Enable low level i2c debugging information on Serial port. 390 | * @param enable true to switch logging on. 391 | */ 392 | void RADIO::_wireDebug(bool enable) 393 | { 394 | _wireDebugEnabled = enable; 395 | _wireDebugFlag = enable; 396 | } // _wireDebug() 397 | 398 | 399 | bool RADIO::_wireExists(TwoWire *port, int address) 400 | { 401 | port->beginTransmission(address); 402 | uint8_t err = port->endTransmission(); 403 | if (_wireDebugEnabled) { 404 | Serial.print("_wireExists("); 405 | Serial.print(address); 406 | Serial.print("): err="); 407 | Serial.println(err); 408 | } 409 | return (err == 0); 410 | } 411 | 412 | // a i2c transmission in one call 413 | void RADIO::_wireWriteTo(TwoWire *port, int address, uint8_t *cmdData, int cmdLen) 414 | { 415 | if (cmdData && cmdLen > 0) { 416 | // send out command sequence 417 | port->beginTransmission(address); 418 | if (_wireDebugFlag) { 419 | Serial.print("--write("); 420 | Serial.print(address); 421 | Serial.print("): "); 422 | } 423 | 424 | for (int i = 0; i < cmdLen; i++) { 425 | uint8_t d = cmdData[i]; 426 | port->write(d); 427 | if (_wireDebugFlag) { 428 | // write a hex value to Serial 429 | if (d < 16) Serial.print('0'); 430 | Serial.print(d, 16); 431 | Serial.print(' '); 432 | } // if 433 | } // for 434 | 435 | port->endTransmission(); 436 | } // if 437 | } // _wireWriteTo 438 | 439 | 440 | // a i2c request in one call 441 | uint8_t RADIO::_wireReadFrom(TwoWire *port, int address, uint8_t *data, int len) 442 | { 443 | uint8_t received = 0; 444 | if (data && len > 0) { 445 | while (!received) { 446 | received = port->requestFrom(address, len); 447 | if (_wireDebugFlag) { 448 | Serial.print('['); 449 | Serial.print(received); 450 | Serial.print(']'); 451 | } 452 | } 453 | 454 | uint8_t *d = data; 455 | for (int n = 0; n < received; n++) { 456 | *d = port->read(); 457 | if (_wireDebugFlag) { 458 | // write a hex value to Serial 459 | if (*d < 16) Serial.print('0'); 460 | Serial.print(*d, 16); 461 | Serial.print(' '); 462 | } 463 | d++; 464 | } 465 | } 466 | return (received); 467 | } // _wireReadFrom 468 | 469 | 470 | // write a 16 bit value in High-Low order to the Wire. 471 | void RADIO::_write16HL(TwoWire *port, uint16_t val) 472 | { 473 | port->write(val >> 8); 474 | port->write(val & 0xFF); 475 | } // _write16HL 476 | 477 | 478 | // read a 16 bit value in High-Low order from the Wire. 479 | uint16_t RADIO::_read16HL(TwoWire *port) 480 | { 481 | uint8_t hiByte = port->read(); 482 | uint8_t loByte = port->read(); 483 | return ((hiByte << 8) + loByte); 484 | } // _read16HL 485 | 486 | 487 | /** 488 | * Write and optionally read data on the i2c bus. 489 | * A debug output can be enabled using _wireDebug(). 490 | * @param port i2c port to be used. 491 | * @param address i2c address to be used. 492 | * @param reg the register to be read (1 byte send). 493 | * @param data buffer array with received data. If this parameter is nullptr no data will be requested. 494 | * @param len length of data buffer. 495 | * @return number of register values received. 496 | */ 497 | int RADIO::_wireRead(TwoWire *port, int address, uint8_t reg, uint8_t *data, int len) 498 | { 499 | return (_wireRead(port, address, ®, 1, data, len)); 500 | } // _wireRead() 501 | 502 | 503 | /** 504 | * Write and optionally read data on the i2c bus. 505 | * A debug output can be enabled using _wireDebug(). 506 | * @param port i2c port to be used. 507 | * @param address i2c address to be used. 508 | * @param cmdData array with data to be send. 509 | * @param cmdLen length of cmdData. 510 | * @param data buffer array with received data. If this parameter is nullptr no data will be requested. 511 | * @param len length of data buffer. 512 | * @return number of register values received. 513 | */ 514 | int RADIO::_wireRead(TwoWire *port, int address, uint8_t *cmdData, int cmdLen, uint8_t *data, int len) 515 | { 516 | int received = 0; 517 | 518 | RADIO::_wireWriteTo(port, address, cmdData, cmdLen); 519 | 520 | // read requested data (when buffer is available) 521 | if (data) { 522 | while (received == 0) { 523 | if (RADIO::_wireDebugFlag) { 524 | Serial.print(" -> "); 525 | } 526 | received = RADIO::_wireReadFrom(port, address, data, len); 527 | if (!(*data & 0x80)) 528 | received = 0; 529 | } 530 | 531 | if (RADIO::_wireDebugFlag) { 532 | Serial.println('.'); 533 | } 534 | } // if (data) 535 | 536 | return (received); 537 | } // _wireRead() 538 | 539 | 540 | /// Prints a byte as 2 character hexadecimal code with leading zeros. 541 | void RADIO::_printHex2(uint8_t val) 542 | { 543 | Serial.print(' '); 544 | if (val <= 0x000F) 545 | Serial.print('0'); // if less 2 Digit 546 | Serial.print(val, HEX); 547 | } // _printHex2 548 | 549 | 550 | /// Prints a word as 4 character hexadecimal code with leading zeros. 551 | void RADIO::_printHex4(uint16_t val) 552 | { 553 | Serial.print(' '); 554 | if (val <= 0x000F) 555 | Serial.print('0'); // if less 2 Digit 556 | if (val <= 0x00FF) 557 | Serial.print('0'); // if less 3 Digit 558 | if (val <= 0x0FFF) 559 | Serial.print('0'); // if less 4 Digit 560 | Serial.print(val, HEX); 561 | } // _printHex4 562 | 563 | // The End. 564 | -------------------------------------------------------------------------------- /ScoutMakes FM Breakout StemmaQT/examples/Arduino_RDA5807M_FMradio/src/radio.h: -------------------------------------------------------------------------------- 1 | /// 2 | /// \file Radio.h 3 | /// \brief Library header file for the radio libraries to control radio chips. 4 | /// 5 | /// \author Matthias Hertel, http://www.mathertel.de 6 | /// \copyright Copyright (c) 2014 by Matthias Hertel.\n 7 | /// This work is licensed under a BSD style license.\n 8 | /// See http://www.mathertel.de/License.aspx 9 | /// 10 | /// \details 11 | /// This library enables the use of diverse radio chips by sharing the same class definition. 12 | /// Implementation for the following Radio Chips are available: 13 | /// * RDA5807M 14 | /// * SI4703 15 | /// * TEA5767 16 | /// 17 | /// The following chip is planned to be supported too: 18 | /// ... 19 | /// 20 | /// More documentation and source code is available at http://www.mathertel.de/Arduino 21 | /// 22 | /// ChangeLog: 23 | /// ---------- 24 | /// * 08.07.2014 creation of the common radio class. 25 | /// * 15.07.2014 examples working with RDA5807M. 26 | /// * 26.08.2014 examples working with SI4703. 27 | /// * 31.08.2014 Doxygen style comments added. 28 | /// * 05.02.2015 mainpage content added. 29 | /// * 29.04.2015 clear RDS function, need to clear RDS info after tuning. 30 | /// * 17.09.2020 Wire Util functions added. 31 | /// * 06.12.2020 I2C Wire and Reset initialization centralized. 32 | 33 | /// TODO: 34 | /// -------- 35 | /// * multi-Band enabled 36 | 37 | /// \mainpage 38 | /// An Arduino library to control radio for receiving FM broadcast signals. 39 | /// 40 | /// Currently the following chips are supported: 41 | /// * The SI4703 from Silicon Labs 42 | /// * The SI4705 from Silicon Labs 43 | /// * The SI4721 from Silicon Labs 44 | /// * The TEA5767 from NXP 45 | /// * The RDA5807M from RDA Microelectronics 46 | /// 47 | /// They all are capable for receiving FM radio stations in stereo with European and US settings and can be controlled by using the I2C bus.However there are differences in the sensitivity and quality and well on receiving RDS information from the stations. 48 | /// 49 | /// For each of these chips a specific library is implemented that knows how to communicate with the chip using the I2C bus and the wire library.These libraries all share a common base, the radio library so that all the common code is only implemented once in there : 50 | /// 51 | /// All the libraries share the same interface (defined by the radio library) so it is possible to exchange them when not using one of the chip specific functions. 52 | /// 53 | 54 | 55 | #ifndef __RADIO_h__ 56 | #define __RADIO_h__ 57 | 58 | #include 59 | #include 60 | 61 | // The DEBUG_xxx Macros enable Information to the Serial port. 62 | // They can be enabled by setting the _debugEnabled variable to true disabled by using the debugEnable function. 63 | // When the code has to be minimized they can be redefined without implementation like: 64 | // #define DEBUG_STR(txt) {} 65 | 66 | /// Used for Debugging text information. 67 | #define DEBUG_STR(txt) if (_debugEnabled) { Serial.print('>'); Serial.println(txt); } 68 | 69 | /// Used for Debugging function entries without parameters. 70 | #define DEBUG_VAL(label, val) if (_debugEnabled) { Serial.print('>'); Serial.print(label); Serial.print(':'); Serial.println(val); } 71 | #define DEBUG_VALX(label, val) if (_debugEnabled) { Serial.print('>'); Serial.print(label); Serial.print(':'); Serial.println(val, HEX); } 72 | 73 | /// Used for Debugging function entries without parameters. 74 | #define DEBUG_FUNC0(fn) if (_debugEnabled) { Serial.print('>'); Serial.print(fn); Serial.println("()"); } 75 | 76 | /// Used for Debugging function entries with 1 parameter. 77 | #define DEBUG_FUNC1(fn, p1) if (_debugEnabled) { Serial.print('>'); Serial.print(fn); Serial.print('('); Serial.print(p1); Serial.println(')'); } 78 | 79 | /// Used for Debugging function entries with 1 parameters as hex Value. 80 | #define DEBUG_FUNC1X(fn, p1) if (_debugEnabled) { Serial.print('>'); Serial.print(fn); Serial.print("(0x"); Serial.print(p1, HEX); Serial.println(')'); } 81 | 82 | /// Used for Debugging function entries with 2 parameters. 83 | #define DEBUG_FUNC2(fn, p1, p2) if (_debugEnabled) { Serial.print('>'); Serial.print(fn); Serial.print('('); Serial.print(p1); Serial.print(", "); Serial.print(p2); Serial.println(')'); } 84 | 85 | /// Used for Debugging function entries with 2 parameters and Hex Value. 86 | #define DEBUG_FUNC2X(fn, p1, p2) if (_debugEnabled) { Serial.print('>'); Serial.print(fn); Serial.print("(0x"); Serial.print(p1, HEX); Serial.print(", 0x"); Serial.print(p2, HEX); Serial.println(')'); } 87 | 88 | 89 | // ----- Callback function types ----- 90 | 91 | /// callback function for passing RDS data. 92 | extern "C" { 93 | typedef void (*receiveRDSFunction)(uint16_t block1, uint16_t block2, uint16_t block3, uint16_t block4); 94 | } 95 | 96 | 97 | // ----- type definitions ----- 98 | 99 | /// Band datatype. 100 | /// The BANDs a receiver probably can implement. 101 | enum RADIO_BAND { 102 | RADIO_BAND_NONE = 0, ///< No band selected. 103 | 104 | RADIO_BAND_FM = 0x01, ///< FM band 87.5 - 108 MHz (USA, Europe) selected. 105 | RADIO_BAND_FMWORLD = 0x02, ///< FM band 76 - 108 MHz (Japan, Worldwide) selected. 106 | RADIO_BAND_AM = 0x03, ///< AM band selected. 107 | RADIO_BAND_KW = 0x04, ///< KW band selected. 108 | 109 | RADIO_BAND_FMTX = 0x11, ///< Transmit for FM. 110 | }; 111 | 112 | 113 | /// Frequency data type. 114 | /// Only 16 bits are used for any frequency value (not the real one) 115 | typedef uint16_t RADIO_FREQ; 116 | 117 | 118 | /// A structure that contains information about the radio features from the chip. 119 | typedef struct RADIO_INFO { 120 | bool active; ///< receiving is active. 121 | uint8_t rssi; ///< Radio Station Strength Information. 122 | uint8_t snr; ///< Signal Noise Ratio. 123 | bool rds; ///< RDS information is available. 124 | bool tuned; ///< A stable frequency is tuned. 125 | bool mono; ///< Mono mode is on. 126 | bool stereo; ///< Stereo audio is available 127 | }; 128 | 129 | 130 | /// a structure that contains information about the audio features 131 | typedef struct AUDIO_INFO { 132 | uint8_t volume; 133 | bool mute; 134 | bool softmute; 135 | bool bassBoost; 136 | }; 137 | 138 | // ----- common RADIO class definition ----- 139 | 140 | #define RADIO_RESETPIN 0x01 141 | #define RADIO_SDAPIN 0x02 142 | #define RADIO_I2CADDRESS 0x03 143 | #define RADIO_ANTENNA 0x04 144 | #define RADIO_ANTENNA_DEFAULT 0 145 | #define RADIO_ANTENNA_OPT1 1 146 | #define RADIO_ANTENNA_OPT2 2 147 | 148 | 149 | /// Library to control radio chips in general. This library acts as a base library for the chip specific implementations. 150 | class RADIO { 151 | 152 | public: 153 | const uint8_t MAXVOLUME = 15; ///< max volume level for all radio implementations. 154 | 155 | RADIO(); ///< create a new object from this class. 156 | 157 | virtual void setup(int feature, int value); ///< configure board/hardware specific features before init(). 158 | virtual bool init(); ///< initialize library and the chip. 159 | virtual bool initWire(TwoWire &port); // init with I2C bus 160 | virtual void term(); ///< terminate all radio functions. 161 | 162 | // ----- Audio features ----- 163 | 164 | virtual void setVolume(uint8_t newVolume); ///< Control the volume output of the radio chip in the range 0..15. 165 | virtual uint8_t getVolume(); ///< Retrieve the current output volume in the range 0..15. 166 | 167 | virtual void setMute(bool switchOn); ///< Control the mute mode of the radio chip. 168 | virtual bool getMute(); ///< Retrieve the current mute mode setting. 169 | 170 | virtual void setSoftMute(bool switchOn); ///< Control the softmute mode (mute on low signals) of the radio chip. 171 | virtual bool getSoftMute(); ///< Retrieve the current soft mute mode setting. 172 | 173 | virtual void setBassBoost(bool switchOn); ///< Control the bass boost mode of the radio chip. 174 | virtual bool getBassBoost(); ///< Retrieve the current bass boost mode setting. 175 | 176 | // ----- Receiver features ----- 177 | 178 | virtual RADIO_FREQ getMinFrequency(); ///< Get the minimum frequency of the current selected band. 179 | virtual RADIO_FREQ getMaxFrequency(); ///< Get the maximum frequency of the current selected band. 180 | virtual RADIO_FREQ getFrequencyStep(); ///< Get resolution of the current selected band. 181 | 182 | virtual void setBand(RADIO_BAND newBand); ///< Set the current band. 183 | virtual RADIO_BAND getBand(); ///< Retrieve the current band setting. 184 | 185 | virtual void setFrequency(RADIO_FREQ newF); ///< Start using the new frequency for receiving. 186 | virtual RADIO_FREQ getFrequency(void); ///< Retrieve the current tuned frequency. 187 | 188 | virtual void setBandFrequency(RADIO_BAND newBand, RADIO_FREQ newFreq); ///< Set Band and Frequency in one call. 189 | 190 | virtual void seekUp(bool toNextSender = true); ///< Start a seek upwards from the current frequency. 191 | virtual void seekDown(bool toNextSender = true); ///< Start a seek downwards from the current frequency. 192 | 193 | virtual void setMono(bool switchOn); ///< Control the mono mode of the radio chip. 194 | virtual bool getMono(); ///< Retrieve the current mono mode setting. 195 | 196 | // ----- combined status functions ----- 197 | 198 | virtual void getRadioInfo(RADIO_INFO *info); ///< Retrieve some information about the current radio function of the chip. 199 | 200 | virtual void getAudioInfo(AUDIO_INFO *info); ///< Retrieve some information about the current audio function of the chip. 201 | 202 | // ----- Supporting RDS for FM bands ----- 203 | 204 | virtual void attachReceiveRDS(receiveRDSFunction newFunction); ///< Register a RDS processor function. 205 | virtual void checkRDS(); ///< Check if RDS Data is available and good. 206 | virtual void clearRDS(); ///< Clear RDS data in the attached RDS Receiver by sending 0,0,0,0. 207 | 208 | // ----- Utilities ----- 209 | 210 | /// Format the current frequency for display and printing. 211 | virtual void formatFrequency(char *s, uint8_t length); 212 | 213 | // ----- debug Helpers send information to Serial port 214 | 215 | /** 216 | * Enable debugging information on Serial port. 217 | * This is for logging on a higher level than i2c data transport. 218 | * @param enable true to switch logging on. 219 | */ 220 | virtual void debugEnable(bool enable = true); 221 | 222 | virtual void debugRadioInfo(); ///< Print out all radio information. 223 | virtual void debugAudioInfo(); ///< Print out all audio information. 224 | virtual void debugStatus(); ///< Send debug information about actual available chip functionality and other internal things. 225 | 226 | // ===== Wire Utilities (static) ===== 227 | 228 | static bool _wireDebugFlag; 229 | static void _wireWriteTo(TwoWire *port, int address, uint8_t *cmdData, int cmdLen); 230 | static uint8_t _wireReadFrom(TwoWire *port, int address, uint8_t *data, int len); 231 | 232 | // write a 16 bit value in High-Low order to the Wire. 233 | static void _write16HL(TwoWire *port, uint16_t val); 234 | static uint16_t _read16HL(TwoWire *port); 235 | 236 | /** 237 | * Enable low level i2c debugging information on Serial port. 238 | * @param enable true to switch logging on. 239 | */ 240 | virtual void _wireDebug(bool enable = true); 241 | 242 | /** check for a device on address. 243 | * @return true when i2c device answered. 244 | */ 245 | bool _wireExists(TwoWire *port, int address); 246 | 247 | /** 248 | * Write and optionally read data on the i2c bus. 249 | * A debug output can be enabled using _wireDebug(). 250 | * @param port i2c port to be used. 251 | * @param address i2c address to be used. 252 | * @param reg the register to be read (1 byte send). 253 | * @param data buffer array with received data. If this parameter is nullptr no data will be requested. 254 | * @param len length of data buffer. 255 | * @return number of register values received. 256 | */ 257 | int _wireRead(TwoWire *port, int address, uint8_t reg, uint8_t *data, int len); 258 | 259 | /** 260 | * Write and optionally read data on the i2c bus. 261 | * A debug output can be enabled using _wireDebug(). 262 | * @param port i2c port to be used. 263 | * @param address i2c address to be used. 264 | * @param cmdData array with data to be send. 265 | * @param cmdLen length of cmdData. 266 | * @param data buffer array with received data. If this parameter is nullptr no data will be requested. 267 | * @param len length of data buffer. 268 | * @return number of register values received. 269 | */ 270 | int _wireRead(TwoWire *port, int address, uint8_t *cmdData, int cmdLen, uint8_t *data, int len); 271 | 272 | protected: 273 | bool _debugEnabled; ///< Set by debugEnable() and controls debugging functionality. 274 | bool _wireDebugEnabled; ///< Set by _wireDebug() and controls i2c data level debugging. 275 | 276 | uint8_t _volume; ///< Last set volume level. 277 | bool _bassBoost; ///< Last set bass Boost effect. 278 | bool _mono; ///< Last set mono effect. 279 | bool _mute; ///< Last set mute effect. 280 | bool _softMute; ///< Last set softMute effect. 281 | 282 | RADIO_BAND _band; ///< Last set band. 283 | RADIO_FREQ _freq; ///< Last set frequency. 284 | 285 | RADIO_FREQ _freqLow; ///< Lowest frequency of the current selected band. 286 | RADIO_FREQ _freqHigh; ///< Highest frequency of the current selected band. 287 | RADIO_FREQ _freqSteps; ///< Resolution of the tuner. 288 | 289 | receiveRDSFunction _sendRDS; ///< Registered RDS Function that is called on new available data. 290 | 291 | void _printHex2(uint8_t val); ///< Prints a byte as 2 character hexadecimal code with leading zeros. 292 | void _printHex4(uint16_t val); ///< Prints a register as 4 character hexadecimal code with leading zeros. 293 | 294 | // i2c bus communication 295 | TwoWire *_i2cPort; 296 | int _i2caddr; 297 | 298 | // extra pins 299 | int _resetPin = -1; 300 | 301 | // OPTIONS 302 | int _antennaOption = 0; 303 | 304 | private: 305 | void int16_to_s(char *s, uint16_t val); ///< Converts a int16 number to a string, similar to itoa, but using the format "00000". 306 | 307 | }; // class RADIO 308 | 309 | 310 | #endif 311 | 312 | // End. -------------------------------------------------------------------------------- /ScoutMakes FM Breakout StemmaQT/examples/CircuitPython_RDA5807M_FMradio/code.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries 2 | # SPDX-FileCopyrightText: Copyright (c) 2022 tinkeringtech for TinkeringTech LLC 3 | # 4 | # SPDX-License-Identifier: Unlicense 5 | 6 | # pylint: disable=global-statement, too-many-branches, too-many-statements 7 | import time 8 | import board 9 | import busio 10 | import supervisor 11 | from adafruit_bus_device.i2c_device import I2CDevice 12 | import tinkeringtech_rda5807m 13 | 14 | presets = [8930, 9510, 9710, 9950, 10100, 10110, 10650] # Preset stations 15 | i_sidx = 3 # Starting at station with index 3 16 | 17 | # Initialize i2c bus 18 | i2c = busio.I2C(board.SCL, board.SDA) 19 | 20 | # Receiver i2c communication 21 | address = 0x11 22 | vol = 3 # Default volume 23 | band = "FM" 24 | 25 | rds = tinkeringtech_rda5807m.RDSParser() 26 | 27 | # Display initialization 28 | initial_time = time.monotonic() # Initial time - used for timing 29 | toggle_frequency = ( 30 | 5 # Frequency at which the text changes between radio frequnecy and rds in seconds 31 | ) 32 | 33 | rdstext = "No rds data" 34 | 35 | # RDS text handle 36 | def textHandle(rdsText): 37 | global rdstext 38 | rdstext = rdsText 39 | print(rdsText) 40 | 41 | 42 | rds.attach_text_callback(textHandle) 43 | 44 | # Initialize the radio classes for use. 45 | radio_i2c = I2CDevice(i2c, address) 46 | radio = tinkeringtech_rda5807m.Radio(radio_i2c, rds, presets[i_sidx], vol) 47 | radio.set_band(band) # Minimum frequency - 87 Mhz, max - 108 Mhz 48 | 49 | # Read input from serial 50 | def serial_read(): 51 | if supervisor.runtime.serial_bytes_available: 52 | command = input() 53 | command = command.split(" ") 54 | cmd = command[0] 55 | if cmd == "f": 56 | value = command[1] 57 | runSerialCommand(cmd, int(value)) 58 | else: 59 | runSerialCommand(cmd) 60 | time.sleep(0.3) 61 | print("-> ", end="") 62 | 63 | 64 | def runSerialCommand(cmd, value=0): 65 | # Executes a command 66 | # Starts with a character, and optionally followed by an integer, if required 67 | global i_sidx 68 | if cmd == "?": 69 | print("? help") 70 | print("+ increase volume") 71 | print("- decrease volume") 72 | print("> next preset") 73 | print("< previous preset") 74 | print(". scan up ") 75 | print(", scan down ") 76 | print( 77 | "f direct frequency input e.g 99.50 MHz is f 9950 or 101.10 MHz is f 10110" 78 | ) 79 | print("i station status") 80 | print("s mono/stereo mode") 81 | print("b bass boost") 82 | print("u mute/unmute") 83 | print("r get rssi data") 84 | print("e softreset chip") 85 | print("q stops the program") 86 | 87 | # Volume and audio control 88 | elif cmd == "+": 89 | v = radio.volume 90 | if v < 15: 91 | radio.set_volume(v + 1) 92 | elif cmd == "-": 93 | v = radio.volume 94 | if v > 0: 95 | radio.set_volume(v - 1) 96 | 97 | # Toggle mute mode 98 | elif cmd == "u": 99 | radio.set_mute(not radio.mute) 100 | # Toggle stereo mode 101 | elif cmd == "s": 102 | radio.set_mono(not radio.mono) 103 | # Toggle bass boost 104 | elif cmd == "b": 105 | radio.set_bass_boost(not radio.bass_boost) 106 | 107 | # Frequency control 108 | elif cmd == ">": 109 | # Goes to the next preset station 110 | if i_sidx < (len(presets) - 1): 111 | i_sidx = i_sidx + 1 112 | radio.set_freq(presets[i_sidx]) 113 | elif cmd == "<": 114 | # Goes to the previous preset station 115 | if i_sidx > 0: 116 | i_sidx = i_sidx - 1 117 | radio.set_freq(presets[i_sidx]) 118 | 119 | # Set frequency 120 | elif cmd == "f": 121 | radio.set_freq(value) 122 | 123 | # Seek up/down 124 | elif cmd == ".": 125 | radio.seek_up() 126 | elif cmd == ",": 127 | radio.seek_down() 128 | 129 | # Display current signal strength 130 | elif cmd == "r": 131 | print("RSSI: " + str(radio.get_rssi())) 132 | 133 | # Soft reset chip 134 | elif cmd == "e": 135 | radio.soft_reset() 136 | 137 | # Not in help 138 | elif cmd == "!": 139 | radio.term() 140 | 141 | elif cmd == "i": 142 | # Display chip info 143 | s = radio.format_freq() 144 | print("Station: " + s) 145 | print("Radio info: ") 146 | print("RDS -> " + str(radio.rds)) 147 | print("TUNED -> " + str(radio.tuned)) 148 | print("STEREO -> " + str(not radio.mono)) 149 | print("Audio info: ") 150 | print("BASS -> " + str(radio.bass_boost)) 151 | print("MUTE -> " + str(radio.mute)) 152 | print("SOFTMUTE -> " + str(radio.soft_mute)) 153 | print("VOLUME -> " + str(radio.volume)) 154 | 155 | 156 | print_rds = False 157 | runSerialCommand("?", 0) 158 | 159 | print("-> ", end="") 160 | 161 | while True: 162 | serial_read() 163 | radio.check_rds() 164 | new_time = time.monotonic() 165 | serial_read() 166 | -------------------------------------------------------------------------------- /ScoutMakes FM Breakout StemmaQT/examples/CircuitPython_RDA5807M_FMradio/lib/tinkeringtech_rda5807m.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Breakout StemmaQT/examples/CircuitPython_RDA5807M_FMradio/lib/tinkeringtech_rda5807m.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Breakout StemmaQT/examples/CircuitPython_RDA5807M_FMradio/rda5807m_simpletest.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries 2 | # SPDX-FileCopyrightText: Copyright (c) 2022 tinkeringtech for TinkeringTech LLC 3 | # 4 | # SPDX-License-Identifier: Unlicense 5 | 6 | # pylint: disable=global-statement, too-many-branches, too-many-statements 7 | import time 8 | import board 9 | import busio 10 | import supervisor 11 | from adafruit_bus_device.i2c_device import I2CDevice 12 | import tinkeringtech_rda5807m 13 | 14 | presets = [8930, 9510, 9710, 9950, 10100, 10110, 10650] # Preset stations 15 | i_sidx = 3 # Starting at station with index 3 16 | 17 | # Initialize i2c bus 18 | i2c = busio.I2C(board.SCL, board.SDA) 19 | 20 | # Receiver i2c communication 21 | address = 0x11 22 | vol = 3 # Default volume 23 | band = "FM" 24 | 25 | rds = tinkeringtech_rda5807m.RDSParser() 26 | 27 | # Display initialization 28 | initial_time = time.monotonic() # Initial time - used for timing 29 | toggle_frequency = ( 30 | 5 # Frequency at which the text changes between radio frequnecy and rds in seconds 31 | ) 32 | 33 | rdstext = "No rds data" 34 | 35 | # RDS text handle 36 | def textHandle(rdsText): 37 | global rdstext 38 | rdstext = rdsText 39 | print(rdsText) 40 | 41 | 42 | rds.attach_text_callback(textHandle) 43 | 44 | # Initialize the radio classes for use. 45 | radio_i2c = I2CDevice(i2c, address) 46 | radio = tinkeringtech_rda5807m.Radio(radio_i2c, rds, presets[i_sidx], vol) 47 | radio.set_band(band) # Minimum frequency - 87 Mhz, max - 108 Mhz 48 | 49 | # Read input from serial 50 | def serial_read(): 51 | if supervisor.runtime.serial_bytes_available: 52 | command = input() 53 | command = command.split(" ") 54 | cmd = command[0] 55 | if cmd == "f": 56 | value = command[1] 57 | runSerialCommand(cmd, int(value)) 58 | else: 59 | runSerialCommand(cmd) 60 | time.sleep(0.3) 61 | print("-> ", end="") 62 | 63 | 64 | def runSerialCommand(cmd, value=0): 65 | # Executes a command 66 | # Starts with a character, and optionally followed by an integer, if required 67 | global i_sidx 68 | if cmd == "?": 69 | print("? help") 70 | print("+ increase volume") 71 | print("- decrease volume") 72 | print("> next preset") 73 | print("< previous preset") 74 | print(". scan up ") 75 | print(", scan down ") 76 | print( 77 | "f direct frequency input e.g 99.50 MHz is f 9950 or 101.10 MHz is f 10110" 78 | ) 79 | print("i station status") 80 | print("s mono/stereo mode") 81 | print("b bass boost") 82 | print("u mute/unmute") 83 | print("r get rssi data") 84 | print("e softreset chip") 85 | print("q stops the program") 86 | 87 | # Volume and audio control 88 | elif cmd == "+": 89 | v = radio.volume 90 | if v < 15: 91 | radio.set_volume(v + 1) 92 | elif cmd == "-": 93 | v = radio.volume 94 | if v > 0: 95 | radio.set_volume(v - 1) 96 | 97 | # Toggle mute mode 98 | elif cmd == "u": 99 | radio.set_mute(not radio.mute) 100 | # Toggle stereo mode 101 | elif cmd == "s": 102 | radio.set_mono(not radio.mono) 103 | # Toggle bass boost 104 | elif cmd == "b": 105 | radio.set_bass_boost(not radio.bass_boost) 106 | 107 | # Frequency control 108 | elif cmd == ">": 109 | # Goes to the next preset station 110 | if i_sidx < (len(presets) - 1): 111 | i_sidx = i_sidx + 1 112 | radio.set_freq(presets[i_sidx]) 113 | elif cmd == "<": 114 | # Goes to the previous preset station 115 | if i_sidx > 0: 116 | i_sidx = i_sidx - 1 117 | radio.set_freq(presets[i_sidx]) 118 | 119 | # Set frequency 120 | elif cmd == "f": 121 | radio.set_freq(value) 122 | 123 | # Seek up/down 124 | elif cmd == ".": 125 | radio.seek_up() 126 | elif cmd == ",": 127 | radio.seek_down() 128 | 129 | # Display current signal strength 130 | elif cmd == "r": 131 | print("RSSI: " + str(radio.get_rssi())) 132 | 133 | # Soft reset chip 134 | elif cmd == "e": 135 | radio.soft_reset() 136 | 137 | # Not in help 138 | elif cmd == "!": 139 | radio.term() 140 | 141 | elif cmd == "i": 142 | # Display chip info 143 | s = radio.format_freq() 144 | print("Station: " + s) 145 | print("Radio info: ") 146 | print("RDS -> " + str(radio.rds)) 147 | print("TUNED -> " + str(radio.tuned)) 148 | print("STEREO -> " + str(not radio.mono)) 149 | print("Audio info: ") 150 | print("BASS -> " + str(radio.bass_boost)) 151 | print("MUTE -> " + str(radio.mute)) 152 | print("SOFTMUTE -> " + str(radio.soft_mute)) 153 | print("VOLUME -> " + str(radio.volume)) 154 | 155 | 156 | print_rds = False 157 | runSerialCommand("?", 0) 158 | 159 | print("-> ", end="") 160 | 161 | while True: 162 | serial_read() 163 | radio.check_rds() 164 | new_time = time.monotonic() 165 | serial_read() 166 | -------------------------------------------------------------------------------- /ScoutMakes FM Kit/FM kit pictures/fmkit_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/FM kit pictures/fmkit_1.jpg -------------------------------------------------------------------------------- /ScoutMakes FM Kit/FM kit pictures/fmkit_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/FM kit pictures/fmkit_2.jpg -------------------------------------------------------------------------------- /ScoutMakes FM Kit/FM kit pictures/fmkit_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/FM kit pictures/fmkit_3.jpg -------------------------------------------------------------------------------- /ScoutMakes FM Kit/README.md: -------------------------------------------------------------------------------- 1 | **ScoutMakes FM radio STEM Electronic Kit** 2 | 3 | **Open Source Hardware Association certified OSHWA UID US000675** 4 | 5 | These are the source design files for the ScoutMakes FM radio Electronic Kit. 6 | 7 | The kits can be bought at https://www.scoutmakes.com. 8 | Please support this educational company by buying our products focused on cultivating more engineers! 9 | 10 | Designed by TinkeringTech. 11 | License: Creative Commons ShareAlike 3.0 United States (CC BY-SA 3.0 US) 12 | License: MIT License 13 | Check license.txt for more information All text above must be included in any redistribution. 14 | 15 | **FM Radio Kit Features & Specifications** 16 | - Open hardware & open source software 17 | - RDA5807M single-chip FM receiver 18 | - Controllable over BLE using an iOS or Android app 19 | - Portable and powered by a rechargeable, LiPo battery 20 | - High-quality stereo audio output 21 | - Built-in volume and bass control 22 | - Received signal strength indicator (RSSI) information 23 | - Station scanning and presets are supported in code 24 | - Radio Data Service (RDS) information available for display 25 | - Received signal strength (RSSI) indication 26 | - Adafruit CircuitPython library 27 | - Adafruit STEMMA QT and SparkFun Qwiic connectors for easy, solderless attachment of other I²C devices 28 | - User-assignable push-buttons for control 29 | - 3.5 mm audio jack 30 | -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/Bluetooth_diagnostics.py: -------------------------------------------------------------------------------- 1 | """ 2 | This test will initialize the BLE module and accept commands from the Bluetooth app controller arrows and manipulate the onboard NEOPIXEL colors. 3 | 4 | To use: 5 | - Open the BLE app (Adafruit's Bluefruit Connect available in iOS and Android). 6 | - Connect to the CIRCUITPYTHON board. 7 | - Select the controller module. 8 | - Select control pad. 9 | - Press the arrows to see the NEOPIXEL change color according to the following commands: 10 | RIGHT = RED 11 | LEFT = BLUE 12 | UP = GREEN 13 | DOWN = WHITE 14 | """ 15 | 16 | from adafruit_ble import BLERadio 17 | from adafruit_ble.advertising.standard import ProvideServicesAdvertisement 18 | from adafruit_ble.services.nordic import UARTService 19 | from adafruit_bluefruit_connect.packet import Packet 20 | # Only the packet classes that are imported will be known to Packet. 21 | from adafruit_bluefruit_connect.button_packet import ButtonPacket 22 | 23 | import time 24 | import board 25 | import pulseio 26 | import neopixel 27 | import busio 28 | 29 | pixel_pin = board.NEOPIXEL 30 | num_pixels = 1 31 | 32 | pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False) 33 | 34 | RED = (255, 0, 0) 35 | YELLOW = (255, 150, 0) 36 | GREEN = (0, 255, 0) 37 | CYAN = (0, 255, 255) 38 | BLUE = (0, 0, 255) 39 | PURPLE = (180, 0, 255) 40 | WHITE = (255,255,255) 41 | 42 | ble = BLERadio() 43 | uart_service = UARTService() 44 | advertisement = ProvideServicesAdvertisement(uart_service) 45 | 46 | while True: 47 | ble.start_advertising(advertisement) 48 | while not ble.connected: 49 | pass 50 | 51 | # Now we're connected 52 | 53 | while ble.connected: 54 | if uart_service.in_waiting: 55 | # Packet is arriving. 56 | packet = Packet.from_stream(uart_service) 57 | if isinstance(packet, ButtonPacket) and packet.pressed: 58 | if packet.button == ButtonPacket.RIGHT: # RIGHT button pressed 59 | pixels.fill(RED) 60 | pixels.show() 61 | # Increase or decrease to change the speed of the solid color change. 62 | time.sleep(1) 63 | elif packet.button == ButtonPacket.LEFT: # LEFT button pressed 64 | pixels.fill(BLUE) 65 | pixels.show() 66 | time.sleep(1) 67 | elif packet.button == ButtonPacket.UP: # UP button pressed 68 | pixels.fill(GREEN) 69 | pixels.show() 70 | time.sleep(1) 71 | elif packet.button == ButtonPacket.DOWN: # DOWN button pressed 72 | pixels.fill(WHITE) 73 | pixels.show() 74 | time.sleep(1) -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/FM_radio_demo.py: -------------------------------------------------------------------------------- 1 | import time 2 | import board 3 | import busio 4 | import supervisor 5 | import displayio 6 | import terminalio 7 | from adafruit_bus_device.i2c_device import I2CDevice 8 | from adafruit_display_text import label 9 | import adafruit_displayio_ssd1306 10 | import tinkeringtech_rda5807m 11 | from digitalio import DigitalInOut, Direction, Pull 12 | 13 | from adafruit_ble import BLERadio 14 | from adafruit_ble.advertising.standard import ProvideServicesAdvertisement 15 | from adafruit_ble.services.nordic import UARTService 16 | from adafruit_bluefruit_connect.packet import Packet 17 | # Only the packet classes that are imported will be known to Packet. 18 | from adafruit_bluefruit_connect.button_packet import ButtonPacket 19 | 20 | ble = BLERadio() 21 | uart_service = UARTService() 22 | advertisement = ProvideServicesAdvertisement(uart_service) 23 | 24 | switch2 = DigitalInOut(board.D5) 25 | switch2.direction = Direction.INPUT 26 | switch2.pull = Pull.UP 27 | 28 | switch1 = DigitalInOut(board.D6) 29 | switch1.direction = Direction.INPUT 30 | switch1.pull = Pull.UP 31 | 32 | switch3 = DigitalInOut(board.D9) 33 | switch3.direction = Direction.INPUT 34 | switch3.pull = Pull.UP 35 | 36 | switch4 = DigitalInOut(board.D10) 37 | switch4.direction = Direction.INPUT 38 | switch4.pull = Pull.UP 39 | 40 | switch5 = DigitalInOut(board.D11) 41 | switch5.direction = Direction.INPUT 42 | switch5.pull = Pull.UP 43 | 44 | switch6 = DigitalInOut(board.D12) 45 | switch6.direction = Direction.INPUT 46 | switch6.pull = Pull.UP 47 | 48 | # Display 49 | displayio.release_displays() 50 | 51 | presets = [ # Preset stations 52 | 8930, 53 | 9510, 54 | 9710, 55 | 9950, 56 | 10100, 57 | 10110, 58 | 10650 59 | ] 60 | i_sidx = 3 # Starting at station with index 3 61 | 62 | # Initialize i2c bus 63 | i2c = busio.I2C(board.SCL, board.SDA) 64 | 65 | # Receiver i2c communication 66 | address = 0x11 67 | radio_i2c = I2CDevice(i2c, address) 68 | 69 | vol = 1 # Default volume 70 | band = "FM" 71 | 72 | radio = tinkeringtech_rda5807m.Radio(radio_i2c, presets[i_sidx], vol) 73 | radio.setBand(band) # Minimum frequency - 87 Mhz, max - 108 Mhz 74 | rds = tinkeringtech_rda5807m.RDSParser() 75 | 76 | # Display initialization 77 | initial_time = time.monotonic() # Initial time - used for timing 78 | toggle_frequency = 5 # Frequency at which the text changes between radio frequnecy and rds in seconds 79 | display_bus = displayio.I2CDisplay(i2c, device_address=0x3C) 80 | display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32) 81 | rdstext = "No rds data" 82 | 83 | 84 | def drawText(text): 85 | # Write text on display 86 | global display 87 | # Make the display context 88 | splash = displayio.Group(max_size=10) 89 | display.show(splash) 90 | 91 | color_bitmap = displayio.Bitmap(128, 32, 1) 92 | color_palette = displayio.Palette(1) 93 | color_palette[0] = 0x000000 # Black 94 | 95 | bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) 96 | splash.append(bg_sprite) 97 | 98 | # Split text into two lines 99 | temp = text.split(" ") 100 | line1 = temp[0] 101 | line2 = " ".join(temp[1:]) 102 | # Check that lines are not empty 103 | if not line1.strip() or not line2.strip(): 104 | warning = "Unclear rds data" 105 | text_area_1 = label.Label(terminalio.FONT, text=warning, color=0xFFFF00, x=5, y=5) 106 | splash.append(text_area_1) 107 | else: 108 | # Line 1 109 | text_area_1 = label.Label(terminalio.FONT, text=line1, color=0xFFFF00, x=5, y=5) 110 | splash.append(text_area_1) 111 | # Line 2 112 | text_area_2 = label.Label(terminalio.FONT, text=line2, color=0xFFFF00, x=5, y=20) 113 | splash.append(text_area_2) 114 | 115 | 116 | # RDS text handle 117 | def textHandle(rdsText): 118 | global rdstext 119 | rdstext = rdsText 120 | print(rdsText) 121 | 122 | 123 | rds.attachTextCallback(textHandle) 124 | 125 | 126 | # Read input from serial 127 | def serial_read(): 128 | if supervisor.runtime.serial_bytes_available: 129 | command = input() 130 | command = command.split(" ") 131 | cmd = command[0] 132 | if cmd == "f": 133 | value = command[1] 134 | runSerialCommand(cmd, int(value)) 135 | else: 136 | runSerialCommand(cmd) 137 | time.sleep(0.3) 138 | print("-> ", end="") 139 | 140 | 141 | def runSerialCommand(cmd, value=0): 142 | # Executes a command 143 | # Starts with a character, and optionally followed by an integer, if required 144 | global i_sidx 145 | global presets 146 | if cmd == "?": 147 | print("? help") 148 | print("+ increase volume") 149 | print("- decrease volume") 150 | print("> next preset") 151 | print("< previous preset") 152 | print(". scan up ") 153 | print(", scan down ") 154 | print("f direct frequency input") 155 | print("i station status") 156 | print("s mono/stereo mode") 157 | print("b bass boost") 158 | print("u mute/unmute") 159 | print("r get rssi data") 160 | print("e softreset chip") 161 | print("q stops the program") 162 | 163 | # Volume and audio control 164 | elif cmd == "+": 165 | v = radio.volume 166 | if v < 15: 167 | radio.setVolume(v + 1) 168 | elif cmd == "-": 169 | v = radio.volume 170 | if v > 0: 171 | radio.setVolume(v - 1) 172 | 173 | # Toggle mute mode 174 | elif cmd == "u": 175 | radio.setMute(not radio.mute) 176 | # Toggle stereo mode 177 | elif cmd == "s": 178 | radio.setMono(not radio.mono) 179 | # Toggle bass boost 180 | elif cmd == "b": 181 | radio.setBassBoost(not radio.bassBoost) 182 | 183 | # Frequency control 184 | elif cmd == ">": 185 | # Goes to the next preset station 186 | if i_sidx < (len(presets) - 1): 187 | i_sidx = i_sidx + 1 188 | radio.setFreq(presets[i_sidx]) 189 | elif cmd == "<": 190 | # Goes to the previous preset station 191 | if i_sidx > 0: 192 | i_sidx = i_sidx - 1 193 | radio.setFreq(presets[i_sidx]) 194 | 195 | # Set frequency 196 | elif cmd == "f": 197 | radio.setFreq(value) 198 | 199 | # Seek up/down 200 | elif cmd == ".": 201 | radio.seekUp() 202 | elif cmd == ",": 203 | radio.seekDown() 204 | 205 | # Display current signal strength 206 | elif cmd == "r": 207 | print("RSSI: " + str(radio.getRssi())) 208 | 209 | # Soft reset chip 210 | elif cmd == "e": 211 | radio.softReset() 212 | 213 | # Not in help 214 | elif cmd == "!": 215 | radio.term() 216 | 217 | elif cmd == "i": 218 | # Display chip info 219 | s = radio.formatFreq() 220 | print("Station: " + s) 221 | print("Radio info: ") 222 | print("RDS -> " + str(radio.rds)) 223 | print("TUNED -> " + str(radio.tuned)) 224 | print("STEREO -> " + str(not radio.mono)) 225 | print("Audio info: ") 226 | print("BASS -> " + str(radio.bassBoost)) 227 | print("MUTE -> " + str(radio.mute)) 228 | print("SOFTMUTE -> " + str(radio.softMute)) 229 | print("VOLUME -> " + str(radio.volume)) 230 | 231 | 232 | print_rds = False 233 | radio.sendRDS = rds.processData 234 | runSerialCommand("?", 0) 235 | 236 | print("-> ", end="") 237 | 238 | while True: 239 | 240 | ble.start_advertising(advertisement) 241 | 242 | while ble.connected: 243 | if uart_service.in_waiting: 244 | # Packet is arriving. 245 | packet = Packet.from_stream(uart_service) 246 | if isinstance(packet, ButtonPacket) and packet.pressed: 247 | if packet.button == ButtonPacket.RIGHT: # UP button pressed 248 | radio.seekUp() 249 | elif packet.button == ButtonPacket.LEFT: # DOWN button pressed 250 | radio.seekDown() 251 | elif packet.button == ButtonPacket.BUTTON_1: # BUTTON 1 button pressed 252 | # Goes to the next preset station 253 | if i_sidx < (len(presets) - 1): 254 | i_sidx = i_sidx + 1 255 | radio.setFreq(presets[i_sidx]) 256 | elif i_sidx == 6: 257 | i_sidx = 0 258 | radio.setFreq(presets[i_sidx]) 259 | elif packet.button == ButtonPacket.BUTTON_2: # BUTTON 2 button pressed 260 | radio.setMute(not radio.mute) 261 | elif packet.button == ButtonPacket.BUTTON_3: # BUTTON 3 button pressed 262 | # Goes preset station 2 263 | radio.setFreq(presets[2]) 264 | elif packet.button == ButtonPacket.BUTTON_4: # BUTTON 4 button pressed 265 | # Goes preset station 4 266 | radio.setFreq(presets[4]) 267 | elif packet.button == ButtonPacket.UP: # UP button pressed 268 | v = radio.volume 269 | if v < 15: 270 | radio.setVolume(v + 1) 271 | elif packet.button == ButtonPacket.DOWN: # DOWN button pressed 272 | v = radio.volume 273 | if v > 0: 274 | radio.setVolume(v - 1) 275 | serial_read() 276 | radio.checkRDS() 277 | new_time = time.monotonic() 278 | if (new_time - initial_time) > toggle_frequency: 279 | print_rds = not print_rds 280 | if print_rds: 281 | if rdstext == "": 282 | drawText("No rds data") 283 | else: 284 | if len(rdstext.split(" ")) > 1: 285 | drawText(rdstext) 286 | else: 287 | drawText("Unclear rds data") 288 | else: 289 | drawText(radio.formatFreq()) 290 | initial_time = new_time 291 | 292 | while not ble.connected: 293 | # Wait for a connection. 294 | # Main loop 295 | if not switch1.value: 296 | print("Seek Up pressed - button 1") 297 | radio.seekUp() 298 | time.sleep(0.01) # debounce delay 299 | 300 | if not switch2.value: 301 | print("Seek Down pressed - button 2") 302 | radio.seekDown() 303 | time.sleep(0.01) # debounce delay 304 | 305 | if not switch3.value: 306 | print("mute pressed - button 3") 307 | radio.setMute(not radio.mute) 308 | time.sleep(0.01) # debounce delay 309 | 310 | if not switch4.value: 311 | print("Preset up pressed - button 4") 312 | # Goes to the next preset station 313 | 314 | print (i_sidx) 315 | if i_sidx < (len(presets) - 1): 316 | i_sidx = i_sidx + 1 317 | radio.setFreq(presets[i_sidx]) 318 | 319 | elif i_sidx == 6: 320 | i_sidx = 0 321 | radio.setFreq(presets[i_sidx]) 322 | time.sleep(0.01) # debounce delay 323 | 324 | if not switch5.value: 325 | print("Volume Up pressed - button 5") 326 | v = radio.volume 327 | if v < 15: 328 | radio.setVolume(v + 1) 329 | time.sleep(0.08) # debounce delay 330 | 331 | if not switch6.value: 332 | print("Volume Down pressed - button 6") 333 | v = radio.volume 334 | if v > 0: 335 | radio.setVolume(v - 1) 336 | time.sleep(0.01) # debounce delay 337 | 338 | 339 | serial_read() 340 | radio.checkRDS() 341 | new_time = time.monotonic() 342 | if (new_time - initial_time) > toggle_frequency: 343 | print_rds = not print_rds 344 | if print_rds: 345 | if rdstext == "": 346 | drawText("No rds data") 347 | else: 348 | if len(rdstext.split(" ")) > 1: 349 | drawText(rdstext) 350 | else: 351 | drawText("Unclear rds data") 352 | else: 353 | drawText(radio.formatFreq()) 354 | initial_time = new_time -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/OLED_Neopixel_diagnostics.py: -------------------------------------------------------------------------------- 1 | """ 2 | This test will illuminate the onboard NEOPIXEL and cycle through colors red, green, 3 | blue followed by chasing pattern and rainbow. 4 | """ 5 | 6 | import time 7 | import board 8 | import neopixel 9 | import displayio 10 | import terminalio 11 | from adafruit_display_text import label 12 | import adafruit_displayio_ssd1306 13 | 14 | displayio.release_displays() 15 | 16 | # Set up display & add group 17 | i2c = board.I2C() 18 | display_bus = displayio.I2CDisplay(i2c, device_address=0x3C) 19 | display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32) 20 | group = displayio.Group(max_size=1) 21 | display.show(group) 22 | 23 | # Add content to group 24 | default_text = "ScoutMakes Azul" 25 | text_area = label.Label(terminalio.FONT, text=default_text, color=0xFFFFFF, x=10, y=17) 26 | group.append(text_area) 27 | 28 | pixel_pin = board.NEOPIXEL 29 | num_pixels = 1 30 | 31 | pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False) 32 | 33 | 34 | def wheel(pos): 35 | # Input a value 0 to 255 to get a color value. 36 | # The colours are a transition r - g - b - back to r. 37 | if pos < 0 or pos > 255: 38 | return (0, 0, 0) 39 | if pos < 85: 40 | return (255 - pos * 3, pos * 3, 0) 41 | if pos < 170: 42 | pos -= 85 43 | return (0, 255 - pos * 3, pos * 3) 44 | pos -= 170 45 | return (pos * 3, 0, 255 - pos * 3) 46 | 47 | 48 | def color_chase(color, wait): 49 | for i in range(num_pixels): 50 | pixels[i] = color 51 | time.sleep(wait) 52 | pixels.show() 53 | time.sleep(0.5) 54 | 55 | 56 | def rainbow_cycle(wait): 57 | for j in range(255): 58 | for i in range(num_pixels): 59 | rc_index = (i * 256 // num_pixels) + j 60 | pixels[i] = wheel(rc_index & 255) 61 | pixels.show() 62 | time.sleep(wait) 63 | 64 | 65 | RED = (255, 0, 0) 66 | YELLOW = (255, 150, 0) 67 | GREEN = (0, 255, 0) 68 | CYAN = (0, 255, 255) 69 | BLUE = (0, 0, 255) 70 | PURPLE = (180, 0, 255) 71 | 72 | while True: 73 | text_area.text = default_text 74 | text_area.x = 20 75 | time.sleep(1) 76 | text_area.text = "Make Something!" 77 | text_area.x = 20 78 | display.show(group) 79 | time.sleep(1) 80 | 81 | pixels.fill(RED) 82 | pixels.show() 83 | # Increase or decrease to change the speed of the solid color change. 84 | time.sleep(1) 85 | pixels.fill(GREEN) 86 | pixels.show() 87 | time.sleep(1) 88 | pixels.fill(BLUE) 89 | pixels.show() 90 | time.sleep(1) 91 | 92 | color_chase(RED, 0.1) # Increase the number to slow down the color chase 93 | color_chase(YELLOW, 0.1) 94 | color_chase(GREEN, 0.1) 95 | color_chase(CYAN, 0.1) 96 | color_chase(BLUE, 0.1) 97 | color_chase(PURPLE, 0.1) 98 | 99 | rainbow_cycle(0) # Increase the number to slow down the rainbow -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/code.py: -------------------------------------------------------------------------------- 1 | import time 2 | import board 3 | import busio 4 | import supervisor 5 | import displayio 6 | import terminalio 7 | from adafruit_bus_device.i2c_device import I2CDevice 8 | from adafruit_display_text import label 9 | import adafruit_displayio_ssd1306 10 | import tinkeringtech_rda5807m 11 | from digitalio import DigitalInOut, Direction, Pull 12 | 13 | from adafruit_ble import BLERadio 14 | from adafruit_ble.advertising.standard import ProvideServicesAdvertisement 15 | from adafruit_ble.services.nordic import UARTService 16 | from adafruit_bluefruit_connect.packet import Packet 17 | # Only the packet classes that are imported will be known to Packet. 18 | from adafruit_bluefruit_connect.button_packet import ButtonPacket 19 | 20 | ble = BLERadio() 21 | uart_service = UARTService() 22 | advertisement = ProvideServicesAdvertisement(uart_service) 23 | 24 | switch2 = DigitalInOut(board.D5) 25 | switch2.direction = Direction.INPUT 26 | switch2.pull = Pull.UP 27 | 28 | switch1 = DigitalInOut(board.D6) 29 | switch1.direction = Direction.INPUT 30 | switch1.pull = Pull.UP 31 | 32 | switch3 = DigitalInOut(board.D9) 33 | switch3.direction = Direction.INPUT 34 | switch3.pull = Pull.UP 35 | 36 | switch4 = DigitalInOut(board.D10) 37 | switch4.direction = Direction.INPUT 38 | switch4.pull = Pull.UP 39 | 40 | switch5 = DigitalInOut(board.D11) 41 | switch5.direction = Direction.INPUT 42 | switch5.pull = Pull.UP 43 | 44 | switch6 = DigitalInOut(board.D12) 45 | switch6.direction = Direction.INPUT 46 | switch6.pull = Pull.UP 47 | 48 | # Display 49 | displayio.release_displays() 50 | 51 | presets = [ # Preset stations 52 | 8930, 53 | 9510, 54 | 9710, 55 | 9950, 56 | 10100, 57 | 10110, 58 | 10650 59 | ] 60 | i_sidx = 3 # Starting at station with index 3 61 | 62 | # Initialize i2c bus 63 | i2c = busio.I2C(board.SCL, board.SDA) 64 | 65 | # Receiver i2c communication 66 | address = 0x11 67 | radio_i2c = I2CDevice(i2c, address) 68 | 69 | vol = 1 # Default volume 70 | band = "FM" 71 | 72 | radio = tinkeringtech_rda5807m.Radio(radio_i2c, presets[i_sidx], vol) 73 | radio.setBand(band) # Minimum frequency - 87 Mhz, max - 108 Mhz 74 | rds = tinkeringtech_rda5807m.RDSParser() 75 | 76 | # Display initialization 77 | initial_time = time.monotonic() # Initial time - used for timing 78 | toggle_frequency = 5 # Frequency at which the text changes between radio frequnecy and rds in seconds 79 | display_bus = displayio.I2CDisplay(i2c, device_address=0x3C) 80 | display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32) 81 | rdstext = "No rds data" 82 | 83 | 84 | def drawText(text): 85 | # Write text on display 86 | global display 87 | # Make the display context 88 | splash = displayio.Group(max_size=10) 89 | display.show(splash) 90 | 91 | color_bitmap = displayio.Bitmap(128, 32, 1) 92 | color_palette = displayio.Palette(1) 93 | color_palette[0] = 0x000000 # Black 94 | 95 | bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) 96 | splash.append(bg_sprite) 97 | 98 | # Split text into two lines 99 | temp = text.split(" ") 100 | line1 = temp[0] 101 | line2 = " ".join(temp[1:]) 102 | # Check that lines are not empty 103 | if not line1.strip() or not line2.strip(): 104 | warning = "Unclear rds data" 105 | text_area_1 = label.Label(terminalio.FONT, text=warning, color=0xFFFF00, x=5, y=5) 106 | splash.append(text_area_1) 107 | else: 108 | # Line 1 109 | text_area_1 = label.Label(terminalio.FONT, text=line1, color=0xFFFF00, x=5, y=5) 110 | splash.append(text_area_1) 111 | # Line 2 112 | text_area_2 = label.Label(terminalio.FONT, text=line2, color=0xFFFF00, x=5, y=20) 113 | splash.append(text_area_2) 114 | 115 | 116 | # RDS text handle 117 | def textHandle(rdsText): 118 | global rdstext 119 | rdstext = rdsText 120 | print(rdsText) 121 | 122 | 123 | rds.attachTextCallback(textHandle) 124 | 125 | 126 | # Read input from serial 127 | def serial_read(): 128 | if supervisor.runtime.serial_bytes_available: 129 | command = input() 130 | command = command.split(" ") 131 | cmd = command[0] 132 | if cmd == "f": 133 | value = command[1] 134 | runSerialCommand(cmd, int(value)) 135 | else: 136 | runSerialCommand(cmd) 137 | time.sleep(0.3) 138 | print("-> ", end="") 139 | 140 | 141 | def runSerialCommand(cmd, value=0): 142 | # Executes a command 143 | # Starts with a character, and optionally followed by an integer, if required 144 | global i_sidx 145 | global presets 146 | if cmd == "?": 147 | print("? help") 148 | print("+ increase volume") 149 | print("- decrease volume") 150 | print("> next preset") 151 | print("< previous preset") 152 | print(". scan up ") 153 | print(", scan down ") 154 | print("f direct frequency input") 155 | print("i station status") 156 | print("s mono/stereo mode") 157 | print("b bass boost") 158 | print("u mute/unmute") 159 | print("r get rssi data") 160 | print("e softreset chip") 161 | print("q stops the program") 162 | 163 | # Volume and audio control 164 | elif cmd == "+": 165 | v = radio.volume 166 | if v < 15: 167 | radio.setVolume(v + 1) 168 | elif cmd == "-": 169 | v = radio.volume 170 | if v > 0: 171 | radio.setVolume(v - 1) 172 | 173 | # Toggle mute mode 174 | elif cmd == "u": 175 | radio.setMute(not radio.mute) 176 | # Toggle stereo mode 177 | elif cmd == "s": 178 | radio.setMono(not radio.mono) 179 | # Toggle bass boost 180 | elif cmd == "b": 181 | radio.setBassBoost(not radio.bassBoost) 182 | 183 | # Frequency control 184 | elif cmd == ">": 185 | # Goes to the next preset station 186 | if i_sidx < (len(presets) - 1): 187 | i_sidx = i_sidx + 1 188 | radio.setFreq(presets[i_sidx]) 189 | elif cmd == "<": 190 | # Goes to the previous preset station 191 | if i_sidx > 0: 192 | i_sidx = i_sidx - 1 193 | radio.setFreq(presets[i_sidx]) 194 | 195 | # Set frequency 196 | elif cmd == "f": 197 | radio.setFreq(value) 198 | 199 | # Seek up/down 200 | elif cmd == ".": 201 | radio.seekUp() 202 | elif cmd == ",": 203 | radio.seekDown() 204 | 205 | # Display current signal strength 206 | elif cmd == "r": 207 | print("RSSI: " + str(radio.getRssi())) 208 | 209 | # Soft reset chip 210 | elif cmd == "e": 211 | radio.softReset() 212 | 213 | # Not in help 214 | elif cmd == "!": 215 | radio.term() 216 | 217 | elif cmd == "i": 218 | # Display chip info 219 | s = radio.formatFreq() 220 | print("Station: " + s) 221 | print("Radio info: ") 222 | print("RDS -> " + str(radio.rds)) 223 | print("TUNED -> " + str(radio.tuned)) 224 | print("STEREO -> " + str(not radio.mono)) 225 | print("Audio info: ") 226 | print("BASS -> " + str(radio.bassBoost)) 227 | print("MUTE -> " + str(radio.mute)) 228 | print("SOFTMUTE -> " + str(radio.softMute)) 229 | print("VOLUME -> " + str(radio.volume)) 230 | 231 | 232 | print_rds = False 233 | radio.sendRDS = rds.processData 234 | runSerialCommand("?", 0) 235 | 236 | print("-> ", end="") 237 | 238 | while True: 239 | 240 | ble.start_advertising(advertisement) 241 | 242 | while ble.connected: 243 | if uart_service.in_waiting: 244 | # Packet is arriving. 245 | packet = Packet.from_stream(uart_service) 246 | if isinstance(packet, ButtonPacket) and packet.pressed: 247 | if packet.button == ButtonPacket.RIGHT: # UP button pressed 248 | radio.seekUp() 249 | elif packet.button == ButtonPacket.LEFT: # DOWN button pressed 250 | radio.seekDown() 251 | elif packet.button == ButtonPacket.BUTTON_1: # BUTTON 1 button pressed 252 | # Goes to the next preset station 253 | if i_sidx < (len(presets) - 1): 254 | i_sidx = i_sidx + 1 255 | radio.setFreq(presets[i_sidx]) 256 | elif i_sidx == 6: 257 | i_sidx = 0 258 | radio.setFreq(presets[i_sidx]) 259 | elif packet.button == ButtonPacket.BUTTON_2: # BUTTON 2 button pressed 260 | radio.setMute(not radio.mute) 261 | elif packet.button == ButtonPacket.BUTTON_3: # BUTTON 3 button pressed 262 | # Goes preset station 2 263 | radio.setFreq(presets[2]) 264 | elif packet.button == ButtonPacket.BUTTON_4: # BUTTON 4 button pressed 265 | # Goes preset station 4 266 | radio.setFreq(presets[4]) 267 | elif packet.button == ButtonPacket.UP: # UP button pressed 268 | v = radio.volume 269 | if v < 15: 270 | radio.setVolume(v + 1) 271 | elif packet.button == ButtonPacket.DOWN: # DOWN button pressed 272 | v = radio.volume 273 | if v > 0: 274 | radio.setVolume(v - 1) 275 | serial_read() 276 | radio.checkRDS() 277 | new_time = time.monotonic() 278 | if (new_time - initial_time) > toggle_frequency: 279 | print_rds = not print_rds 280 | if print_rds: 281 | if rdstext == "": 282 | drawText("No rds data") 283 | else: 284 | if len(rdstext.split(" ")) > 1: 285 | drawText(rdstext) 286 | else: 287 | drawText("Unclear rds data") 288 | else: 289 | drawText(radio.formatFreq()) 290 | initial_time = new_time 291 | 292 | while not ble.connected: 293 | # Wait for a connection. 294 | # Main loop 295 | if not switch1.value: 296 | print("Seek Up pressed - button 1") 297 | radio.seekUp() 298 | time.sleep(0.01) # debounce delay 299 | 300 | if not switch2.value: 301 | print("Seek Down pressed - button 2") 302 | radio.seekDown() 303 | time.sleep(0.01) # debounce delay 304 | 305 | if not switch3.value: 306 | print("mute pressed - button 3") 307 | radio.setMute(not radio.mute) 308 | time.sleep(0.01) # debounce delay 309 | 310 | if not switch4.value: 311 | print("Preset up pressed - button 4") 312 | # Goes to the next preset station 313 | 314 | print (i_sidx) 315 | if i_sidx < (len(presets) - 1): 316 | i_sidx = i_sidx + 1 317 | radio.setFreq(presets[i_sidx]) 318 | 319 | elif i_sidx == 6: 320 | i_sidx = 0 321 | radio.setFreq(presets[i_sidx]) 322 | time.sleep(0.01) # debounce delay 323 | 324 | if not switch5.value: 325 | print("Volume Up pressed - button 5") 326 | v = radio.volume 327 | if v < 15: 328 | radio.setVolume(v + 1) 329 | time.sleep(0.08) # debounce delay 330 | 331 | if not switch6.value: 332 | print("Volume Down pressed - button 6") 333 | v = radio.volume 334 | if v > 0: 335 | radio.setVolume(v - 1) 336 | time.sleep(0.01) # debounce delay 337 | 338 | 339 | serial_read() 340 | radio.checkRDS() 341 | new_time = time.monotonic() 342 | if (new_time - initial_time) > toggle_frequency: 343 | print_rds = not print_rds 344 | if print_rds: 345 | if rdstext == "": 346 | drawText("No rds data") 347 | else: 348 | if len(rdstext.split(" ")) > 1: 349 | drawText(rdstext) 350 | else: 351 | drawText("Unclear rds data") 352 | else: 353 | drawText(radio.formatFreq()) 354 | initial_time = new_time -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/__init__.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/adafruit.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/adafruit.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/apple.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/apple.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/standard.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/standard.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/attributes/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/attributes/__init__.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/__init__.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/float.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/float.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/int.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/int.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/stream.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/stream.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/string.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/string.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/services/circuitpython.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble/services/circuitpython.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble_radio.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_ble_radio.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_display_text/bitmap_label.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_display_text/bitmap_label.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_display_text/label.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_display_text/label.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_displayio_ssd1306.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/adafruit_displayio_ssd1306.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/advertising/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/advertising/__init__.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/advertising/adafruit.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/advertising/adafruit.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/advertising/apple.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/advertising/apple.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/advertising/standard.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/advertising/standard.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/attributes/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/attributes/__init__.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/characteristics/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/characteristics/__init__.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/characteristics/float.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/characteristics/float.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/characteristics/int.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/characteristics/int.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/characteristics/stream.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/characteristics/stream.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/characteristics/string.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/characteristics/string.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/neopixel.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/neopixel.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/services/circuitpython.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/services/circuitpython.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/simpleio.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/simpleio.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/tinkeringtech_rda5807m.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes FM Kit/examples/lib/adafruit_ble/tinkeringtech_rda5807m.mpy -------------------------------------------------------------------------------- /ScoutMakes FM Kit/examples/lib/adafruit_ble/tinkeringtech_rda5807m.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2021 Vid Osep for TinkeringTech 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 13 | # all 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 21 | # THE SOFTWARE. 22 | """ 23 | `tinkeringtech_rda5807m` 24 | ================================================================================ 25 | 26 | CircuitPython helper library for the RDA5807M FM radio module. 27 | 28 | 29 | * Author(s): TinkeringTech & Vid Osep 30 | 31 | Implementation Notes 32 | -------------------- 33 | 34 | **Hardware:** 35 | 36 | .. todo:: Add links to any specific hardware product page(s), or category page(s). Use unordered list & hyperlink rST 37 | inline format: "* `Link Text `_" 38 | 39 | **Software and Dependencies:** 40 | 41 | * Adafruit CircuitPython firmware for the supported boards: 42 | https://github.com/adafruit/circuitpython/releases 43 | 44 | * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice 45 | """ 46 | 47 | # imports 48 | 49 | __version__ = "0.0.0-auto.0" 50 | __repo__ = "https://github.com/tinkeringtech/rda5807m.git" 51 | 52 | import time 53 | 54 | # Registers definitions 55 | FREQ_STEPS = 10 56 | RADIO_REG_CHIPID = 0x00 57 | 58 | RADIO_REG_CTRL = 0x02 59 | RADIO_REG_CTRL_OUTPUT = 0x8000 60 | RADIO_REG_CTRL_UNMUTE = 0x4000 61 | RADIO_REG_CTRL_MONO = 0x2000 62 | RADIO_REG_CTRL_BASS = 0x1000 63 | RADIO_REG_CTRL_SEEKUP = 0x0200 64 | RADIO_REG_CTRL_SEEK = 0x0100 65 | RADIO_REG_CTRL_RDS = 0x0008 66 | RADIO_REG_CTRL_NEW = 0x0004 67 | RADIO_REG_CTRL_RESET = 0x0002 68 | RADIO_REG_CTRL_ENABLE = 0x0001 69 | 70 | RADIO_REG_CHAN = 0x03 71 | RADIO_REG_CHAN_SPACE = 0x0003 72 | RADIO_REG_CHAN_SPACE_100 = 0x0000 73 | RADIO_REG_CHAN_BAND = 0x000C 74 | RADIO_REG_CHAN_BAND_FM = 0x0000 75 | RADIO_REG_CHAN_BAND_FMWORLD = 0x0008 76 | RADIO_REG_CHAN_TUNE = 0x0010 77 | RADIO_REG_CHAN_NR = 0x7FC0 78 | 79 | RADIO_REG_R4 = 0x04 80 | RADIO_REG_R4_EM50 = 0x0800 81 | RADIO_REG_R4_SOFTMUTE = 0x0200 82 | RADIO_REG_R4_AFC = 0x0100 83 | 84 | RADIO_REG_VOL = 0x05 85 | RADIO_REG_VOL_VOL = 0x000F 86 | 87 | RADIO_REG_RA = 0x0A 88 | RADIO_REG_RA_RDS = 0x8000 89 | RADIO_REG_RA_RDSBLOCK = 0x0800 90 | RADIO_REG_RA_STEREO = 0x0400 91 | RADIO_REG_RA_NR = 0x03FF 92 | RADIO_REG_RA_STC = 0x4000 93 | RADIO_REG_RA_SF = 0x2000 94 | 95 | RADIO_REG_RB = 0x0B 96 | RADIO_REG_RB_FMTRUE = 0x0100 97 | RADIO_REG_RB_FMREADY = 0x0080 98 | 99 | RADIO_REG_RDSA = 0x0C 100 | RADIO_REG_RDSB = 0x0D 101 | RADIO_REG_RDSC = 0x0E 102 | RADIO_REG_RDSD = 0x0F 103 | 104 | 105 | # Radio class definition 106 | class Radio: 107 | """ 108 | A class for communicating with the rda5807m chip 109 | 110 | ... 111 | 112 | Attributes 113 | ---------- 114 | registers : list 115 | virtual registers 116 | address : int 117 | chip's address 118 | maxvolume : int 119 | maximum volume 120 | freqLow, freqHigh, freqSteps : int 121 | min and max frequency for FM band, and frequency steps 122 | board : busio.i2c object 123 | used for i2c communication 124 | frequency : int 125 | current chip frequency 126 | volume : int 127 | current chip volume 128 | bassBoost : boolean 129 | toggle bass boost on the chip 130 | mute : boolean 131 | toggle mute/unmute 132 | softMute : boolean 133 | toggle soft mute (mute if signal strength too low) 134 | mono : boolean 135 | toggle stereo mode 136 | rds : boolean 137 | toggle rds 138 | tuned : boolean 139 | is chip tuned 140 | band : string 141 | selected band (FM or FMWORLD) 142 | """ 143 | 144 | # Initialize virtual registers 145 | registers = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 146 | 147 | # Chip constants 148 | address = 0x11 149 | maxvolume = 15 150 | 151 | # FMWORLD Band 152 | freqLow = 8700 153 | freqHigh = 10800 154 | freqSteps = 10 155 | 156 | # Set default frequency and volume 157 | def __init__(self, board, frequency=10000, volume=1): 158 | self.board = board 159 | self.frequency = frequency 160 | 161 | # Basic audio info 162 | self.volume = volume 163 | self.bassBoost = False 164 | self.mute = False 165 | self.softMute = False 166 | 167 | # Radio features from the chip 168 | self.mono = False 169 | self.rds = False 170 | self.tuned = False 171 | 172 | # Is the signal strong enough to get rds? 173 | self.rdsReady = False 174 | self.rdsThreshold = 20 # rssi threshold for accepting rds - change this to value most appropriate 175 | self.interval = 10 # Used for timing rssi checks - in seconds 176 | self.initial = time.monotonic() # Time since boot 177 | 178 | # Band - Default FMWORLD 179 | # 1. FM 180 | # 2. FMWORLD 181 | self.band = "FM" 182 | 183 | # Functions saves register values to virtual registers, sets the basic frequency and volume 184 | self.setup() 185 | print("Got to point 1!") 186 | self.tune() # Apply volume and frequency 187 | 188 | def setup(self): 189 | # Initialize registers 190 | self.registers[RADIO_REG_CHIPID] = 0x58 191 | self.registers[RADIO_REG_CTRL] = (RADIO_REG_CTRL_RESET | RADIO_REG_CTRL_ENABLE) | ( 192 | RADIO_REG_CTRL_UNMUTE | RADIO_REG_CTRL_OUTPUT) 193 | # self.registers[RADIO_REG_R4] = RADIO_REG_R4_EM50 194 | # Initialized to volume - 6 by default 195 | self.registers[RADIO_REG_VOL] = 0x84D1 196 | # Other registers are already set to zero 197 | # Update registers 198 | self.saveRegister(RADIO_REG_CTRL) 199 | self.saveRegister(RADIO_REG_VOL) 200 | 201 | self.registers[ 202 | RADIO_REG_CTRL] = RADIO_REG_CTRL_ENABLE | RADIO_REG_CTRL_NEW | RADIO_REG_CTRL_RDS | RADIO_REG_CTRL_UNMUTE | RADIO_REG_CTRL_OUTPUT 203 | self.saveRegister(RADIO_REG_CTRL) 204 | 205 | # Turn on bass boost and rds 206 | self.setBassBoost(True) 207 | 208 | self.rds = True 209 | self.mute = False 210 | 211 | def tune(self): 212 | # Tunes radio to current frequency and volume 213 | self.setFreq(self.frequency) 214 | self.setVolume(self.volume) 215 | self.tuned = True 216 | 217 | def setFreq(self, freq): 218 | # Sets frequency to freq 219 | if freq < self.freqLow: 220 | freq = self.freqLow 221 | elif freq > self.freqHigh: 222 | freq = self.freqHigh 223 | self.frequency = freq 224 | newChannel = (freq - self.freqLow) // 10 225 | 226 | regChannel = RADIO_REG_CHAN_TUNE # Enable tuning 227 | regChannel = regChannel | (newChannel << 6) 228 | 229 | # Enable output, unmute 230 | self.registers[RADIO_REG_CTRL] = self.registers[RADIO_REG_CTRL] | ( 231 | RADIO_REG_CTRL_OUTPUT | RADIO_REG_CTRL_UNMUTE | RADIO_REG_CTRL_RDS | RADIO_REG_CTRL_ENABLE) 232 | self.saveRegister(RADIO_REG_CTRL) 233 | 234 | # Save frequency to register 235 | self.registers[RADIO_REG_CHAN] = regChannel 236 | self.saveRegister(RADIO_REG_CHAN) 237 | time.sleep(0.2) 238 | 239 | # Adjust volume 240 | self.saveRegister(RADIO_REG_VOL) 241 | time.sleep(0.3) 242 | 243 | # Get frequnecy 244 | self.getFreq() 245 | 246 | if self.getRssi() > self.rdsThreshold: 247 | self.rdsReady = True 248 | else: 249 | self.rdsReady = False 250 | 251 | def getFreq(self): 252 | # Read register RA 253 | self.writeBytes(bytes([RADIO_REG_RA])) 254 | self.registers[RADIO_REG_RA] = self.read16() 255 | 256 | ch = self.registers[RADIO_REG_RA] & RADIO_REG_RA_NR 257 | 258 | self.frequency = self.freqLow + ch * 10 259 | return self.frequency 260 | 261 | def formatFreq(self): 262 | # Formats the current frequency for better readabilitiy 263 | freq = self.frequency 264 | 265 | s = str(freq) 266 | s = list(s) 267 | last_two = s[-2:] 268 | s[-2] = "." 269 | s[-1] = last_two[0] 270 | s.append(last_two[1]) 271 | return ("".join(s)) + " Mhz" 272 | 273 | def setBand(self, band): 274 | # Changes bands to FM or FMWORLD 275 | self.band = band 276 | if band == "FM": 277 | r = RADIO_REG_CHAN_BAND_FM 278 | else: 279 | r = RADIO_REG_CHAN_BAND_FMWORLD 280 | self.registers[RADIO_REG_CHAN] = (r | RADIO_REG_CHAN_SPACE_100) 281 | self.saveRegister(RADIO_REG_CHAN) 282 | 283 | def term(self): 284 | # Terminates all receiver functions 285 | self.setVolume(0) 286 | self.registers[RADIO_REG_CTRL] = 0x0000 287 | self.saveRegisters 288 | 289 | def setBassBoost(self, switchOn): 290 | # Switches bass boost to true or false 291 | self.bassBoost = switchOn 292 | regCtrl = self.registers[RADIO_REG_CTRL] 293 | if switchOn: 294 | regCtrl = regCtrl | RADIO_REG_CTRL_BASS 295 | else: 296 | regCtrl = regCtrl & (~RADIO_REG_CTRL_BASS) 297 | self.registers[RADIO_REG_CTRL] = regCtrl 298 | self.saveRegister(RADIO_REG_CTRL) 299 | 300 | def setMono(self, switchOn): 301 | # Switches mono to 0 or 1 302 | self.mono = switchOn 303 | self.registers[RADIO_REG_CTRL] = self.registers[RADIO_REG_CTRL] & (~RADIO_REG_CTRL_SEEK) 304 | if switchOn: 305 | self.registers[RADIO_REG_CTRL] = self.registers[RADIO_REG_CTRL] | RADIO_REG_CTRL_MONO 306 | else: 307 | self.registers[RADIO_REG_CTRL] = self.registers[RADIO_REG_CTRL] & (~RADIO_REG_CTRL_MONO) 308 | self.saveRegister(RADIO_REG_CTRL) 309 | 310 | def setMute(self, switchOn): 311 | # Switches mute off or on 312 | self.mute = switchOn 313 | if (switchOn): 314 | self.registers[RADIO_REG_CTRL] = self.registers[RADIO_REG_CTRL] & (~RADIO_REG_CTRL_UNMUTE) 315 | else: 316 | self.registers[RADIO_REG_CTRL] = self.registers[RADIO_REG_CTRL] | RADIO_REG_CTRL_UNMUTE 317 | self.saveRegister(RADIO_REG_CTRL) 318 | 319 | def setSoftMute(self, switchOn): 320 | # Switches soft mute off or on 321 | self.softMute = switchOn 322 | if switchOn: 323 | self.registers[RADIO_REG_R4] = self.registers[RADIO_REG_R4] | RADIO_REG_R4_SOFTMUTE 324 | else: 325 | self.registers[RADIO_REG_R4] = self.registers[RADIO_REG_R4] & (~RADIO_REG_R4_SOFTMUTE) 326 | self.saveRegister(RADIO_REG_R4) 327 | 328 | def softReset(self): 329 | # Soft reset chip 330 | self.registers[RADIO_REG_CTRL] = self.registers[RADIO_REG_CTRL] | RADIO_REG_CTRL_RESET 331 | self.saveRegister(RADIO_REG_CTRL) 332 | time.sleep(2) 333 | self.registers[RADIO_REG_CTRL] = self.registers[RADIO_REG_CTRL] & (~RADIO_REG_CTRL_RESET) 334 | self.saveRegister(RADIO_REG_CTRL) 335 | 336 | def seekUp(self): 337 | # Start seek mode upwards 338 | self.registers[RADIO_REG_CTRL] = self.registers[RADIO_REG_CTRL] | RADIO_REG_CTRL_SEEKUP 339 | self.registers[RADIO_REG_CTRL] = self.registers[RADIO_REG_CTRL] | RADIO_REG_CTRL_SEEK 340 | self.saveRegister(RADIO_REG_CTRL) 341 | 342 | # Wait until scan is over 343 | time.sleep(1) 344 | self.getFreq() 345 | self.registers[RADIO_REG_CTRL] = self.registers[RADIO_REG_CTRL] & (~RADIO_REG_CTRL_SEEK) 346 | self.saveRegister(RADIO_REG_CTRL) 347 | 348 | def seekDown(self): 349 | # Start seek mode downwards 350 | self.registers[RADIO_REG_CTRL] = self.registers[RADIO_REG_CTRL] & (~RADIO_REG_CTRL_SEEKUP) 351 | self.registers[RADIO_REG_CTRL] = self.registers[RADIO_REG_CTRL] | RADIO_REG_CTRL_SEEK 352 | self.saveRegister(RADIO_REG_CTRL) 353 | 354 | # Wait until scan is over 355 | time.sleep(1) 356 | self.getFreq() 357 | self.registers[RADIO_REG_CTRL] = self.registers[RADIO_REG_CTRL] & (~RADIO_REG_CTRL_SEEK) 358 | self.saveRegister(RADIO_REG_CTRL) 359 | 360 | def setVolume(self, volume): 361 | # Sets the volume 362 | if (volume > self.maxvolume): 363 | volume = self.maxvolume 364 | self.volume = volume 365 | self.registers[RADIO_REG_VOL] = self.registers[RADIO_REG_VOL] & (~RADIO_REG_VOL_VOL) 366 | self.registers[RADIO_REG_VOL] = self.registers[RADIO_REG_VOL] | volume 367 | self.saveRegister(RADIO_REG_VOL) 368 | 369 | def checkRDS(self): 370 | # Check for rds data 371 | self.checkThreshold() 372 | if self.sendRDS and self.rdsReady: 373 | self.registers[RADIO_REG_RA] = self.read16() 374 | 375 | if (self.registers[RADIO_REG_RA] & RADIO_REG_RA_RDS): 376 | # Check for new RDS data available 377 | result = False 378 | 379 | self.writeBytes(bytes([RADIO_REG_RDSA])) 380 | 381 | newData = self.read16() 382 | if newData != self.registers[RADIO_REG_RDSA]: 383 | self.registers[RADIO_REG_RDSA] = newData 384 | result = True 385 | 386 | newData = self.read16() 387 | if newData != self.registers[RADIO_REG_RDSB]: 388 | self.registers[RADIO_REG_RDSB] = newData 389 | result = True 390 | 391 | newData = self.read16() 392 | if newData != self.registers[RADIO_REG_RDSC]: 393 | self.registers[RADIO_REG_RDSC] = newData 394 | result = True 395 | 396 | newData = self.read16() 397 | if newData != self.registers[RADIO_REG_RDSD]: 398 | self.registers[RADIO_REG_RDSD] = newData 399 | result = True 400 | 401 | if result: 402 | self.sendRDS(self.registers[RADIO_REG_RDSA], self.registers[RADIO_REG_RDSB], 403 | self.registers[RADIO_REG_RDSC], self.registers[RADIO_REG_RDSD]) 404 | 405 | def checkThreshold(self): 406 | # Check every interval if the signal strength is strong enough for receiving rds data 407 | currentTime = time.monotonic() 408 | if (currentTime - self.initial) > self.interval: 409 | if self.getRssi() >= self.rdsThreshold: 410 | self.rdsReady = True 411 | else: 412 | self.rdsReady = False 413 | self.initial = currentTime 414 | 415 | def getRssi(self): 416 | # Get the current signal strength 417 | self.writeBytes(bytes([RADIO_REG_RB])) 418 | self.registers[RADIO_REG_RB] = self.read16() 419 | self.rssi = self.registers[RADIO_REG_RB] >> 10 420 | return self.rssi 421 | 422 | def getRadioInfo(self): 423 | # Reads info from chip and saves it into virtual memory 424 | self.readRegisters() 425 | if self.registers[RADIO_REG_RA] & RADIO_REG_RA_RDS: 426 | self.rds = True 427 | self.rssi = self.registers[RADIO_REG_RB] >> 10 428 | if self.registers[RADIO_REG_RB] & RADIO_REG_RB_FMTRUE: 429 | self.tuned = True 430 | if self.registers[RADIO_REG_CTRL] & RADIO_REG_CTRL_MONO: 431 | self.mono = True 432 | 433 | def saveRegister(self, regN): 434 | # Write register from memory to receiver 435 | regVal = self.registers[regN] # 16 bit value in list 436 | regVal1 = regVal >> 8 437 | regVal2 = regVal & 255 438 | 439 | self.writeBytes(bytes([regN, regVal1, regVal2])) # regN is a register address 440 | 441 | def writeBytes(self, values): 442 | with self.board: 443 | self.board.write(values) 444 | 445 | def saveRegisters(self): 446 | for i in range(2, 7): 447 | self.saveRegister(i) 448 | 449 | def read16(self): 450 | # Reads two bytes, returns as one 16 bit integer 451 | with self.board: 452 | result = bytearray(2) 453 | self.board.readinto(result) 454 | return result[0] * 256 + result[1] 455 | 456 | def readRegisters(self): 457 | # Reads register from chip to virtual memory 458 | with self.board: 459 | self.board.write(bytes([RADIO_REG_RA])) 460 | for i in range(6): 461 | self.registers[0xA + i] = self.read16() 462 | 463 | 464 | def replaceElement(index, text, newchar): 465 | # Replaces char in string at index with newchar 466 | newlist = list(text) 467 | if type(newchar) is int: 468 | if newchar < 127 and newchar > 31: 469 | newlist[index] = chr(newchar) 470 | else: 471 | newlist[index] = " " 472 | else: 473 | newlist[index] = newchar 474 | return "".join(newlist) 475 | 476 | 477 | class RDSParser: 478 | """ 479 | A class used for parsing rds data into readable strings 480 | """ 481 | 482 | def __init__(self): 483 | # RDS Values 484 | self.rdsGroupType = None 485 | # Traffic programme 486 | self.rdsTP = None 487 | # Program type 488 | self.rdsPTY = None 489 | # RDS text chars get stored here 490 | self.textAB = None 491 | self.last_textAB = None 492 | # Time 493 | self.lastMinutes1 = 0 494 | self.lastMinutes2 = 0 495 | # Previous index 496 | self.lastTextIDX = 0 497 | # Functions initialization 498 | self.sendServiceName = None 499 | self.sendText = None 500 | self.sendTime = None 501 | # Radio text 502 | self.RDSText = " " * 66 503 | # Station names 504 | self.PSName1 = "--------" 505 | self.PSName2 = self.PSName1 506 | self.programServiceName = " " 507 | 508 | def init(self): 509 | self.RDSText = " " * 66 510 | self.PSName1 = "--------" 511 | self.PSName2 = self.PSName1 512 | self.programServiceName = " " 513 | self.lastTextIDX = 0 514 | 515 | def attachServicenNameCallback(self, newFunction): 516 | self.sendServiceName = newFunction 517 | 518 | def attachTextCallback(self, newFunction): 519 | self.sendText = newFunction 520 | 521 | def attachTimeCallback(self, newFunction): 522 | self.sendTime = newFunction 523 | 524 | def processData(self, block1, block2, block3, block4): 525 | 526 | # Analyzing block 1 527 | if block1 == 0: 528 | # If block1 set to zero, reset all RDS info 529 | self.init() 530 | if self.sendServiceName: 531 | self.sendServiceName(self.programServiceName) 532 | if self.sendText: 533 | self.sendText("") 534 | return 0 535 | 536 | # Block 2 537 | rdsGroupType = 0x0A | ((block2 & 0xF000) >> 8) | ((block2 & 0x0800) >> 11) 538 | self.rdsTP = block2 & 0x0400 539 | self.rdsPTY = block2 & 0x0400 540 | 541 | # rdsGroupType cases 542 | if rdsGroupType == 0x0A: 543 | pass 544 | 545 | elif rdsGroupType == 0x0B: 546 | # Data received is part of Service Station name 547 | idx = 2 * (block2 & 0x0003) 548 | 549 | c1 = block4 >> 8 550 | c2 = block4 & 0x00FF 551 | 552 | # Check that the data was successfuly received 553 | if ((self.PSName1[idx] == c1) and (self.PSName1[idx + 1] == c2)): 554 | self.PSName2 = replaceElement(idx, self.PSName2, c1) 555 | self.PSName2 = replaceElement(idx + 1, self.PSName2, c2) 556 | if (idx == 6) and (self.PSName2 == self.PSName1): 557 | if self.programServiceName != self.PSName2: 558 | # Publish station name 559 | self.programServiceName = self.PSName2 560 | if self.sendServiceName: 561 | self.sendServiceName(self.programServiceName) 562 | 563 | if (self.PSName1[idx] != c1) or (self.PSName1[idx + 1] != c2): 564 | self.PSName1 = replaceElement(idx, self.PSName1, c1) 565 | self.PSName1 = replaceElement(idx + 1, self.PSName1, c2) 566 | 567 | elif rdsGroupType == 0x2A: 568 | time.sleep(0.1) 569 | self.textAB = block2 & 0x0010 570 | idx = 4 * (block2 & 0x000F) 571 | if idx < self.lastTextIDX: 572 | if (self.sendText): 573 | self.sendText(self.RDSText) 574 | self.lastTextIDX = idx 575 | 576 | if (self.textAB != self.last_textAB): 577 | # Clear buffer 578 | self.last_textAB = self.textAB 579 | self.RDSText = " " * 66 580 | 581 | self.RDSText = replaceElement(idx, self.RDSText, block3 >> 8) 582 | idx += 1 583 | self.RDSText = replaceElement(idx, self.RDSText, block3 & 0x00FF) 584 | idx += 1 585 | self.RDSText = replaceElement(idx, self.RDSText, block4 >> 8) 586 | idx += 1 587 | self.RDSText = replaceElement(idx, self.RDSText, block4 & 0x00FF) 588 | idx += 1 589 | elif rdsGroupType == 0x4A: 590 | time.sleep(0.1) 591 | off = (block4) & 0x3F 592 | mins = (block4 >> 6) & 0x3F 593 | mins += 60 * (((block3 & 0x0001) << 4) | ((block4 >> 12) & 0x0F)) 594 | if off & 0x20: 595 | mins -= 30 * (off & 0x1F) 596 | else: 597 | mins += 30 * (off & 0x1F) 598 | 599 | # Check if function sendTime was set, and chek if the time is different from last time 600 | if (self.sendTime) and (mins != self.lastMinutes1): 601 | # Checks if time appeared in the last two instances - To avoid noise 602 | if self.lastMinutes1 + 1 == mins or self.lastMinutes2 + 1 == mins or self.lastMinutes1 == 0 or self.lastMinutes2 == 0: 603 | self.lastMinutes2 = self.lastMinutes1 604 | self.lastMinutes1 = mins 605 | self.sendTime(mins // 60, mins % 60) 606 | -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/README.md: -------------------------------------------------------------------------------- 1 | **ScoutMakes Robot STEM Electronic Kits** 2 | 3 | **Open Source Hardware Association certified OSHWA UID US000676** 4 | 5 | These are the source design files for the ScoutMakes Robot Electronic Kit. 6 | 7 | The kits can be bought at https://www.scoutmakes.com. 8 | Please support this eduactiional company by buying our products focused on cultivating more engineers! 9 | 10 | The Chassis 3D print TinkerCad files can be found at https://www.tinkercad.com/things/9izqkyQWX8r 11 | 12 | Designed by TinkeringTech. 13 | License: Creative Commons ShareAlike 3.0 United States (CC BY-SA 3.0 US) 14 | License: MIT License 15 | Check license.txt for more information All text above must be included in any redistribution. 16 | 17 | **Robot Kit Features & Specifications** 18 | - Open hardware and open source software 19 | - Quick and easy assembly (all mechanical hardware is included in the kit) 20 | - Controllable over BLE using an iOS or Android app 21 | - A piezoelectric speaker allows your robot to make sounds 22 | - Powered by a rechargeable, LiPo battery 23 | - Four NeoPixels on the robot board provide illumination 24 | - Modify the source files for the robot chassis and 3D print your own designs 25 | - Quality, N20 motors with metal gear boxes and rubber tires 26 | -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/Robot Kit 3D print files/Final ScoutMakes RobotKit Chassis v2.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/Robot Kit 3D print files/Final ScoutMakes RobotKit Chassis v2.stl -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/Robot Kit 3D print files/Final ScoutMakes RobotKit Support v2.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/Robot Kit 3D print files/Final ScoutMakes RobotKit Support v2.stl -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/Robot Kit 3D print files/TinkerCad 3D print project: -------------------------------------------------------------------------------- 1 | This is the location of the main TinkerCad 3D print source CAD files for the robot chassis and support. 2 | https://www.tinkercad.com/things/9izqkyQWX8r 3 | -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/Robot-kit-pictures/robotkit_1.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/Robot-kit-pictures/robotkit_1.JPG -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/Robot-kit-pictures/robotkit_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/Robot-kit-pictures/robotkit_2.jpg -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/Robot-kit-pictures/robotkit_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/Robot-kit-pictures/robotkit_3.jpg -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/Bluetooth_diagnostics.py: -------------------------------------------------------------------------------- 1 | """ 2 | This test will initialize the BLE module and accept commands from the Bluetooth app controller arrows and manipulate the onboard NEOPIXEL colors. 3 | 4 | To use: 5 | - Open the BLE app (Adafruit's Bluefruit Connect available in iOS and Android). 6 | - Connect to the CIRCUITPYTHON board. 7 | - Select the controller module. 8 | - Select control pad. 9 | - Press the arrows to see the NEOPIXEL change color according to the following commands: 10 | RIGHT = RED 11 | LEFT = BLUE 12 | UP = GREEN 13 | DOWN = WHITE 14 | """ 15 | 16 | from adafruit_ble import BLERadio 17 | from adafruit_ble.advertising.standard import ProvideServicesAdvertisement 18 | from adafruit_ble.services.nordic import UARTService 19 | from adafruit_bluefruit_connect.packet import Packet 20 | # Only the packet classes that are imported will be known to Packet. 21 | from adafruit_bluefruit_connect.button_packet import ButtonPacket 22 | 23 | import time 24 | import board 25 | import pulseio 26 | import neopixel 27 | import busio 28 | 29 | pixel_pin = board.NEOPIXEL 30 | num_pixels = 1 31 | 32 | pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False) 33 | 34 | RED = (255, 0, 0) 35 | YELLOW = (255, 150, 0) 36 | GREEN = (0, 255, 0) 37 | CYAN = (0, 255, 255) 38 | BLUE = (0, 0, 255) 39 | PURPLE = (180, 0, 255) 40 | WHITE = (255,255,255) 41 | 42 | ble = BLERadio() 43 | uart_service = UARTService() 44 | advertisement = ProvideServicesAdvertisement(uart_service) 45 | 46 | while True: 47 | ble.start_advertising(advertisement) 48 | while not ble.connected: 49 | pass 50 | 51 | # Now we're connected 52 | 53 | while ble.connected: 54 | if uart_service.in_waiting: 55 | # Packet is arriving. 56 | packet = Packet.from_stream(uart_service) 57 | if isinstance(packet, ButtonPacket) and packet.pressed: 58 | if packet.button == ButtonPacket.RIGHT: # RIGHT button pressed 59 | pixels.fill(RED) 60 | pixels.show() 61 | # Increase or decrease to change the speed of the solid color change. 62 | time.sleep(1) 63 | elif packet.button == ButtonPacket.LEFT: # LEFT button pressed 64 | pixels.fill(BLUE) 65 | pixels.show() 66 | time.sleep(1) 67 | elif packet.button == ButtonPacket.UP: # UP button pressed 68 | pixels.fill(GREEN) 69 | pixels.show() 70 | time.sleep(1) 71 | elif packet.button == ButtonPacket.DOWN: # DOWN button pressed 72 | pixels.fill(WHITE) 73 | pixels.show() 74 | time.sleep(1) -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/FM_Radio_Demo.py: -------------------------------------------------------------------------------- 1 | import time 2 | import board 3 | import busio 4 | import supervisor 5 | import displayio 6 | import terminalio 7 | from adafruit_bus_device.i2c_device import I2CDevice 8 | from adafruit_display_text import label 9 | import adafruit_displayio_ssd1306 10 | import tinkeringtech_rda5807m 11 | from digitalio import DigitalInOut, Direction, Pull 12 | 13 | from adafruit_ble import BLERadio 14 | from adafruit_ble.advertising.standard import ProvideServicesAdvertisement 15 | from adafruit_ble.services.nordic import UARTService 16 | from adafruit_bluefruit_connect.packet import Packet 17 | # Only the packet classes that are imported will be known to Packet. 18 | from adafruit_bluefruit_connect.button_packet import ButtonPacket 19 | 20 | ble = BLERadio() 21 | uart_service = UARTService() 22 | advertisement = ProvideServicesAdvertisement(uart_service) 23 | 24 | switch2 = DigitalInOut(board.D5) 25 | switch2.direction = Direction.INPUT 26 | switch2.pull = Pull.UP 27 | 28 | switch1 = DigitalInOut(board.D6) 29 | switch1.direction = Direction.INPUT 30 | switch1.pull = Pull.UP 31 | 32 | switch3 = DigitalInOut(board.D9) 33 | switch3.direction = Direction.INPUT 34 | switch3.pull = Pull.UP 35 | 36 | switch4 = DigitalInOut(board.D10) 37 | switch4.direction = Direction.INPUT 38 | switch4.pull = Pull.UP 39 | 40 | switch5 = DigitalInOut(board.D11) 41 | switch5.direction = Direction.INPUT 42 | switch5.pull = Pull.UP 43 | 44 | switch6 = DigitalInOut(board.D12) 45 | switch6.direction = Direction.INPUT 46 | switch6.pull = Pull.UP 47 | 48 | # Display 49 | displayio.release_displays() 50 | 51 | presets = [ # Preset stations 52 | 8930, 53 | 9510, 54 | 9710, 55 | 9950, 56 | 10100, 57 | 10110, 58 | 10650 59 | ] 60 | i_sidx = 3 # Starting at station with index 3 61 | 62 | # Initialize i2c bus 63 | i2c = busio.I2C(board.SCL, board.SDA) 64 | 65 | # Receiver i2c communication 66 | address = 0x11 67 | radio_i2c = I2CDevice(i2c, address) 68 | 69 | vol = 1 # Default volume 70 | band = "FM" 71 | 72 | radio = tinkeringtech_rda5807m.Radio(radio_i2c, presets[i_sidx], vol) 73 | radio.setBand(band) # Minimum frequency - 87 Mhz, max - 108 Mhz 74 | rds = tinkeringtech_rda5807m.RDSParser() 75 | 76 | # Display initialization 77 | initial_time = time.monotonic() # Initial time - used for timing 78 | toggle_frequency = 5 # Frequency at which the text changes between radio frequnecy and rds in seconds 79 | display_bus = displayio.I2CDisplay(i2c, device_address=0x3C) 80 | display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32) 81 | rdstext = "No rds data" 82 | 83 | 84 | def drawText(text): 85 | # Write text on display 86 | global display 87 | # Make the display context 88 | splash = displayio.Group(max_size=10) 89 | display.show(splash) 90 | 91 | color_bitmap = displayio.Bitmap(128, 32, 1) 92 | color_palette = displayio.Palette(1) 93 | color_palette[0] = 0x000000 # Black 94 | 95 | bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) 96 | splash.append(bg_sprite) 97 | 98 | # Split text into two lines 99 | temp = text.split(" ") 100 | line1 = temp[0] 101 | line2 = " ".join(temp[1:]) 102 | # Check that lines are not empty 103 | if not line1.strip() or not line2.strip(): 104 | warning = "Unclear rds data" 105 | text_area_1 = label.Label(terminalio.FONT, text=warning, color=0xFFFF00, x=5, y=5) 106 | splash.append(text_area_1) 107 | else: 108 | # Line 1 109 | text_area_1 = label.Label(terminalio.FONT, text=line1, color=0xFFFF00, x=5, y=5) 110 | splash.append(text_area_1) 111 | # Line 2 112 | text_area_2 = label.Label(terminalio.FONT, text=line2, color=0xFFFF00, x=5, y=20) 113 | splash.append(text_area_2) 114 | 115 | 116 | # RDS text handle 117 | def textHandle(rdsText): 118 | global rdstext 119 | rdstext = rdsText 120 | print(rdsText) 121 | 122 | 123 | rds.attachTextCallback(textHandle) 124 | 125 | 126 | # Read input from serial 127 | def serial_read(): 128 | if supervisor.runtime.serial_bytes_available: 129 | command = input() 130 | command = command.split(" ") 131 | cmd = command[0] 132 | if cmd == "f": 133 | value = command[1] 134 | runSerialCommand(cmd, int(value)) 135 | else: 136 | runSerialCommand(cmd) 137 | time.sleep(0.3) 138 | print("-> ", end="") 139 | 140 | 141 | def runSerialCommand(cmd, value=0): 142 | # Executes a command 143 | # Starts with a character, and optionally followed by an integer, if required 144 | global i_sidx 145 | global presets 146 | if cmd == "?": 147 | print("? help") 148 | print("+ increase volume") 149 | print("- decrease volume") 150 | print("> next preset") 151 | print("< previous preset") 152 | print(". scan up ") 153 | print(", scan down ") 154 | print("f direct frequency input") 155 | print("i station status") 156 | print("s mono/stereo mode") 157 | print("b bass boost") 158 | print("u mute/unmute") 159 | print("r get rssi data") 160 | print("e softreset chip") 161 | print("q stops the program") 162 | 163 | # Volume and audio control 164 | elif cmd == "+": 165 | v = radio.volume 166 | if v < 15: 167 | radio.setVolume(v + 1) 168 | elif cmd == "-": 169 | v = radio.volume 170 | if v > 0: 171 | radio.setVolume(v - 1) 172 | 173 | # Toggle mute mode 174 | elif cmd == "u": 175 | radio.setMute(not radio.mute) 176 | # Toggle stereo mode 177 | elif cmd == "s": 178 | radio.setMono(not radio.mono) 179 | # Toggle bass boost 180 | elif cmd == "b": 181 | radio.setBassBoost(not radio.bassBoost) 182 | 183 | # Frequency control 184 | elif cmd == ">": 185 | # Goes to the next preset station 186 | if i_sidx < (len(presets) - 1): 187 | i_sidx = i_sidx + 1 188 | radio.setFreq(presets[i_sidx]) 189 | elif cmd == "<": 190 | # Goes to the previous preset station 191 | if i_sidx > 0: 192 | i_sidx = i_sidx - 1 193 | radio.setFreq(presets[i_sidx]) 194 | 195 | # Set frequency 196 | elif cmd == "f": 197 | radio.setFreq(value) 198 | 199 | # Seek up/down 200 | elif cmd == ".": 201 | radio.seekUp() 202 | elif cmd == ",": 203 | radio.seekDown() 204 | 205 | # Display current signal strength 206 | elif cmd == "r": 207 | print("RSSI: " + str(radio.getRssi())) 208 | 209 | # Soft reset chip 210 | elif cmd == "e": 211 | radio.softReset() 212 | 213 | # Not in help 214 | elif cmd == "!": 215 | radio.term() 216 | 217 | elif cmd == "i": 218 | # Display chip info 219 | s = radio.formatFreq() 220 | print("Station: " + s) 221 | print("Radio info: ") 222 | print("RDS -> " + str(radio.rds)) 223 | print("TUNED -> " + str(radio.tuned)) 224 | print("STEREO -> " + str(not radio.mono)) 225 | print("Audio info: ") 226 | print("BASS -> " + str(radio.bassBoost)) 227 | print("MUTE -> " + str(radio.mute)) 228 | print("SOFTMUTE -> " + str(radio.softMute)) 229 | print("VOLUME -> " + str(radio.volume)) 230 | 231 | 232 | print_rds = False 233 | radio.sendRDS = rds.processData 234 | runSerialCommand("?", 0) 235 | 236 | print("-> ", end="") 237 | 238 | while True: 239 | 240 | ble.start_advertising(advertisement) 241 | 242 | while ble.connected: 243 | if uart_service.in_waiting: 244 | # Packet is arriving. 245 | packet = Packet.from_stream(uart_service) 246 | if isinstance(packet, ButtonPacket) and packet.pressed: 247 | if packet.button == ButtonPacket.RIGHT: # UP button pressed 248 | radio.seekUp() 249 | elif packet.button == ButtonPacket.LEFT: # DOWN button pressed 250 | radio.seekDown() 251 | elif packet.button == ButtonPacket.BUTTON_1: # BUTTON 1 button pressed 252 | # Goes to the next preset station 253 | if i_sidx < (len(presets) - 1): 254 | i_sidx = i_sidx + 1 255 | radio.setFreq(presets[i_sidx]) 256 | elif i_sidx == 6: 257 | i_sidx = 0 258 | radio.setFreq(presets[i_sidx]) 259 | elif packet.button == ButtonPacket.BUTTON_2: # BUTTON 2 button pressed 260 | radio.setMute(not radio.mute) 261 | elif packet.button == ButtonPacket.BUTTON_3: # BUTTON 3 button pressed 262 | # Goes preset station 2 263 | radio.setFreq(presets[2]) 264 | elif packet.button == ButtonPacket.BUTTON_4: # BUTTON 4 button pressed 265 | # Goes preset station 4 266 | radio.setFreq(presets[4]) 267 | elif packet.button == ButtonPacket.UP: # UP button pressed 268 | v = radio.volume 269 | if v < 15: 270 | radio.setVolume(v + 1) 271 | elif packet.button == ButtonPacket.DOWN: # DOWN button pressed 272 | v = radio.volume 273 | if v > 0: 274 | radio.setVolume(v - 1) 275 | serial_read() 276 | radio.checkRDS() 277 | new_time = time.monotonic() 278 | if (new_time - initial_time) > toggle_frequency: 279 | print_rds = not print_rds 280 | if print_rds: 281 | if rdstext == "": 282 | drawText("No rds data") 283 | else: 284 | if len(rdstext.split(" ")) > 1: 285 | drawText(rdstext) 286 | else: 287 | drawText("Unclear rds data") 288 | else: 289 | drawText(radio.formatFreq()) 290 | initial_time = new_time 291 | 292 | while not ble.connected: 293 | # Wait for a connection. 294 | # Main loop 295 | if not switch1.value: 296 | print("Seek Up pressed - button 1") 297 | radio.seekUp() 298 | time.sleep(0.01) # debounce delay 299 | 300 | if not switch2.value: 301 | print("Seek Down pressed - button 2") 302 | radio.seekDown() 303 | time.sleep(0.01) # debounce delay 304 | 305 | if not switch3.value: 306 | print("mute pressed - button 3") 307 | radio.setMute(not radio.mute) 308 | time.sleep(0.01) # debounce delay 309 | 310 | if not switch4.value: 311 | print("Preset up pressed - button 4") 312 | # Goes to the next preset station 313 | 314 | print (i_sidx) 315 | if i_sidx < (len(presets) - 1): 316 | i_sidx = i_sidx + 1 317 | radio.setFreq(presets[i_sidx]) 318 | 319 | elif i_sidx == 6: 320 | i_sidx = 0 321 | radio.setFreq(presets[i_sidx]) 322 | time.sleep(0.01) # debounce delay 323 | 324 | if not switch5.value: 325 | print("Volume Up pressed - button 5") 326 | v = radio.volume 327 | if v < 15: 328 | radio.setVolume(v + 1) 329 | time.sleep(0.08) # debounce delay 330 | 331 | if not switch6.value: 332 | print("Volume Down pressed - button 6") 333 | v = radio.volume 334 | if v > 0: 335 | radio.setVolume(v - 1) 336 | time.sleep(0.01) # debounce delay 337 | 338 | 339 | serial_read() 340 | radio.checkRDS() 341 | new_time = time.monotonic() 342 | if (new_time - initial_time) > toggle_frequency: 343 | print_rds = not print_rds 344 | if print_rds: 345 | if rdstext == "": 346 | drawText("No rds data") 347 | else: 348 | if len(rdstext.split(" ")) > 1: 349 | drawText(rdstext) 350 | else: 351 | drawText("Unclear rds data") 352 | else: 353 | drawText(radio.formatFreq()) 354 | initial_time = new_time -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/OLED_Neopixel_diagnostics.py: -------------------------------------------------------------------------------- 1 | """ 2 | This test will illuminate the onboard NEOPIXEL and cycle through colors red, green, 3 | blue followed by chasing pattern and rainbow. 4 | """ 5 | 6 | import time 7 | import board 8 | import neopixel 9 | import displayio 10 | import terminalio 11 | from adafruit_display_text import label 12 | import adafruit_displayio_ssd1306 13 | 14 | displayio.release_displays() 15 | 16 | # Set up display & add group 17 | i2c = board.I2C() 18 | display_bus = displayio.I2CDisplay(i2c, device_address=0x3C) 19 | display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32) 20 | group = displayio.Group(max_size=1) 21 | display.show(group) 22 | 23 | # Add content to group 24 | default_text = "ScoutMakes Azul" 25 | text_area = label.Label(terminalio.FONT, text=default_text, color=0xFFFFFF, x=10, y=17) 26 | group.append(text_area) 27 | 28 | pixel_pin = board.NEOPIXEL 29 | num_pixels = 1 30 | 31 | pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False) 32 | 33 | 34 | def wheel(pos): 35 | # Input a value 0 to 255 to get a color value. 36 | # The colours are a transition r - g - b - back to r. 37 | if pos < 0 or pos > 255: 38 | return (0, 0, 0) 39 | if pos < 85: 40 | return (255 - pos * 3, pos * 3, 0) 41 | if pos < 170: 42 | pos -= 85 43 | return (0, 255 - pos * 3, pos * 3) 44 | pos -= 170 45 | return (pos * 3, 0, 255 - pos * 3) 46 | 47 | 48 | def color_chase(color, wait): 49 | for i in range(num_pixels): 50 | pixels[i] = color 51 | time.sleep(wait) 52 | pixels.show() 53 | time.sleep(0.5) 54 | 55 | 56 | def rainbow_cycle(wait): 57 | for j in range(255): 58 | for i in range(num_pixels): 59 | rc_index = (i * 256 // num_pixels) + j 60 | pixels[i] = wheel(rc_index & 255) 61 | pixels.show() 62 | time.sleep(wait) 63 | 64 | 65 | RED = (255, 0, 0) 66 | YELLOW = (255, 150, 0) 67 | GREEN = (0, 255, 0) 68 | CYAN = (0, 255, 255) 69 | BLUE = (0, 0, 255) 70 | PURPLE = (180, 0, 255) 71 | 72 | while True: 73 | text_area.text = default_text 74 | text_area.x = 20 75 | time.sleep(1) 76 | text_area.text = "Make Something!" 77 | text_area.x = 20 78 | display.show(group) 79 | time.sleep(1) 80 | 81 | pixels.fill(RED) 82 | pixels.show() 83 | # Increase or decrease to change the speed of the solid color change. 84 | time.sleep(1) 85 | pixels.fill(GREEN) 86 | pixels.show() 87 | time.sleep(1) 88 | pixels.fill(BLUE) 89 | pixels.show() 90 | time.sleep(1) 91 | 92 | color_chase(RED, 0.1) # Increase the number to slow down the color chase 93 | color_chase(YELLOW, 0.1) 94 | color_chase(GREEN, 0.1) 95 | color_chase(CYAN, 0.1) 96 | color_chase(BLUE, 0.1) 97 | color_chase(PURPLE, 0.1) 98 | 99 | rainbow_cycle(0) # Increase the number to slow down the rainbow -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/Robot_Demo.py: -------------------------------------------------------------------------------- 1 | from adafruit_ble import BLERadio 2 | from adafruit_ble.advertising.standard import ProvideServicesAdvertisement 3 | from adafruit_ble.services.nordic import UARTService 4 | 5 | from adafruit_bluefruit_connect.packet import Packet 6 | from adafruit_bluefruit_connect.accelerometer_packet import AccelerometerPacket 7 | from adafruit_bluefruit_connect.magnetometer_packet import MagnetometerPacket 8 | from adafruit_bluefruit_connect.gyro_packet import GyroPacket 9 | from adafruit_bluefruit_connect.quaternion_packet import QuaternionPacket 10 | from adafruit_bluefruit_connect.button_packet import ButtonPacket 11 | 12 | import time 13 | import board 14 | import pulseio 15 | import neopixel 16 | import simpleio 17 | import busio 18 | import terminalio 19 | from digitalio import DigitalInOut, Direction, Pull 20 | 21 | from adafruit_display_text import label 22 | import adafruit_displayio_ssd1306 23 | import displayio 24 | # Display 25 | displayio.release_displays() 26 | 27 | # Initialize i2c bus 28 | i2c = busio.I2C(board.SCL, board.SDA) 29 | 30 | display_bus = displayio.I2CDisplay(i2c, device_address=0x3C) 31 | display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32) 32 | oled_text = "Robot Ready!" 33 | 34 | def drawText(text): 35 | # Write text on display 36 | global display 37 | # Make the display context 38 | splash = displayio.Group(max_size=10) 39 | display.show(splash) 40 | 41 | color_bitmap = displayio.Bitmap(128, 32, 1) 42 | color_palette = displayio.Palette(1) 43 | color_palette[0] = 0x000000 # Black 44 | 45 | bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) 46 | splash.append(bg_sprite) 47 | text_area_1 = label.Label(terminalio.FONT, text=oled_text, color=0xFFFF00, x=30, y=15) 48 | splash.append(text_area_1) 49 | 50 | pixel_pin = board.D12 #Pin that the NEOPIXELS are attached to. 51 | num_pixels = 4 52 | 53 | pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False) 54 | 55 | RED = (255, 0, 0) 56 | YELLOW = (255, 150, 0) 57 | GREEN = (0, 255, 0) 58 | CYAN = (0, 255, 255) 59 | BLUE = (0, 0, 255) 60 | PURPLE = (180, 0, 255) 61 | WHITE = (255, 255, 255) 62 | 63 | def color_chase(color, wait): 64 | for i in range(num_pixels): 65 | pixels[i] = color 66 | time.sleep(wait) 67 | pixels.show() 68 | time.sleep(0.5) 69 | 70 | # Define pin connected to piezo buzzer. 71 | PIEZO_PIN = board.D11 72 | 73 | # Define a list of tones/music notes to play on the buzzer. 74 | TONE_FREQ = [ 262, # C4 75 | 294, # D4 76 | 330, # E4 77 | 349, # F4 78 | 392, # G4 79 | 440, # A4 80 | 494 ] # B4 81 | 82 | #motor pin definitions 83 | motor1A = DigitalInOut(board.D5) 84 | motor1B = DigitalInOut(board.D6) 85 | motor2A = DigitalInOut(board.D9) 86 | motor2B = DigitalInOut(board.D10) 87 | 88 | motor1A.direction = Direction.OUTPUT 89 | motor1B.direction = Direction.OUTPUT 90 | motor2A.direction = Direction.OUTPUT 91 | motor2B.direction = Direction.OUTPUT 92 | 93 | ble = BLERadio() 94 | uart = UARTService() 95 | advertisement = ProvideServicesAdvertisement(uart) 96 | while True: 97 | drawText("") #Robot ready splash 98 | pixels.fill(BLUE) 99 | pixels.show() 100 | ble.start_advertising(advertisement) 101 | 102 | while not ble.connected: 103 | pass 104 | 105 | # Now we're connected 106 | 107 | while ble.connected: 108 | if uart.in_waiting: 109 | packet = Packet.from_stream(uart) 110 | if isinstance(packet, ButtonPacket) and packet.pressed: 111 | 112 | if packet.button == ButtonPacket.RIGHT: #RIGHT 113 | pixels.fill(BLUE) 114 | pixels.show() 115 | simpleio.tone(PIEZO_PIN, TONE_FREQ[5], duration=0.05) 116 | simpleio.tone(PIEZO_PIN, TONE_FREQ[4], duration=0.1) 117 | simpleio.tone(PIEZO_PIN, TONE_FREQ[0], duration=0.05) 118 | motor1A.value = False 119 | motor1B.value = True 120 | motor2A.value = False 121 | motor2B.value = True 122 | 123 | elif packet.button == ButtonPacket.LEFT: # LEFT 124 | pixels.fill(YELLOW) 125 | pixels.show() 126 | simpleio.tone(PIEZO_PIN, TONE_FREQ[6], duration=0.05) 127 | simpleio.tone(PIEZO_PIN, TONE_FREQ[5], duration=0.1) 128 | simpleio.tone(PIEZO_PIN, TONE_FREQ[0], duration=0.05) 129 | motor1A.value = True 130 | motor1B.value = False 131 | motor2A.value = True 132 | motor2B.value = False 133 | 134 | elif packet.button == ButtonPacket.UP: # FORWARD 135 | pixels.fill(GREEN) 136 | pixels.show() 137 | simpleio.tone(PIEZO_PIN, TONE_FREQ[2], duration=0.1) 138 | motor1A.value = False 139 | motor1B.value = True 140 | motor2A.value = True 141 | motor2B.value = False 142 | 143 | elif packet.button == ButtonPacket.DOWN: # REVERSE 144 | pixels.fill(RED) 145 | pixels.show() 146 | simpleio.tone(PIEZO_PIN, TONE_FREQ[3], duration=0.1) 147 | motor1A.value = True 148 | motor1B.value = False 149 | motor2A.value = False 150 | motor2B.value = True 151 | 152 | elif packet.button == ButtonPacket.BUTTON_1: # button 1 153 | pixels.fill(YELLOW) 154 | pixels.show() 155 | simpleio.tone(PIEZO_PIN, TONE_FREQ[6], duration=0.2) 156 | simpleio.tone(PIEZO_PIN, TONE_FREQ[3], duration=0.1) 157 | simpleio.tone(PIEZO_PIN, TONE_FREQ[0], duration=0.4) 158 | print("released button 1") 159 | 160 | elif packet.button == ButtonPacket.BUTTON_2: # button 2 161 | pixels.fill(RED) 162 | pixels.show() 163 | simpleio.tone(PIEZO_PIN, TONE_FREQ[0], duration=0.2) 164 | simpleio.tone(PIEZO_PIN, TONE_FREQ[3], duration=0.1) 165 | simpleio.tone(PIEZO_PIN, TONE_FREQ[6], duration=0.4) 166 | print("released button 2") 167 | 168 | elif packet.button == ButtonPacket.BUTTON_3: # button 3 169 | pixels.fill(BLUE) 170 | pixels.show() 171 | print("released button 3") 172 | 173 | elif packet.button == ButtonPacket.BUTTON_4: # button 4 174 | pixels.fill(CYAN) 175 | pixels.show() 176 | print("released button 4") 177 | else: 178 | pixels.fill(WHITE) 179 | pixels.show() 180 | print("stopped") 181 | drawText("") #Robot ready splash 182 | motor1A.value = False 183 | motor1B.value = False 184 | motor2A.value = False 185 | motor2B.value = False 186 | 187 | elif isinstance(packet, ButtonPacket) and not packet.pressed: 188 | if packet.button == ButtonPacket.RIGHT: 189 | print("released right") 190 | motor1A.value = False 191 | motor1B.value = False 192 | motor2A.value = False 193 | motor2B.value = False 194 | if packet.button == ButtonPacket.LEFT: 195 | print("released left") 196 | motor1A.value = False 197 | motor1B.value = False 198 | motor2A.value = False 199 | motor2B.value = False 200 | if packet.button == ButtonPacket.UP: 201 | print("released forward") 202 | motor1A.value = False 203 | motor1B.value = False 204 | motor2A.value = False 205 | motor2B.value = False 206 | if packet.button == ButtonPacket.DOWN: 207 | print("released reverse") 208 | motor1A.value = False 209 | motor1B.value = False 210 | motor2A.value = False 211 | motor2B.value = False -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/code.py: -------------------------------------------------------------------------------- 1 | from adafruit_ble import BLERadio 2 | from adafruit_ble.advertising.standard import ProvideServicesAdvertisement 3 | from adafruit_ble.services.nordic import UARTService 4 | 5 | from adafruit_bluefruit_connect.packet import Packet 6 | from adafruit_bluefruit_connect.accelerometer_packet import AccelerometerPacket 7 | from adafruit_bluefruit_connect.magnetometer_packet import MagnetometerPacket 8 | from adafruit_bluefruit_connect.gyro_packet import GyroPacket 9 | from adafruit_bluefruit_connect.quaternion_packet import QuaternionPacket 10 | from adafruit_bluefruit_connect.button_packet import ButtonPacket 11 | 12 | import time 13 | import board 14 | import pulseio 15 | import neopixel 16 | import simpleio 17 | import busio 18 | import terminalio 19 | from digitalio import DigitalInOut, Direction, Pull 20 | 21 | from adafruit_display_text import label 22 | import adafruit_displayio_ssd1306 23 | import displayio 24 | # Display 25 | displayio.release_displays() 26 | 27 | # Initialize i2c bus 28 | i2c = busio.I2C(board.SCL, board.SDA) 29 | 30 | display_bus = displayio.I2CDisplay(i2c, device_address=0x3C) 31 | display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32) 32 | oled_text = "Robot Ready!" 33 | 34 | def drawText(text): 35 | # Write text on display 36 | global display 37 | # Make the display context 38 | splash = displayio.Group(max_size=10) 39 | display.show(splash) 40 | 41 | color_bitmap = displayio.Bitmap(128, 32, 1) 42 | color_palette = displayio.Palette(1) 43 | color_palette[0] = 0x000000 # Black 44 | 45 | bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0) 46 | splash.append(bg_sprite) 47 | text_area_1 = label.Label(terminalio.FONT, text=oled_text, color=0xFFFF00, x=30, y=15) 48 | splash.append(text_area_1) 49 | 50 | pixel_pin = board.D12 #Pin that the NEOPIXELS are attached to. 51 | num_pixels = 4 52 | 53 | pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False) 54 | 55 | RED = (255, 0, 0) 56 | YELLOW = (255, 150, 0) 57 | GREEN = (0, 255, 0) 58 | CYAN = (0, 255, 255) 59 | BLUE = (0, 0, 255) 60 | PURPLE = (180, 0, 255) 61 | WHITE = (255, 255, 255) 62 | 63 | def color_chase(color, wait): 64 | for i in range(num_pixels): 65 | pixels[i] = color 66 | time.sleep(wait) 67 | pixels.show() 68 | time.sleep(0.5) 69 | 70 | # Define pin connected to piezo buzzer. 71 | PIEZO_PIN = board.D11 72 | 73 | # Define a list of tones/music notes to play on the buzzer. 74 | TONE_FREQ = [ 262, # C4 75 | 294, # D4 76 | 330, # E4 77 | 349, # F4 78 | 392, # G4 79 | 440, # A4 80 | 494 ] # B4 81 | 82 | #motor pin definitions 83 | motor1A = DigitalInOut(board.D5) 84 | motor1B = DigitalInOut(board.D6) 85 | motor2A = DigitalInOut(board.D9) 86 | motor2B = DigitalInOut(board.D10) 87 | 88 | motor1A.direction = Direction.OUTPUT 89 | motor1B.direction = Direction.OUTPUT 90 | motor2A.direction = Direction.OUTPUT 91 | motor2B.direction = Direction.OUTPUT 92 | 93 | ble = BLERadio() 94 | uart = UARTService() 95 | advertisement = ProvideServicesAdvertisement(uart) 96 | while True: 97 | drawText("") #Robot ready splash 98 | pixels.fill(BLUE) 99 | pixels.show() 100 | ble.start_advertising(advertisement) 101 | 102 | while not ble.connected: 103 | pass 104 | 105 | # Now we're connected 106 | 107 | while ble.connected: 108 | if uart.in_waiting: 109 | packet = Packet.from_stream(uart) 110 | if isinstance(packet, ButtonPacket) and packet.pressed: 111 | 112 | if packet.button == ButtonPacket.RIGHT: #RIGHT 113 | pixels.fill(BLUE) 114 | pixels.show() 115 | simpleio.tone(PIEZO_PIN, TONE_FREQ[5], duration=0.05) 116 | simpleio.tone(PIEZO_PIN, TONE_FREQ[4], duration=0.1) 117 | simpleio.tone(PIEZO_PIN, TONE_FREQ[0], duration=0.05) 118 | motor1A.value = False 119 | motor1B.value = True 120 | motor2A.value = False 121 | motor2B.value = True 122 | 123 | elif packet.button == ButtonPacket.LEFT: # LEFT 124 | pixels.fill(YELLOW) 125 | pixels.show() 126 | simpleio.tone(PIEZO_PIN, TONE_FREQ[6], duration=0.05) 127 | simpleio.tone(PIEZO_PIN, TONE_FREQ[5], duration=0.1) 128 | simpleio.tone(PIEZO_PIN, TONE_FREQ[0], duration=0.05) 129 | motor1A.value = True 130 | motor1B.value = False 131 | motor2A.value = True 132 | motor2B.value = False 133 | 134 | elif packet.button == ButtonPacket.UP: # FORWARD 135 | pixels.fill(GREEN) 136 | pixels.show() 137 | simpleio.tone(PIEZO_PIN, TONE_FREQ[2], duration=0.1) 138 | motor1A.value = False 139 | motor1B.value = True 140 | motor2A.value = True 141 | motor2B.value = False 142 | 143 | elif packet.button == ButtonPacket.DOWN: # REVERSE 144 | pixels.fill(RED) 145 | pixels.show() 146 | simpleio.tone(PIEZO_PIN, TONE_FREQ[3], duration=0.1) 147 | motor1A.value = True 148 | motor1B.value = False 149 | motor2A.value = False 150 | motor2B.value = True 151 | 152 | elif packet.button == ButtonPacket.BUTTON_1: # button 1 153 | pixels.fill(YELLOW) 154 | pixels.show() 155 | simpleio.tone(PIEZO_PIN, TONE_FREQ[6], duration=0.2) 156 | simpleio.tone(PIEZO_PIN, TONE_FREQ[3], duration=0.1) 157 | simpleio.tone(PIEZO_PIN, TONE_FREQ[0], duration=0.4) 158 | print("released button 1") 159 | 160 | elif packet.button == ButtonPacket.BUTTON_2: # button 2 161 | pixels.fill(RED) 162 | pixels.show() 163 | simpleio.tone(PIEZO_PIN, TONE_FREQ[0], duration=0.2) 164 | simpleio.tone(PIEZO_PIN, TONE_FREQ[3], duration=0.1) 165 | simpleio.tone(PIEZO_PIN, TONE_FREQ[6], duration=0.4) 166 | print("released button 2") 167 | 168 | elif packet.button == ButtonPacket.BUTTON_3: # button 3 169 | pixels.fill(BLUE) 170 | pixels.show() 171 | print("released button 3") 172 | 173 | elif packet.button == ButtonPacket.BUTTON_4: # button 4 174 | pixels.fill(CYAN) 175 | pixels.show() 176 | print("released button 4") 177 | else: 178 | pixels.fill(WHITE) 179 | pixels.show() 180 | print("stopped") 181 | drawText("") #Robot ready splash 182 | motor1A.value = False 183 | motor1B.value = False 184 | motor2A.value = False 185 | motor2B.value = False 186 | 187 | elif isinstance(packet, ButtonPacket) and not packet.pressed: 188 | if packet.button == ButtonPacket.RIGHT: 189 | print("released right") 190 | motor1A.value = False 191 | motor1B.value = False 192 | motor2A.value = False 193 | motor2B.value = False 194 | if packet.button == ButtonPacket.LEFT: 195 | print("released left") 196 | motor1A.value = False 197 | motor1B.value = False 198 | motor2A.value = False 199 | motor2B.value = False 200 | if packet.button == ButtonPacket.UP: 201 | print("released forward") 202 | motor1A.value = False 203 | motor1B.value = False 204 | motor2A.value = False 205 | motor2B.value = False 206 | if packet.button == ButtonPacket.DOWN: 207 | print("released reverse") 208 | motor1A.value = False 209 | motor1B.value = False 210 | motor2A.value = False 211 | motor2B.value = False -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/__init__.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/__init__.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/adafruit.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/adafruit.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/apple.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/apple.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/standard.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/advertising/standard.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/attributes/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/attributes/__init__.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/__init__.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/float.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/float.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/int.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/int.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/stream.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/stream.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/string.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/characteristics/string.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/services/circuitpython.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/services/circuitpython.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/uuid/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble/uuid/__init__.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble_radio.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_ble_radio.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/__init__.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/__init__.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/_xyz_packet.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/_xyz_packet.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/accelerometer_packet.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/accelerometer_packet.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/button_packet.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/button_packet.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/color_packet.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/color_packet.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/gyro_packet.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/gyro_packet.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/location_packet.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/location_packet.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/magnetometer_packet.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/magnetometer_packet.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/packet.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/packet.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/quaternion_packet.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bluefruit_connect/quaternion_packet.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bus_device/i2c_device.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bus_device/i2c_device.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bus_device/spi_device.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_bus_device/spi_device.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_displayio_ssd1306.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/adafruit_displayio_ssd1306.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/neopixel.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/neopixel.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/simpleio.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/simpleio.mpy -------------------------------------------------------------------------------- /ScoutMakes Robot Kit/examples/lib/adafruit_ble/tinkeringtech_rda5807m.mpy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/ScoutMakes Robot Kit/examples/lib/adafruit_ble/tinkeringtech_rda5807m.mpy -------------------------------------------------------------------------------- /assets/FM_Robot_kit_combo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/assets/FM_Robot_kit_combo.png -------------------------------------------------------------------------------- /assets/license.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tinkeringtech/scoutmakes/c7e1adddae30ca2989365b596d3d46a1a6f7c952/assets/license.JPG --------------------------------------------------------------------------------