Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ The player plays the MP3 files of `music/` on the card. Copy them there on a
PC, or send them over the console:

```bash
scripts/ymodem_send.py --dest /mnt/dmsdio0_0p1/music *.mp3
scripts/ymodem_send.py --dest music *.mp3
```

carhmi reads the directory when it starts: restart it (`service restart carhmi`)
Expand Down Expand Up @@ -317,6 +317,12 @@ the SD card) to the device over its UART console, with YMODEM: dmell's
no pyserial needed) types it and sends the files - their paths kept under
the destination directory.

The files go to the SD card: the script asks the device what is mounted in
`/mnt` - automount mounts a card at `/mnt/<label>`, or `/mnt/<node name>`
without one (`/mnt/dmsdio0_0p1`) - and sends them there when there is one
card. With several, `DMBOOT_UPLOAD_CARD` names it; an absolute
`DMBOOT_UPLOAD_DEST` is used as it is.

- `upload-files` - to a device that is running
- `install-all` - `install-firmware`, then the files once the device has started

Expand All @@ -328,13 +334,16 @@ cmake --build . --target upload-files
|----------|---------|-------------|
| `DMBOOT_UPLOAD_PORT` | `/dev/ttyACM0` | The device's console |
| `DMBOOT_UPLOAD_BAUD` | `921600` | Its baud rate |
| `DMBOOT_UPLOAD_DEST` | `/mnt/dmsdio0_0p1` | Directory on the device |
| `DMBOOT_UPLOAD_DEST` | empty | Directory on the card (relative, empty: its root), or an absolute one |
| `DMBOOT_UPLOAD_CARD` | `auto` | The card: its name in `/mnt`, `auto` (the one there is), `none` (the shell's directory) |
| `DMBOOT_UPLOAD_SOURCES` | `build/sdcard` | Files and directories (`SRC=NAME` sends SRC as NAME) |
| `DMBOOT_UPLOAD_BLOCK` | `1024` | YMODEM block size (128 or 1024) |
| `DMBOOT_UPLOAD_WAIT` | `60` | `install-all`: seconds the device may take to start |

The script works on its own too:

```bash
scripts/ymodem_send.py --dest /mnt/dmsdio0_0p1/views view.dmv fonts/
scripts/ymodem_send.py --dest views view.dmv fonts/ # views/ on the card
scripts/ymodem_send.py --card bootfs --dest views view.dmv # of the card in /mnt/bootfs
scripts/ymodem_send.py --dest /mnt/sd/views view.dmv # an absolute directory
```
24 changes: 19 additions & 5 deletions scripts/targets.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -161,27 +161,41 @@ add_custom_target(debug
# `ymodem` command receives them (scripts/ymodem_send.py types it).
# upload-files the files, to the device running (its console on DMBOOT_UPLOAD_PORT)
# install-all the firmware, then the files (waiting for the device to start)
# They go to the SD card the script finds on the device (in /mnt, where
# automount mounts it by its label or node name) - or to an absolute
# DMBOOT_UPLOAD_DEST.
set(DMBOOT_UPLOAD_PORT "/dev/ttyACM0" CACHE STRING "Serial port of the device's dmell console the files are sent over (upload-files)")
set(DMBOOT_UPLOAD_BAUD "921600" CACHE STRING "Baud rate of DMBOOT_UPLOAD_PORT")
set(DMBOOT_UPLOAD_DEST "/mnt/dmsdio0_0p1" CACHE STRING "Directory on the device the uploaded files go to (their paths under it)")
set(DMBOOT_UPLOAD_DEST "" CACHE STRING "Directory the uploaded files go to (their paths under it): on the SD card (relative; empty: its root), or absolute")
set(DMBOOT_UPLOAD_CARD "auto" CACHE STRING "The card a relative DMBOOT_UPLOAD_DEST is on: its name in /mnt, auto (the one the device has), none (the shell's directory)")
set(DMBOOT_UPLOAD_SOURCES "${CMAKE_BINARY_DIR}/sdcard" CACHE STRING "Files and directories uploaded (semicolon-separated; SRC=NAME puts SRC as NAME); default: build/sdcard")
set(DMBOOT_UPLOAD_BLOCK "1024" CACHE STRING "YMODEM block size, 128 or 1024")
set(DMBOOT_UPLOAD_WAIT "60" CACHE STRING "install-all: seconds the device may take to start before it receives the files")

find_package(Python3 COMPONENTS Interpreter QUIET)
if(Python3_Interpreter_FOUND)
set(DMBOOT_UPLOAD_COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/scripts/ymodem_send.py
--port ${DMBOOT_UPLOAD_PORT} --baud ${DMBOOT_UPLOAD_BAUD} --dest ${DMBOOT_UPLOAD_DEST} --block ${DMBOOT_UPLOAD_BLOCK})
--port ${DMBOOT_UPLOAD_PORT} --baud ${DMBOOT_UPLOAD_BAUD} --card ${DMBOOT_UPLOAD_CARD} --block ${DMBOOT_UPLOAD_BLOCK})
if(NOT "${DMBOOT_UPLOAD_DEST}" STREQUAL "")
list(APPEND DMBOOT_UPLOAD_COMMAND --dest ${DMBOOT_UPLOAD_DEST})
endif()
if("${DMBOOT_UPLOAD_DEST}" MATCHES "^/")
set(DMBOOT_UPLOAD_WHERE "${DMBOOT_UPLOAD_DEST}")
else()
set(DMBOOT_UPLOAD_WHERE "the SD card (${DMBOOT_UPLOAD_CARD})/${DMBOOT_UPLOAD_DEST}")
endif()
# (build/sdcard - the sdcard modules - is made by download_sdcard_modules: first)
add_custom_target(upload-files
COMMAND ${DMBOOT_UPLOAD_COMMAND} ${DMBOOT_UPLOAD_SOURCES}
DEPENDS download_sdcard_modules
USES_TERMINAL
COMMENT "Uploading files to ${DMBOOT_UPLOAD_DEST} over ${DMBOOT_UPLOAD_PORT} (YMODEM)..."
COMMENT "Uploading files to ${DMBOOT_UPLOAD_WHERE} over ${DMBOOT_UPLOAD_PORT} (YMODEM)..."
)
add_custom_target(install-all
COMMAND ${DMBOOT_UPLOAD_COMMAND} --wait ${DMBOOT_UPLOAD_WAIT} ${DMBOOT_UPLOAD_SOURCES}
DEPENDS install-firmware
DEPENDS install-firmware download_sdcard_modules
USES_TERMINAL
COMMENT "Uploading files to ${DMBOOT_UPLOAD_DEST} once ${TARGET} has started..."
COMMENT "Uploading files to ${DMBOOT_UPLOAD_WHERE} once ${TARGET} has started..."
)
else()
message(STATUS "Python 3 not found - the upload-files and install-all targets are not available")
Expand Down
67 changes: 62 additions & 5 deletions scripts/ymodem_send.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@
types `ymodem recv -d DEST` into the console, waits for the receiver's
'C' and sends every file - its name (with directories) under DEST:

ymodem_send.py --port /dev/ttyACM0 --dest /mnt/dmsdio0_0p1 build/sdcard
ymodem_send.py --dest /mnt/dmsdio0_0p1/views view.dmv fonts/
ymodem_send.py --dest /mnt/sd local/dir=remote/dir
ymodem_send.py build/sdcard (the card's root)
ymodem_send.py --dest views view.dmv fonts/ (views/ on the card)
ymodem_send.py --dest /mnt/sd local/dir=remote/dir (that directory)

A DEST that is not absolute is on the SD card: the card is found on the
device - `ls /mnt`, where automount mounts every card (/mnt/<label>, or
/mnt/<node name>) - when it has one; --card NAME picks one of several,
--card none sends under the shell's current directory instead.

A FILE is sent by its name, a DIR with everything in it (names relative
to it), SRC=NAME as NAME (a directory: under NAME). Only the standard
Expand All @@ -16,6 +21,7 @@

import argparse
import os
import re
import select
import sys
import termios
Expand Down Expand Up @@ -179,6 +185,52 @@ def receiver_ready(link, command, timeout):
return False


def mounted_cards(link):
"""What /mnt holds on the device - the cards automount mounted"""
link.write(b'\r')
link.drain()
link.write(b'ls /mnt\r')
said = link.drain(0.5).decode(errors='replace')
said = re.sub(r'\x1b\[[0-9;]*[A-Za-z]', '', said)
if 'ls /mnt' not in said or 'ERROR' in said:
return [] # (the shell not answering yet - starting -, or no /mnt)
said = said.split('ls /mnt', 1)[1] # (what the echo is followed by - it may run into it)
said = re.sub(r'\S*@\S*>', '', said) # (the prompts)
names = []
for line in said.replace('\r', '\n').split('\n'):
names += [n for n in re.split(r'\s{2,}', line.strip()) if n]
return [n for n in names if re.fullmatch(r'[\x21-\x7e][\x20-\x7e]*', n)] # (not what the line had before)


def find_card(link, card, wait, log):
"""The card's directory: CARD, or the one card mounted - looked for again for `wait` seconds"""
until = time.monotonic() + wait
while True:
cards = mounted_cards(link)
if card != 'auto' and card in cards:
return f'/mnt/{card}'
if card == 'auto' and len(cards) == 1:
return f'/mnt/{cards[0]}'
if card == 'auto' and len(cards) > 1:
raise Failure(f'more than one card on the device ({", ".join(cards)}): pick one with --card, '
'or give an absolute --dest')
if time.monotonic() >= until:
what = f'no card {card} in /mnt' if card != 'auto' else 'no card mounted in /mnt'
raise Failure(f'{what} (found: {", ".join(cards) or "nothing"}) - is the card in, formatted (FAT)?')
log(' waiting for the card ...')
time.sleep(2.0)


def destination(link, args, log):
"""Where the files go: --dest as it is (absolute), or under the card"""
if args.dest.startswith('/') or args.card == 'none':
return args.dest
root = find_card(link, args.card, args.wait, log)
dest = f'{root}/{args.dest.strip("/")}' if args.dest.strip('/') else root
log(f' to {dest}')
return dest


def files_of(sources):
"""(local path, name sent) of every source"""
out = []
Expand All @@ -205,7 +257,11 @@ def main():
ap.add_argument('sources', nargs='+', help='FILE, DIR or SRC=NAME')
ap.add_argument('--port', default='/dev/ttyACM0', help='the device console (default /dev/ttyACM0)')
ap.add_argument('--baud', type=int, default=921600)
ap.add_argument('--dest', default='', help='the directory on the device the names are under')
ap.add_argument('--dest', default='', help='the directory on the device the names are under: absolute, '
'or on the SD card (default: the card\'s root)')
ap.add_argument('--card', default='auto', metavar='NAME',
help='the card a relative --dest is on: its name in /mnt (auto: the one there is; none: '
'under the shell\'s current directory)')
ap.add_argument("--block", type=int, choices=(128, 1024), default=1024,
help='YMODEM block size (default 1024)')
ap.add_argument('--no-command', action='store_true', help='ymodem recv is already running')
Expand All @@ -227,7 +283,8 @@ def progress(name, sent, size):
if args.no_command:
wait_for(link, (CRC,), 15.0, 'the receiver')
else:
command = f'ymodem recv -d {args.dest}' if args.dest else 'ymodem recv'
dest = destination(link, args, log)
command = f'ymodem recv -d {dest}' if dest else 'ymodem recv'
until = time.monotonic() + args.wait
while True:
link.write(b'\r')
Expand Down
Loading