tinkeringtech / CircuitPython_rda5807

MIT License
3 stars 3 forks source link
circuitpython

Introduction

.. image:: https://readthedocs.org/projects/tinkeringtech-circuitpython-rda5807m/badge/?version=latest :target: https://circuitpython-rda5807m.readthedocs.io/ :alt: Documentation Status

.. image:: https://img.shields.io/discord/327254708534116352.svg :target: https://adafru.it/discord :alt: Discord

.. image:: https://github.com/tinkeringtech/Tinkeringtech_CircuitPython_rda5807m/workflows/Build%20CI/badge.svg :target: https://github.com/tinkeringtech/Tinkeringtech_CircuitPython_rda5807m/actions :alt: Build Status

.. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/psf/black :alt: Code Style: Black

rda5807m FM radio chip CircuitPython library

Dependencies

This driver depends on:

Please ensure all dependencies are available on the CircuitPython filesystem. This is easily achieved by downloading the Adafruit library and driver bundle <https://circuitpython.org/libraries> or individual libraries can be installed using circup <https://github.com/adafruit/circup>.

Installing to a Connected CircuitPython Device with Circup

Make sure that you have circup installed in your Python environment. Install it with the following command if necessary:

.. code-block:: shell

pip3 install circup

With circup installed and your CircuitPython device connected use the following command to install:

.. code-block:: shell

circup install rda5807m

Or the following command to update an existing version:

.. code-block:: shell

circup update

Usage Example

.. code-block:: shell

import time
import board
import busio
import supervisor
import displayio
import terminalio
from adafruit_bus_device.i2c_device import I2CDevice
from adafruit_display_text import label
import adafruit_displayio_ssd1306
import tinkeringtech_rda5807m
from digitalio import DigitalInOut, Direction, Pull

# Display
displayio.release_displays()
oled_reset = board.D9

presets = [  # Preset stations
    8930,
    9510,
    9710,
    9950,
    10100,
    10110,
    10650
]
i_sidx = 3  # Starting at station with index 3

# Initialize i2c bus
i2c = busio.I2C(board.SCL1, board.SDA1)

# Receiver i2c communication
address = 0x11
radio_i2c = I2CDevice(i2c, address)

vol = 0  # Default volume
band = "FM"

radio = tinkeringtech_rda5807m.Radio(radio_i2c, presets[i_sidx], vol)
radio.setBand(band)  # Minimum frequency - 87 Mhz, max - 108 Mhz
rds = tinkeringtech_rda5807m.RDSParser()

# Display initialization
initial_time = time.monotonic()  # Initial time - used for timing
toggle_frequency = 5  # Frequency at which the text changes between radio frequnecy and rds in seconds
display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32)
rdstext = "No rds data"

def drawText(text):
    # Write text on display
    global display
    # Make the display context
    splash = displayio.Group()
    display.show(splash)

    color_bitmap = displayio.Bitmap(128, 32, 1)
    color_palette = displayio.Palette(1)
    color_palette[0] = 0x000000  # Black

    bg_sprite = displayio.TileGrid(color_bitmap, pixel_shader=color_palette, x=0, y=0)
    splash.append(bg_sprite)

    # Split text into two lines
    temp = text.split(" ")
    line1 = temp[0]
    line2 = " ".join(temp[1:])
    # Check that lines are not empty
    if not line1.strip() or not line2.strip():
        warning = "Unclear rds data"
        text_area_1 = label.Label(terminalio.FONT, text=warning, color=0xFFFF00, x=5, y=5)
        splash.append(text_area_1)
    else:
        # Line 1
        text_area_1 = label.Label(terminalio.FONT, text=line1, color=0xFFFF00, x=5, y=5)
        splash.append(text_area_1)
        # Line 2
        text_area_2 = label.Label(terminalio.FONT, text=line2, color=0xFFFF00, x=5, y=20)
        splash.append(text_area_2)

# RDS text handle
def textHandle(rdsText):
    global rdstext
    rdstext = rdsText
    print(rdsText)
rds.attachTextCallback(textHandle)

