Compare commits

...

9 Commits

7 changed files with 436 additions and 99 deletions

325
Cargo.lock generated
View File

@@ -44,6 +44,12 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.9.4" version = "2.9.4"
@@ -56,6 +62,15 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
[[package]]
name = "convert_case"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7"
dependencies = [
"unicode-segmentation",
]
[[package]] [[package]]
name = "crossbeam-channel" name = "crossbeam-channel"
version = "0.5.15" version = "0.5.15"
@@ -71,12 +86,79 @@ version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "crossterm"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
dependencies = [
"bitflags",
"crossterm_winapi",
"derive_more",
"document-features",
"mio",
"parking_lot",
"rustix",
"signal-hook",
"signal-hook-mio",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "defer-lite" name = "defer-lite"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6a1ef0750c0fcdb9bd00e7829fcad58e9a0a2ab7078b57c39743b973f3878ce" checksum = "d6a1ef0750c0fcdb9bd00e7829fcad58e9a0a2ab7078b57c39743b973f3878ce"
[[package]]
name = "derive_more"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
dependencies = [
"derive_more-impl",
]
[[package]]
name = "derive_more-impl"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
dependencies = [
"convert_case",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "document-features"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d"
dependencies = [
"litrs",
]
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.0",
]
[[package]] [[package]]
name = "getopts" name = "getopts"
version = "0.2.24" version = "0.2.24"
@@ -93,16 +175,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
[[package]] [[package]]
name = "libredox" name = "linux-raw-sys"
version = "0.1.10" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]]
name = "litrs"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
[[package]]
name = "lock_api"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
dependencies = [ dependencies = [
"bitflags", "autocfg",
"libc", "scopeguard",
"redox_syscall",
] ]
[[package]]
name = "log"
version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
[[package]] [[package]]
name = "mach" name = "mach"
version = "0.1.2" version = "0.1.2"
@@ -124,6 +223,18 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "mio"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "nom" name = "nom"
version = "7.1.3" version = "7.1.3"
@@ -135,10 +246,27 @@ dependencies = [
] ]
[[package]] [[package]]
name = "numtoa" name = "parking_lot"
version = "0.2.4" version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f" checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets",
]
[[package]] [[package]]
name = "pbr" name = "pbr"
@@ -191,10 +319,23 @@ dependencies = [
] ]
[[package]] [[package]]
name = "redox_termios" name = "rustix"
version = "0.1.3" version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.61.0",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]] [[package]]
name = "serial2" name = "serial2"
@@ -228,6 +369,42 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-mio"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
dependencies = [
"libc",
"mio",
"signal-hook",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.106" version = "2.0.106"
@@ -239,28 +416,16 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "termion"
version = "4.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3669a69de26799d6321a5aa713f55f7e2cd37bd47be044b50f2acafc42c122bb"
dependencies = [
"libc",
"libredox",
"numtoa",
"redox_termios",
]
[[package]] [[package]]
name = "tulflash" name = "tulflash"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"argp", "argp",
"crossterm",
"pbr", "pbr",
"serial2", "serial2",
"serial_enumerator", "serial_enumerator",
"shlex", "shlex",
"termion",
] ]
[[package]] [[package]]
@@ -275,12 +440,24 @@ version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.2.1" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@@ -309,39 +486,127 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aac7fef12f4b59cd0a29339406cc9203ab44e440ddff6b3f5a41455349fa9cf3" checksum = "aac7fef12f4b59cd0a29339406cc9203ab44e440ddff6b3f5a41455349fa9cf3"
dependencies = [ dependencies = [
"windows_aarch64_msvc", "windows_aarch64_msvc 0.29.0",
"windows_i686_gnu", "windows_i686_gnu 0.29.0",
"windows_i686_msvc", "windows_i686_msvc 0.29.0",
"windows_x86_64_gnu", "windows_x86_64_gnu 0.29.0",
"windows_x86_64_msvc", "windows_x86_64_msvc 0.29.0",
] ]
[[package]]
name = "windows-link"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc 0.52.6",
"windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
"windows_i686_msvc 0.52.6",
"windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc 0.52.6",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.29.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b" checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.29.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8793f59f7b8e8b01eda1a652b2697d87b93097198ae85f823b969ca5b89bba58" checksum = "8793f59f7b8e8b01eda1a652b2697d87b93097198ae85f823b969ca5b89bba58"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.29.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4" checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.29.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d615f419543e0bd7d2b3323af0d86ff19cbc4f816e6453f36a2c2ce889c354" checksum = "f3d615f419543e0bd7d2b3323af0d86ff19cbc4f816e6453f36a2c2ce889c354"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.29.0" version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11d95421d9ed3672c280884da53201a5c46b7b2765ca6faf34b0d71cf34a3561" checksum = "11d95421d9ed3672c280884da53201a5c46b7b2765ca6faf34b0d71cf34a3561"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View File

