# T-DeckARD: T-Deck Augmented Runtime Distribution ## About T-DeckARD is a curated, interconnected and integrated collection of Python 3 modules developed for CircuitPython 10.x on LilyGO T-Deck (but also mostly compatible with MicroPython and desktop CPython) aimed at turning the stock (Circuit)Python REPL into an easy to use operating environment. T-DeckARD modules are divided into two categories: **components**, which are the building blocks anyone can use to easily create their own applications, and ready-made **applets** which can already be used as stand-alone applications, as well as included as components of other, more complicated ones. This repo also hosts the **games** section which is just a special kind of applets that implement various computer games. ## Prerequisites for T-Deck (Plus) On T-Deck (Plus), the following components must be installed: - CircuitPython 10.x (tested on 10.0.3); - Adafruit Library Bundles from the [official CircuitPython page](https://circuitpython.org/libraries). If you have `circup` installed, you can connect the device via USB and then run `circup install -r requirements.txt` from the project root. The [tdeck_repl](https://github.com/RetiredWizard/tdeck_repl) distribution is already incorporated into the repo. On other generic platforms, most modules which are not T-Deck-specific are set to work on both CPython and MicroPython. ## Installation on T-Deck (Plus) Current installation process doesn't involve any `.mpy` module compilation, so, after installing the prerequisites, you just need to copy the `repl`, `deck`, `app` and `game` directories, as well as the `code.py` and `tdeckboot.py` files, into the root of the `CIRCUITPY` removable volume. ## Components (`deck.*`) As of now, T-DeckARD implements the following component modules. ### `deck.runtime` A library for establishing runtime compatibility across various Python environments. Exported functions: - `runcode(code_string)`: compile and execute a Python program expressed as a string. Used by REPL and some applets. ### `deck.input` A library for single-line and multi-line (ed-like) text input. Exported functions: - `input(prompt=None)`: standard single-line Python input - `input_multi(prompt=None, terminator='.')`: multi-line input, end with the terminator string on a separate line ### `deck.pager` A library for paged text output. In CPython, relies on the terminal dimensions provided by the host OS. In CircuitPython and MicroPython, it requires correct values to be provided inside `TERM_COLS` and `TERM_ROWS` environment variables. In case they are not provided, these values default to 53 columns and 19 rows (the actual value for T-Deck running `tdeck_repl` in CircuitPython). Exported functions: - `term_size()`: return the terminal dimensions tuple in the `(rows, columns)` format - `reflow(text)`: split text into a list of lines not exceeding terminal width - `print_paged(text)`: reflow and print the text in a paginated manner, prompting for Enter presses to move to the next page ### `deck.menu` A library for easy menu systems for T-DeckARD programs. Exported functions: - `confirm(msg, yes='y', no='n', alt_prompt=None)`: prompt for yes/no confirmation, using a standard prompt in `msg` and the `yes`/`no` message in the corresponding parameters, or a completely alternative prompt in `alt_prompt`.Returns True or False as the result. - `shortmenu(choices, suffix=': ')`: display several menu items from the `choices` list, automatically labeling the first fitting letter from the item as the selection shortcut. Returns a tuple (`result`, `label`), or (``,``) in case the selection doesn't match. - `menu(choices)`: display up to 10 menu items with the ability to select them with a single digit or a key on the `QWERTYUIOP` keyboard row. Accepts a list of **tuples**, each in the format `(id, label)`. The `label` field is what's displayed on the screen, the `id` field is the string that gets returned upon selection. If the user selects `c`, the operation is canceled and an empty `id` string is returned. ### `deck.time` A wrapper for standard Python `date`, `time` and `datetime` modules. Just run `from deck.time import *` to activate. ### `deck.chat` A generic chat UI helper library. Exports a single class called `DeckChat` with the following parameters: ```python chat_instance = DeckChat(start_state={}, chat_prefix='> ', command_prefix='/') ``` where the constructor parameters are: - `start_state`: the state object to be modified by chat actions - `chat_prefix`: the prefix to be displayed before each user's message input - `command_prefix`: the prefix to be prepended to every registered chat command Every chat instance exposes the following methods: - `command(command_name, handler)`: register a command under the `command_name` according to the handler specification (see below); e.g. if the prefix is `/` and the command name is `list`, the chat will react to the `/list` command and pass everything after it as the argument to the handler function - `start()`: start the chat loop (keyboard interrupts, if any are supported, exit the loop) The handler accepts two parameters: a message and a state object, and returns the response and the new state object. If the returned state object is `None`, then the chat loop exits. Non-command handler (i.e. what should be done on any user input that doesn't start with a registered command) is registered under the `default` command. ### `deck.xlat` Character translation helper library. For now, only supports base Cyrillic character set. Exports the following functions: - `enc(s, mapname='CYR')`: encode from the selected character set into Latin - `dec(s, mapname='CYR')`: decode from Latin into the selected character set ### `deck.fs` FS helper librаry. Exports the following functions: - `unlock_rootfs()`: make the device root filesystem read-write (does nothing on desktop) - `lock_rootfs()`: make the device root filesystem read-only (does nothing on desktop) - `stat(path)` (aka `du(path)`): alias to `os.stat` but returning the stats as a dictionary - `statvfs(path)` (aka `df(path)`): alias to `os.statvfs` but returning the stats as a dictionary - `mount_sd(path='/sd', readonly=False)`: mount the inserted microSD card (T-Deck only, must be FAT32) - `umount_sd(path='/sd')`: unmount the inserted microSD card (T-Deck only) The following `deck.fs` functions are direct aliases to the corresponding `os` call counterparts: - `sep` = `pathsep` = `os.sep` - `cwd` = `pwd` = `os.getcwd` - `ls` = `listdir` = `os.listdir` - `md` = `mkdir` = `os.mkdir` - `cd` = `chdir` = `os.chdir` - `rd` = `rmdir` = `os.rmdir` - `rm` = `remove` = `os.remove` - `mv` = `rename` = `move` = `os.rename` - `sync` = `os.sync` (where supported) - `env` = `getenv` = `os.getenv` - `rnd` = `urandom` = `os.urandom` ### `deck.hwinfo` Various hardware information. May be expanded in the future. Exports the following functions: - `board_id()`: get the board ID (e.g. `lilygo_tdeck` for T-Deck/T-Deck Plus), or `emulated` if it's not run on a CircuitPython device - `battery_v()`: (T-Deck-specific) get the current battery voltage (or 0 if running in an emulated environment) - `cpu_f()`: CPU frequency in Hertz Also, this module exposes the `REAL_HW` variable to detect whether the code is running on a real hardware in the CircuitPython environment. ### `deck.net` T-Deck/CircuitPython-specific library for Wi-Fi connection and returning `requests` and `socket` library instances. Exported functions: - `wifi_scan()`: scan available Wi-Fi networks and return the list of `(ssid, rssi)` tuples (sorted from the strongest signal to the weakest) - `wifi_connect(ssid=None, password=None)`: connect to a Wi-Fi SSID without waiting (default credentials are pulled from the `/settings.toml` file) - `wifi_connect_wait(ssid=None, password=None, tmout=15, retries=3)`: connect to a Wi-Fi SSID (with the same parameters as `wifi_connect`) and wait until the connection is established - `my_ip()`: return the current local IPv4 (as a string) - `ssl_context()`: get the default SSL context for wrapping in a raw socket - `init_socket()`: return the active reference to the `socket` library - `init_requests()`: return the active reference to the `requests` library - `init_ntp(tz=0)`: return an NTP time client instance (use the `.datetime` property of the instance to access current time and the `tz` parameter to specify the timezone offset) A normal flow for instantiating a Requests library looks like this: ```python # init requests library in a platform-agnostic way requests = None try: from deck import net print('Waiting for online status...') status, stext, myip = net.wifi_connect_wait() if status: print("We're online, initing requests lib...") requests = net.init_requests() except: import requests ``` ### `deck.http` High-level HTTP client library. Exports the following functions: - `http_set_ua(ua_str='Mozilla/5.0')`: set a default HTTP user agent string - `http_fetch(url, useragent=None, hdrs={})`: fetch text content from a URL into a string (returns `(status_code, content)` tuple) - `auth_header(username, password)`: get a dictionary fragment with the corresponding HTTP Basic Auth header according to the username and password - `url_escape(s)`: escape a string to be used as a part of URL parameters - `form_encode(params)`: encode a form body dictionary in the `x-www-form-urlencoded` format - `wget(url, filename='', useragent=None, hdrs={})`: download a file into a local path (returns `(status_code, filename)` tuple) - `wput(url, file_path, field_name="file", method="POST", format="x-www-form-urlencoded", headers={}, useragent=None)`: upload a file from a local path in the `x-www-form-urlencoded` or JSON format (returns `(status_code, content)` tuple) ### `deck.otp` A library that provides HOTP and TOTP one-time password implementations. Exports the following functions: - `hotp(key, counter, digits=6)`: generate a `digits`-long HOTP code from (bytes-only) key and counter value - `totp(key, time_step, digits=6)`: generate a `digits`-long TOTP code from (bytes-only) key, using `time_step` as the basis (30 seconds is default and the most common) - `get_epoch()`: a helper platform-agnostic function to get the current Unix timestamp in seconds ### `deck.text` A library that implements a [DeckText](decktext-spec.md) format parser. Exports a single class, `DeckText`, with the following methods: - `doc = DeckText(src=None)` constructor: initialize a DeckText document object from the passed source - `doc.load(src)`: load DeckText source into the existing document object. After the source is loaded, the document object exposes two properties: `title` and `pages`. The `title` property is a normal string that represents the document's title (read from the `