# Read input from serial
def serial_read():
    if supervisor.runtime.serial_bytes_available:
        command = input()
        command = command.split(" ")
        cmd = command[0]
        if cmd == "f":
            value = command[1]
            runSerialCommand(cmd, int(value))
        else:
            runSerialCommand(cmd)
        time.sleep(0.3)
        print("-> ", end="")

def runSerialCommand(cmd, value=0):
    # Executes a command
    # Starts with a character, and optionally followed by an integer, if required
    global i_sidx
    global presets
    if cmd == "?":
        print("? help")
        print("+ increase volume")
        print("- decrease volume")
        print("> next preset")
        print("< previous preset")
        print(". scan up ")
        print(", scan down ")
        print("f direct frequency input")
        print("i station status")
        print("s mono/stereo mode")
        print("b bass boost")
        print("u mute/unmute")
        print("r get rssi data")
        print("e softreset chip")
        print("q stops the program")

    # Volume and audio control
    elif cmd == "+":
        v = radio.volume
        if v < 15:
            radio.setVolume(v + 1)
    elif cmd == "-":
        v = radio.volume
        if v > 0:
            radio.setVolume(v - 1)

    # Toggle mute mode
    elif cmd == "u":
        radio.setMute(not radio.mute)
    # Toggle stereo mode
    elif cmd == "s":
        radio.setMono(not radio.mono)
    # Toggle bass boost
    elif cmd == "b":
        radio.setBassBoost(not radio.bassBoost)

    # Frequency control
    elif cmd == ">":
        # Goes to the next preset station
        if i_sidx < (len(presets) - 1):
            i_sidx = i_sidx + 1
            radio.setFreq(presets[i_sidx])
    elif cmd == "<":
        # Goes to the previous preset station
        if i_sidx > 0:
            i_sidx = i_sidx - 1
            radio.setFreq(presets[i_sidx])

    # Set frequency
    elif cmd == "f":
        radio.setFreq(value)

    # Seek up/down
    elif cmd == ".":
        radio.seekUp()
    elif cmd == ",":
        radio.seekDown()

    # Display current signal strength
    elif cmd == "r":
        print("RSSI: " + str(radio.getRssi()))

    # Soft reset chip
    elif cmd == "e":
        radio.softReset()

    # Not in help
    elif cmd == "!":
        radio.term()

    elif cmd == "i":
        # Display chip info
        s = radio.formatFreq()
        print("Station: " + s)
        print("Radio info: ")
        print("RDS -> " + str(radio.rds))
        print("TUNED -> " + str(radio.tuned))
        print("STEREO -> " + str(not radio.mono))
        print("Audio info: ")
        print("BASS -> " + str(radio.bassBoost))
        print("MUTE -> " + str(radio.mute))
        print("SOFTMUTE -> " + str(radio.softMute))
        print("VOLUME -> " + str(radio.volume))

print_rds = False
radio.sendRDS = rds.processData
runSerialCommand("?", 0)

print("-> ", end="")

while True:
        serial_read()
        radio.checkRDS()
        new_time = time.monotonic()
        if (new_time - initial_time) > toggle_frequency:
            print_rds = not print_rds
            if print_rds:
                if rdstext == "":
                    drawText("No rds data")
                else:
                    if len(rdstext.split(" ")) > 1:
                        drawText(rdstext)
                    else:
                        drawText("Unclear rds data")
            else:
                drawText(radio.formatFreq())
            initial_time = new_time

Documentation

API documentation for this library can be found on Read the Docs <https://circuitpython-rda5807m.readthedocs.io/>_.

For information on building library documentation, please check out this guide <https://learn.adafruit.com/creating-and-sharing-a-circuitpython-library/sharing-our-docs-on-readthedocs#sphinx-5-1>_.

Contributing

Contributions are welcome! Please read our Code of Conduct <https://github.com/tinkeringtech/Tinkeringtech_CircuitPython_rda5807m/blob/HEAD/CODE_OF_CONDUCT.md>_ before contributing to help this project stay welcoming.