@@ -5,8 +5,8 @@ edition = "2024"
[dependencies] [dependencies]
argp = "0.4.0" argp = "0.4.0"
crossterm = "0.29.0"
pbr = "1.1.1" pbr = "1.1.1"
serial2 = "0.2.32" serial2 = "0.2.32"
serial_enumerator = "0.2.12" serial_enumerator = "0.2.12"
shlex = "1.3.0" shlex = "1.3.0"
termion = "4.0.5"

View File

@@ -2,31 +2,33 @@
## Installation instructions ## Installation instructions
No need to clone this repo manually. You'll just need to install the Rust toolchain. No need to clone this repo manually. You'll just need to install the Rust toolchain and SDCC.
```bash ```bash
# All OSes # All OSes
cargo install --git https://git.zumepro.cz/michal.prochazka/tulflash cargo install --git https://git.zumepro.cz/michal.prochazka/tulflash
``` ```
## Flashing Intel HEX binaries ## Running the example program
```bash
# Generate the example program (only needed to run once):
tulflash example
# Compile, flash and monitor the example program:
tulflash run example.c:
# note: `tulflash run example.c` is the thing as `tulflash write --cmd "sdcc example.c" --monitor example.ihx`
```
If the flash fails, try to add `--slow` before `run` (should not be needed though).
## Manually flashing Intel HEX binaries
```bash ```bash
# All OSes, automatically detects the correct serial port # All OSes, automatically detects the correct serial port
tulflash write <path-to-hex> tulflash write <path-to-hex>
``` ```
If the flash fails, try to add `--slow` before `write` (should not be needed though).
The tool also allows reading and erasing the chip, figure that out on your own if you need that (although `tulflash --help` might guide you if you ask it nicely). The tool also allows reading and erasing the chip, figure that out on your own if you need that (although `tulflash --help` might guide you if you ask it nicely).
## Example program
You'll need to clone this repo (or just [download the file](example.c)) and install SDCC:
```bash
tulflash run example.c
# Same thing as `tulflash write --cmd "sdcc example.c" --monitor example.ihx`
```

View File

@@ -8,19 +8,12 @@
//********************************************************************** //**********************************************************************
//********************************************************************** //**********************************************************************
#include <at89c55.h> #include <at89c51ed2.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#define TICK_RATE 100 #define TICK_RATE 100
#define NPER (0x10000 - (20000000 / 12 / TICK_RATE)) #define NPER (0x10000 - (20000000 / 6 / TICK_RATE))
// Missing port definitions
__sbit __at (0xC4) P4_4;
__sbit __at (0xC3) P4_3;
__sbit __at (0xC2) P4_2;
__sbit __at (0xC1) P4_1;
__sbit __at (0xC0) P4_0;
// I/O definitions // I/O definitions
#define BUTTON_1 P3_2 #define BUTTON_1 P3_2
@@ -71,8 +64,7 @@ uint8_t lcd_pos;
// Quick'n'dirty CPU pause, just enough for the LCD to stabilize. // Quick'n'dirty CPU pause, just enough for the LCD to stabilize.
void lcd_pause(void) { void lcd_pause(void) {
int i = 30; __asm__ ("nop");
while(i--);
} }
// Reads the status register from the LCD. // Reads the status register from the LCD.
@@ -170,11 +162,8 @@ void lcd_init(void) {
// Puts a character to the LCD. Correctly handles '\n'. // Puts a character to the LCD. Correctly handles '\n'.
void lcd_putchar(char c) { void lcd_putchar(char c) {
if(c == 10) { if(c == 10) {
while((lcd_pos != 0) && (lcd_pos != 40)) { if(lcd_pos < 40) lcd_pos = 40;
lcd_send_data(32); else lcd_pos = 0;
lcd_pos++;
if(lcd_pos == 80) lcd_pos=0;
}
} else { } else {
lcd_send_data(c); lcd_send_data(c);
lcd_pos++; lcd_pos++;
@@ -184,6 +173,8 @@ void lcd_putchar(char c) {
// Initializes the background tick timer (for delays). // Initializes the background tick timer (for delays).
void timer_init(void) { void timer_init(void) {
CKCON0 = X2; // Enable 2x clock mode
// Initialize timer 0 as 16-bit countdown, timer 1 as 8-bit auto-reload countdown // Initialize timer 0 as 16-bit countdown, timer 1 as 8-bit auto-reload countdown
TMOD = 0x21; TMOD = 0x21;
@@ -196,7 +187,8 @@ void timer_init(void) {
// Enable interrupts only for timer 0 // Enable interrupts only for timer 0
IE = 0x82; EA = 1;
ET0 = 1;
} }
// Initializes the serial port (along with timer 2). // Initializes the serial port (along with timer 2).
@@ -204,7 +196,7 @@ void serial_init(void) {
// Initialize timer 2 as 312500 Hz as the baud rate generator (for tulflash) // Initialize timer 2 as 312500 Hz as the baud rate generator (for tulflash)
RCAP2H = 0xFF; RCAP2H = 0xFF;
RCAP2L = 0xFE; RCAP2L = 0xFC;
T2CON = 0x34; T2CON = 0x34;
// Initialize serial I/O // Initialize serial I/O
@@ -217,6 +209,7 @@ void serial_init(void) {
void serial_putchar(char c) { void serial_putchar(char c) {
while(TI == 0); while(TI == 0);
SBUF = c; SBUF = c;
TI = 0;
} }
__bit stdout_to_lcd = 0; __bit stdout_to_lcd = 0;
@@ -296,6 +289,8 @@ void main(void) {
lcd_init(); lcd_init();
serial_init(); serial_init();
delay(1);
stdout_to_serial = 1; stdout_to_serial = 1;
stdout_to_lcd = 1; stdout_to_lcd = 1;

View File

@@ -24,7 +24,8 @@ pub enum ArgCommand {
Write(ArgWrite), Write(ArgWrite),
Erase(ArgErase), Erase(ArgErase),
Monitor(ArgMonitor), Monitor(ArgMonitor),
Run(ArgRun) Run(ArgRun),
Example(ArgExample)
} }
#[derive(FromArgs)] #[derive(FromArgs)]
@@ -56,6 +57,10 @@ pub struct ArgWrite {
#[argp(description = "Path to the source Intel HEX file.")] #[argp(description = "Path to the source Intel HEX file.")]
pub path: OsString, pub path: OsString,
#[argp(option)]
#[argp(description = "Where to run the command. Will be created if it doesn't exist.")]
pub cmd_path: Option<std::path::PathBuf>,
#[argp(option)] #[argp(option)]
#[argp(description = "Command to run before writing the file. Handy for compiling the program and running it at the same time.")] #[argp(description = "Command to run before writing the file. Handy for compiling the program and running it at the same time.")]
pub cmd: Option<OsString>, pub cmd: Option<OsString>,
@@ -90,19 +95,28 @@ pub struct ArgWrite {
#[argp(subcommand, name = "erase")] #[argp(subcommand, name = "erase")]
pub struct ArgErase {} pub struct ArgErase {}
#[derive(FromArgs)]
#[argp(description = "Opens the serial monitor.")]
#[argp(subcommand, name = "monitor")]
pub struct ArgMonitor {}
#[derive(FromArgs)] #[derive(FromArgs)]
#[argp(description = "Handy shorthand for `write --cmd \"sdcc <srcpath>\" --monitor <hexpath>`.")] #[argp(description = "Handy shorthand for `write --cmd \"sdcc <srcpath>\" --monitor <hexpath>`.")]
#[argp(subcommand, name = "run")] #[argp(subcommand, name = "run")]
pub struct ArgRun { pub struct ArgRun {
#[argp(positional)] #[argp(positional)]
#[argp(description = "Path to the source C file.")] #[argp(description = "Path to the source C file.")]
pub path: OsString pub path: std::path::PathBuf
} }
#[derive(FromArgs)] #[derive(FromArgs)]
#[argp(description = "Opens the serial monitor.")] #[argp(description = "Generates a \"stub\" C file for the TUL výukový přípravek™.")]
#[argp(subcommand, name = "monitor")] #[argp(subcommand, name = "example")]
pub struct ArgMonitor {} pub struct ArgExample {
#[argp(positional)]
#[argp(description = "Path to the source C file to be generated.")]
pub path: Option<OsString>
}
pub fn parse() -> Args { pub fn parse() -> Args {
let args: Args = argp::parse_args_or_exit(argp::DEFAULT); let args: Args = argp::parse_args_or_exit(argp::DEFAULT);

View File

@@ -3,6 +3,7 @@ use std::io::{Cursor, Error, Write};
use std::path::PathBuf; use std::path::PathBuf;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use crossterm::event::{KeyCode, KeyModifiers};
use pbr::ProgressBar; use pbr::ProgressBar;
mod args; mod args;
@@ -16,7 +17,6 @@ use monitor::Monitor;
mod target; mod target;
use target::{PhysicalTarget, Target}; use target::{PhysicalTarget, Target};
use termion::event::Key;
mod utils; mod utils;
@@ -204,16 +204,23 @@ fn write_chip_data(args: &ArgWrite, target: &mut PhysicalTarget) -> Result<(), E
fn write_chip(args: ArgWrite, target: &mut PhysicalTarget) -> Result<(), Error> { fn write_chip(args: ArgWrite, target: &mut PhysicalTarget) -> Result<(), Error> {
loop { loop {
if let Some(cmd) = args.cmd.as_ref() { if let Some(cmd) = args.cmd.as_ref() {
let cmd_path = &args.cmd_path;
let mut args = shlex::bytes::split(cmd.as_encoded_bytes()) let mut args = shlex::bytes::split(cmd.as_encoded_bytes())
.ok_or(Error::other("Error parsing commandline arguments"))? .ok_or(Error::other("Error parsing commandline arguments"))?
.into_iter() .into_iter()
.map(|x| unsafe { OsString::from_encoded_bytes_unchecked(x) }); .map(|x| unsafe { OsString::from_encoded_bytes_unchecked(x) });
if let Some(cmd_path) = cmd_path {
if !cmd_path.is_dir() {
Err(Error::other("invalid cmd path (not a dir)"))?
}
}
let Some(name) = args.next() else { let Some(name) = args.next() else {
Err(Error::other("No command provided"))? Err(Error::other("No command provided"))?
}; };
let out = std::process::Command::new(name) let out = std::process::Command::new(name)
.current_dir(cmd_path.as_ref().map(|p| p.as_path()).unwrap_or(&std::path::Path::new(".")))
.args(args) .args(args)
.output()?; .output()?;
@@ -230,11 +237,13 @@ fn write_chip(args: ArgWrite, target: &mut PhysicalTarget) -> Result<(), Error>
if !args.monitor { break } if !args.monitor { break }
let cause = Monitor::new() let mut mon = Monitor::new();
.add_hook(Key::Ctrl('f'), if args.cmd.is_none() { "Re-flash target" } else { "Re-run command and flash target" })
.run(target.port())?;
if cause != Key::Ctrl('f') { break } let reflash_handle = mon.add_hook(KeyCode::Char('f'), KeyModifiers::CONTROL, if args.cmd.is_none() { "Re-flash target" } else { "Re-run command and flash target" });
let cause = mon.run(target.port())?;
if cause != reflash_handle { break }
target.resync_target()?; target.resync_target()?;
} }
@@ -255,11 +264,21 @@ fn monitor_chip(_args: ArgMonitor, target: &mut PhysicalTarget) -> Result<(), Er
} }
fn run_chip(args: ArgRun, target: &mut PhysicalTarget) -> Result<(), Error> { fn run_chip(args: ArgRun, target: &mut PhysicalTarget) -> Result<(), Error> {
let path = PathBuf::from(&args.path).with_extension("ihx").into_os_string(); let build_dir = args.path.parent().unwrap().join("tulflash");
let cmd = Some(OsString::from(format!("sdcc \"{}\"", unsafe { String::from_utf8_unchecked(args.path.into_encoded_bytes()) })));
let source_file_name = args.path.file_name().ok_or(Error::other("invalid path to compilation source"))?;
let source_file = build_dir.join(&source_file_name);
let output_file = source_file.with_extension("ihx");
let cmd = Some(OsString::from(format!("sdcc \"{}\"", source_file_name.to_string_lossy())));
let cmd_path = Some(build_dir.clone());
std::fs::create_dir_all(build_dir)?;
std::fs::copy(args.path, &source_file)?;
write_chip(ArgWrite { write_chip(ArgWrite {
path, path: output_file.into_os_string(),
cmd_path,
cmd, cmd,
start: 0, start: 0,
end: 65535, end: 65535,
@@ -270,9 +289,32 @@ fn run_chip(args: ArgRun, target: &mut PhysicalTarget) -> Result<(), Error> {
}, target) }, target)
} }
fn gen_example(args: ArgExample) -> Result<(), Error> {
let path = PathBuf::from(args.path.unwrap_or(OsString::from("example.c")));
if path.try_exists()? {
Err(Error::other("File already exists"))?
}
std::fs::write(&path, include_bytes!("../example.c"))?;
let path = path.to_string_lossy();
println!("Example source code generated to `{}`.", path);
println!("Execute `tulflash run \"{}\"` to run it.", path);
Ok(())
}
fn main() { fn main() {
let args = args::parse(); let args = args::parse();
if let ArgCommand::Example(args) = args.command {
if let Err(err) = gen_example(args) {
println!("Error generating example source code: {}", err);
}
return
}
let start = SystemTime::now(); let start = SystemTime::now();
let port = args.port.or_else(|| { let port = args.port.or_else(|| {
@@ -298,7 +340,8 @@ fn main() {
ArgCommand::Write(args) => write_chip(args, &mut target), ArgCommand::Write(args) => write_chip(args, &mut target),
ArgCommand::Erase(args) => erase_chip(args, &mut target), ArgCommand::Erase(args) => erase_chip(args, &mut target),
ArgCommand::Monitor(args) => monitor_chip(args, &mut target), ArgCommand::Monitor(args) => monitor_chip(args, &mut target),
ArgCommand::Run(args) => run_chip(args, &mut target) ArgCommand::Run(args) => run_chip(args, &mut target),
ArgCommand::Example(_) => unreachable!()
}; };
if let Err(err) = res { if let Err(err) = res {

View File

@@ -1,32 +1,46 @@
use std::io::{Error, ErrorKind, Write}; use std::io::{Error, ErrorKind, Write};
use std::time::Duration; use std::time::Duration;
use crossterm::event::{Event, KeyCode, KeyModifiers};
use serial2::SerialPort; use serial2::SerialPort;
use termion::raw::IntoRawMode; struct RawMode {}
use termion::event::Key;
use termion::input::TermRead; impl RawMode {
fn init() -> Result<Self, Error> {
crossterm::terminal::enable_raw_mode()?;
Ok(Self {})
}
}
impl Drop for RawMode {
fn drop(&mut self) {
let _ = crossterm::terminal::disable_raw_mode();
}
}
pub struct Monitor { pub struct Monitor {
hooks: Vec<(Key, &'static str)> hooks: Vec<(KeyCode, KeyModifiers, &'static str)>
} }
impl Monitor { impl Monitor {
pub fn new() -> Self { pub fn new() -> Self {
let mut hooks = Vec::new(); let mut hooks = Vec::new();
hooks.push((Key::Ctrl('c'), "Exit monitor")); hooks.push((KeyCode::Char('c'), KeyModifiers::CONTROL, "Exit monitor"));
hooks.push((Key::Ctrl('r'), "Reboot target")); hooks.push((KeyCode::Char('r'), KeyModifiers::CONTROL, "Reboot target"));
Self { hooks } Self { hooks }
} }
pub fn add_hook(&mut self, key: Key, desc: &'static str) -> &mut Self { pub fn add_hook(&mut self, key: KeyCode, mods: KeyModifiers, desc: &'static str) -> usize {
self.hooks.push((key, desc)); let idx = self.hooks.len();
self self.hooks.push((key, mods, desc));
idx
} }
pub fn run(&mut self, port: &mut SerialPort) -> Result<Key, Error> { pub fn run(&mut self, port: &mut SerialPort) -> Result<usize, Error> {
port.set_dtr(true)?; port.set_dtr(true)?;
port.set_rts(true)?; port.set_rts(true)?;
std::thread::sleep(Duration::from_millis(100)); std::thread::sleep(Duration::from_millis(100));
@@ -36,10 +50,10 @@ impl Monitor {
println!(); println!();
println!("Monitor controls:"); println!("Monitor controls:");
for (key, desc) in &self.hooks { for (key, mods, desc) in &self.hooks {
let key = match key { let key = match (key, *mods) {
Key::Char(c) => format!("{}", c.to_uppercase()), (KeyCode::Char(c), KeyModifiers::NONE) => format!("{}", c.to_uppercase()),
Key::Ctrl(c) => format!("Ctrl+{}", c.to_uppercase()), (KeyCode::Char(c), KeyModifiers::CONTROL) => format!("Ctrl+{}", c.to_uppercase()),
key => format!("{:?}", key) key => format!("{:?}", key)
}; };
@@ -48,9 +62,8 @@ impl Monitor {
println!(); println!();
let mut stdout = std::io::stdout().into_raw_mode().unwrap(); let _raw = RawMode::init()?;
let mut stdout = std::io::stdout();
let mut stdin = termion::async_stdin().keys();
'main: loop { 'main: loop {
let mut buf = [0u8; 1]; let mut buf = [0u8; 1];
@@ -70,8 +83,13 @@ impl Monitor {
Err(err)? Err(err)?
} }
if let Some(Ok(key)) = stdin.next() { if crossterm::event::poll(Duration::ZERO)? {
if let Key::Ctrl('r') = key { let (key, mods) = match crossterm::event::read()? {
Event::Key(ev) => (ev.code, ev.modifiers),
_ => continue
};
if key == KeyCode::Char('r') && mods == KeyModifiers::CONTROL {
stdout.write_all(b"\r\n*** Reboot ***\r\n")?; stdout.write_all(b"\r\n*** Reboot ***\r\n")?;
port.set_dtr(true)?; port.set_dtr(true)?;
port.set_rts(true)?; port.set_rts(true)?;
@@ -81,10 +99,10 @@ impl Monitor {
continue continue
} }
for (hook_key, _) in &self.hooks { for (idx, (hook_key, hook_mods, _)) in self.hooks.iter().enumerate() {
if hook_key == &key { if hook_key == &key && hook_mods == &mods {
stdout.write_all(b"\r\n")?; stdout.write_all(b"\r\n")?;
break 'main Ok(key) break 'main Ok(idx)
} }
} }
} }