Compare commits

..

24 Commits

Author SHA1 Message Date
04b642776d Made the code look a bit less ugly 2025-09-24 13:19:01 +02:00
9f4a61a7ec add compilation in separate directory 2025-09-24 12:06:43 +02:00
d35c88e38f Temporarily removed the serial echo (was causing terrible performance) 2025-09-21 12:26:04 +02:00
cf04037f9d Example now enables the serial RX interrupt for echo 2025-09-21 11:10:53 +02:00
2a88835da5 Massively sped up LCD comms 2025-09-21 10:56:15 +02:00
aa84a2c03b Massively sped up lcd_putchar's handling of '\n' 2025-09-21 10:51:08 +02:00
52a232f1e9 Now using the correct header file with all port definitions 2025-09-21 10:49:39 +02:00
ab9078ab3f Added command for generating the kopyto 2025-09-20 23:04:18 +02:00
37f15bf187 Swapped out termion for crossterm 2025-09-20 22:48:12 +02:00
e4c4a7f14a The program no longer swears at you 2025-09-19 18:09:28 +02:00
d7b70b7629 Fixed wording 2025-09-19 18:09:14 +02:00
b2ab748ffb Hopefully improves formatting 2025-09-19 18:08:36 +02:00
4bf8f6a8e7 The monitor no longer spits out garbage, whoops 2025-09-19 18:03:01 +02:00
2ef84e6aa6 Added convenient run shorthand 2025-09-19 18:02:43 +02:00
dd49c30ac9 Added functionality for running a command before flashing 2025-09-19 17:50:52 +02:00
1b9f1ea4c1 write can now open a monitor right after flashing 2025-09-19 16:13:51 +02:00
b6b79e7fcf Vandalized the example even more 2025-09-19 15:27:19 +02:00
ffd1aa4874 Target resync now flushes all buffers (caused errors before) 2025-09-19 15:26:53 +02:00
dcbdc9ff89 Made the monitor actually usable now 2025-09-19 15:26:39 +02:00
80dd1c1a70 The monitor now correctly outputs stuff to the screen 2025-09-19 15:15:40 +02:00
1dbbaab197 Implemented auto port detection 2025-09-19 11:14:13 +02:00
d298db44d2 No longer panic in Drop 2025-09-19 11:12:47 +02:00
ebd24ae7b5 Added some stuff for the monitor (can already reboot the target) 2025-09-19 11:04:53 +02:00
c803e6514f Some functions are not even tested 2025-09-19 09:31:56 +02:00
8 changed files with 979 additions and 294 deletions

428
Cargo.lock generated
View File

@@ -2,6 +2,27 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "CoreFoundation-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0e9889e6db118d49d88d84728d0e964d973a5680befb5f85f55141beea5c20b"
dependencies = [
"libc",
"mach",
]
[[package]]
name = "IOKit-sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99696c398cbaf669d2368076bdb3d627fb0ce51a26899d7c61228c5c0af3bf4a"
dependencies = [
"CoreFoundation-sys",
"libc",
"mach",
]
[[package]]
name = "argp"
version = "0.4.0"
@@ -23,6 +44,12 @@ dependencies = [
"syn",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "bitflags"
version = "2.9.4"
@@ -35,6 +62,15 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "crossbeam-channel"
version = "0.5.15"
@@ -50,6 +86,79 @@ version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "defer-lite"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "getopts"
version = "0.2.24"
@@ -65,12 +174,100 @@ version = "0.2.175"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
[[package]]
name = "linux-raw-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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 = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
[[package]]
name = "mach"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9"
dependencies = [
"libc",
]
[[package]]
name = "memchr"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "parking_lot"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "pbr"
version = "1.1.1"
@@ -112,6 +309,34 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
dependencies = [
"bitflags",
]
[[package]]
name = "rustix"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "serial2"
version = "0.2.32"
@@ -123,6 +348,63 @@ dependencies = [
"winapi",
]
[[package]]
name = "serial_enumerator"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "831ffc034580df26f33a70363cc92c6b1ebd5c6872ef7c191f9140cc0aafb29c"
dependencies = [
"CoreFoundation-sys",
"IOKit-sys",
"defer-lite",
"libc",
"mach",
"nom",
"windows",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "syn"
version = "2.0.106"
@@ -139,8 +421,11 @@ name = "tulflash"
version = "0.1.0"
dependencies = [
"argp",
"crossterm",
"pbr",
"serial2",
"serial_enumerator",
"shlex",
]
[[package]]
@@ -155,12 +440,24 @@ version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-width"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "winapi"
version = "0.3.9"
@@ -182,3 +479,134 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aac7fef12f4b59cd0a29339406cc9203ab44e440ddff6b3f5a41455349fa9cf3"
dependencies = [
"windows_aarch64_msvc 0.29.0",
"windows_i686_gnu 0.29.0",
"windows_i686_msvc 0.29.0",
"windows_x86_64_gnu 0.29.0",
"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]]
name = "windows_aarch64_msvc"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "windows_i686_msvc"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "windows_x86_64_msvc"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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,5 +5,8 @@ edition = "2024"
[dependencies]
argp = "0.4.0"
crossterm = "0.29.0"
pbr = "1.1.1"
serial2 = "0.2.32"
serial_enumerator = "0.2.12"
shlex = "1.3.0"

View File

@@ -2,36 +2,33 @@
## 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
# All OSes
cargo install --git https://git.zumepro.cz/michal.prochazka/tulflash
```
## Flashing Intel HEX binaries
## Running the example program
```
# Linux
tulflash --port /dev/ttyUSBx write <path-to-hex>
```bash
# Generate the example program (only needed to run once):
tulflash example
# macOS
tulflash --port /dev/tty.usbserial-xxx write <path-to-hex>
# Compile, flash and monitor the example program:
tulflash run example.c:
# Wokňous
tulflash --port COMx write <path-to-hex>
# 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 the `--port` argument (should not be needed though).
If the flash fails, try to add `--slow` before `run` (should not be needed though).
## Manually flashing Intel HEX binaries
```bash
# All OSes, automatically detects the correct serial port
tulflash write <path-to-hex>
```
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:
```
sdcc example.c
tulflash --port ... write example.ihx
```

453
example.c
View File

@@ -3,362 +3,319 @@
//*** ***
//*** K O P Y T O V1.1 ***
//*** ***
//*** vandalizoval Michal Procházka ***
//*** vandalized by Michal Procházka ***
//*** ***
//**********************************************************************
//**********************************************************************
#include <8051.h>
#include <at89c51ed2.h>
#include <stdio.h>
#include <stdint.h>
#define TickPerSec 100
#define NPER (0x10000-(20000000L/12/TickPerSec))
#define TICK_RATE 100
#define NPER (0x10000 - (20000000 / 6 / TICK_RATE))
// Definice vstupu a vystupu
#define _P0 0x80
#define _P1 0x90
#define _P2 0xa0
#define _P3 0xb0
#define _P4 0xc0
// I/O definitions
#define BUTTON_1 P3_2
#define BUTTON_2 P3_3
#define PIEZO P3_6
#define Tlac1 P3_2
#define Tlac2 P3_3
#define Buzzer P3_6
#define LED1 P4_2
#define LED2 P4_3
#define LED3 P4_4
#define LED_RED P4_2
#define LED_YELLOW P4_3
#define LED_GREEN P4_4
#define POT P1_0
#define SMT P1_1
#define ZAR P1_2
#define LB_Data P1_3
#define LB_SCK P1_4
#define LB_SCL P1_5
#define LB_RCK P1_6
#define LB_OE P1_7
#define THERM P1_1
#define BULB P1_2
// TIMER se odecita v casovem preruseni
volatile uint16_t TIMER;
uint8_t LCD_Pos;
/*************************************************************************\
* LCD - Liquid Crystal Display *
*-------------------------------------------------------------------------*
* Description : Header file for programming of LCD display based on *
* HITACHI controller HD44780. *
*-------------------------------------------------------------------------*
* Author : Ceba & www.HW.cz Email : ceba@hw.cz *
* Developed : 06.02.2002 Last Update : 12.04.2003 *
* Version : 0.1.0 *
*-------------------------------------------------------------------------*
* Compiler : ANY Version: ANY *
* Source file : LCD.H *
*-------------------------------------------------------------------------*
* Target system : Charon II. - ATmega128, Quartz 14.7456 MHz *
* LCD SC1602A - 4.bit mode *
*-------------------------------------------------------------------------*
* Instruction D7 D6 D5 D4 D3 D2 D1 D0 *
* ============================================== *
* Display clear 0 0 0 0 0 0 0 1 *
* Cursor home 0 0 0 0 0 0 1 * *
* Entry Mode Set 0 0 0 0 0 1 I/D S *
* Display On/Off 0 0 0 0 1 D C B *
* Curs/Disp shift 0 0 0 1 S/C R/L * * *
* Function Set 0 0 1 DL N F * * *
* CG RAM addr set 0 1 ---------Acg--------- *
* DD RAM addr set 1 -------------Add--------- *
* *
* Meaning: *
* * - nonvalid bit *
* Acg - CG RAM address (CHARACTER GENERATOR) *
* Add - DD RAM address (DATA DISPLAY) *
* AC - adress counter *
* *
* I/D - 1-increment, 0-decrement *
* S - 1-display shift, 0-no display shift *
* D - 1-display ON, 0-display OFF *
* C - 1-cursor ON, 0-cursor OFF *
* B - 1-blink ON, 0-blink OFF *
* S/C - 1-display shift, 0-cursor movement *
* R/L - 1-right shift, 0-left shift *
* DL - 1-8 bits data transfer, 0-4 bits data transfer *
* N - 1-1/16 duty, 0-1/8 or 1/11 duty *
* F - 1-5x10 dot matrix, 0-5x7 dot matrix *
* BF - 1-internal operation in progress, 0-display ready *
* *
\*************************************************************************/
#define BAR_DAT P1_3
#define BAR_SCK P1_4
#define BAR_SCL P1_5
#define BAR_RCK P1_6
#define BAR_OE P1_7
#define LCD_RS_PIN P2_4
#define LCD_RW_PIN P2_5
#define LCD_EN_PIN P2_6
#define LCD_RS 0x10 /* rgister select */
#define LCD_RW 0x20 /* read/write */
#define LCD_EN 0x40 /* chip enable */
#define KEY_COL_1 P0_0
#define KEY_COL_2 P0_1
#define KEY_COL_3 P0_2
#define KEY_COL_4 P0_3
/* --- LCD commands --- */
#define KEY_ROW_1 P0_4
#define KEY_ROW_2 P0_5
#define KEY_ROW_3 P0_6
#define KEY_ROW_4 P0_7
#define cmd_lcd_init 0x38
volatile uint16_t TIMER;
#define cmd_lcd_clear 0x01
#define cmd_lcd_home 0x02
#define cmd_cur_shift_on 0x06
#define cmd_cur_shift_off 0x07
#define cmd_lcd_on 0x0E
#define cmd_lcd_off 0x0A
#define cmd_cur_on 0x0E
#define cmd_cur_off 0x0C
#define cmd_cur_blink_on 0x0F
#define cmd_cur_blink_off 0x0E
#define cmd_cur_left 0x10
#define cmd_cur_right 0x14
#define cmd_scr_left 0x18
#define cmd_scr_right 0x1C
#define cmd_set_cgram_addr 0x40
#define cmd_set_ddram_addr 0x80
void Delay(int pause) {
// Timer-based delay, waits for pause * 10 ms
void delay(int pause) {
TIMER = 1 + pause;
while(TIMER);
}
void LCD_Pause(void) {
// Hnus, ale funguje to
int i = 30;
while(i--);
uint8_t lcd_pos;
#define LCD_RS 0x10 /* rgister select */
#define LCD_RW 0x20 /* read/write */
#define LCD_EN 0x40 /* chip enable */
// Quick'n'dirty CPU pause, just enough for the LCD to stabilize.
void lcd_pause(void) {
__asm__ ("nop");
}
uint8_t LCD_State(void) {
// Reads the status register from the LCD.
uint8_t lcd_read_status(void) {
uint8_t temp;
LCD_Pause();
lcd_pause();
P2 = LCD_RW | 0x0F;
LCD_Pause();
lcd_pause();
LCD_EN_PIN = 1;
LCD_Pause();
lcd_pause();
temp = (P2 & 0x0F) << 4;
LCD_EN_PIN = 0;
LCD_Pause();
lcd_pause();
LCD_EN_PIN = 1;
LCD_Pause();
lcd_pause();
temp = temp + (P2 & 0x0F);
LCD_EN_PIN = 0;
return temp;
}
void LCD_SendCmd( uint8_t val )
// Writes a command to the LCD.
void lcd_send_cmd( uint8_t val )
{
LCD_Pause();
lcd_pause();
P2 = (val >> 4) & 0x0F;
LCD_Pause();
lcd_pause();
LCD_EN_PIN = 1;
LCD_Pause();
lcd_pause();
LCD_EN_PIN = 0;
LCD_Pause();
lcd_pause();
P2 = (val & 0x0F);
LCD_Pause();
lcd_pause();
LCD_EN_PIN = 1;
LCD_Pause();
lcd_pause();
LCD_EN_PIN = 0;
while(LCD_State() & 0x80);
while(lcd_read_status() & 0x80);
}
void LCD_SendData(uint8_t val) {
LCD_Pause();
// Writes a data value to the LCD.
void lcd_send_data(uint8_t val) {
lcd_pause();
P2 = LCD_RS | ((val >> 4) & 0x0F);
LCD_Pause();
lcd_pause();
LCD_EN_PIN = 1;
LCD_Pause();
lcd_pause();
LCD_EN_PIN = 0;
LCD_Pause();
lcd_pause();
P2 = LCD_RS | (val & 0x0F);
LCD_Pause();
lcd_pause();
LCD_EN_PIN = 1;
LCD_Pause();
lcd_pause();
LCD_EN_PIN = 0;
while(LCD_State() & 0x80);
while(lcd_read_status() & 0x80);
}
void LCD_Clear(void) {
LCD_SendCmd(0x01); /* display clear */
LCD_Pos=0;
// Clears the LCD.
void lcd_clear(void) {
lcd_send_cmd(0x01); /* display clear */
lcd_pos = 0;
}
void LCD_Init(void) {
// Initializes the LCD.
void lcd_init(void) {
P2 = 0; /* set RS, RW and EN low */
/* all delays are vital */
Delay(50); /* power on delay - wait more than 15 ms */
delay(50); /* power on delay - wait more than 15 ms */
for(uint8_t i = 0; i < 3; i++) {
P2 = 0x03; /* lce enable low */
Delay(1); /* wait more than 100us */
delay(1); /* wait more than 100us */
P2 = LCD_EN | 0x03; /* lcd enable high */
Delay(1); /* wait more than 100us */
delay(1); /* wait more than 100us */
P2 = 0x03; /* lce enable low */
Delay(5); /* wait more than 4.1 ms */
delay(5); /* wait more than 4.1 ms */
}
P2 = 0x02; /* lcd enable low */
Delay(1); /* wait more than 100us */
delay(1); /* wait more than 100us */
P2 = LCD_EN | 0x02; /* lcd enable high */
Delay(1); /* wait more than 100us */
delay(1); /* wait more than 100us */
P2 = 0x02; /* lcd enable low */
Delay(5); /* wait more than 100us */
delay(5); /* wait more than 100us */
LCD_SendCmd(0x28); /* 4 bit mode, 1/16 duty, 5x8 font */
LCD_SendCmd(0x08); /* display off */
LCD_Clear();
LCD_SendCmd(0x06); /* entry mode */
LCD_SendCmd(0x0C); /* display on, blinking cursor off */
lcd_send_cmd(0x28); /* 4 bit mode, 1/16 duty, 5x8 font */
lcd_send_cmd(0x08); /* display off */
lcd_clear();
lcd_send_cmd(0x06); /* entry mode */
lcd_send_cmd(0x0C); /* display on, blinking cursor off */
}
int putchar(int c) {
// Puts a character to the LCD. Correctly handles '\n'.
void lcd_putchar(char c) {
if(c == 10) {
while((LCD_Pos != 0) && (LCD_Pos != 40)) {
LCD_SendData(32);
LCD_Pos++;
if(LCD_Pos == 80) LCD_Pos=0;
}
if(lcd_pos < 40) lcd_pos = 40;
else lcd_pos = 0;
} else {
LCD_SendData(c);
LCD_Pos++;
if(LCD_Pos == 80) LCD_Pos=0;
lcd_send_data(c);
lcd_pos++;
if(lcd_pos == 80) lcd_pos=0;
}
}
// Initializes the background tick timer (for delays).
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
TMOD = 0x21;
TCON = 0x50;
// Initialize timer 0 for 100 Hz
TL0 = (uint8_t)NPER;
TH0 = (uint8_t)(NPER >> 8);
// Enable interrupts only for timer 0
EA = 1;
ET0 = 1;
}
// Initializes the serial port (along with timer 2).
void serial_init(void) {
// Initialize timer 2 as 312500 Hz as the baud rate generator (for tulflash)
RCAP2H = 0xFF;
RCAP2L = 0xFC;
T2CON = 0x34;
// Initialize serial I/O
SCON = 0x50;
TI = 1;
}
// Writes a character to the serial port.
void serial_putchar(char c) {
while(TI == 0);
SBUF = c;
TI = 0;
}
__bit stdout_to_lcd = 0;
__bit stdout_to_serial = 0;
// Writes a character to standard output (LCD, serial or both).
int putchar(int c) {
if(stdout_to_lcd) {
lcd_putchar(c);
}
if(stdout_to_serial) {
serial_putchar(c);
}
return 0;
}
/*****************************************
** Nastaveni preruseni **
*****************************************/
/* Seriove preruseni a timer1 jsou nastaveny
na 115200bps, timer0 se nastavuje pomoci TH0.*/
void init_interrupts(void) {
TMOD=0x21;
TCON=0x50;
PCON=0x80;
TL0=(uint8_t)NPER;
TH0=(uint8_t)(NPER >> 8);
IE=0x82;
}
/*****************************************
** Obsluha LED baru **
*****************************************/
/*
__sbit __at _P1+3 LB_Data;
__sbit __at _P1+4 LB_SCK;
__sbit __at _P1+5 LB_SCL; RESET
__sbit __at _P1+6 LB_RCK; PREPIS
__sbit __at _P1+7 LB_OE;
*/
void SetLedBar(uint16_t n) {
// Writes a 10-bit value to the LED bar. Bit 0 = bottom LED, bit 9 = top LED.
void led_bar_set(uint16_t n) {
uint8_t i;
LB_RCK = 0;
LB_SCL = 0;
LB_SCL = 1;
LB_SCK = 0;
BAR_RCK = 0;
BAR_SCL = 0;
BAR_SCL = 1;
BAR_SCK = 0;
for(i = 0; i < 10; i++) {
LB_Data = !(n & 1);
BAR_DAT = !(n & 1);
n >>= 1; // n = n >> 1
LB_SCK = 1;
LB_SCK = 0;
BAR_SCK = 1;
BAR_SCK = 0;
}
LB_RCK = 1;
LB_OE = 0;
BAR_RCK = 1;
BAR_OE = 0;
}
/*****************************************
** Obsluha Klavesnice **
*****************************************/
#define KEY_C_1 P0_0
#define KEY_C_2 P0_1
#define KEY_C_3 P0_2
#define KEY_C_4 P0_3
#define KEY_R_1 P0_4
#define KEY_R_2 P0_5
#define KEY_R_3 P0_6
#define KEY_R_4 P0_7
char GetKeyboard(void) {
// Reads a character from the keypad.
char keypad_read(void) {
P0 = 0xFF;
KEY_R_1 = 0;
LCD_Pause();
if (!KEY_C_1) return '1';
if (!KEY_C_2) return '2';
if (!KEY_C_3) return '3';
if (!KEY_C_4) return 'A';
KEY_ROW_1 = 0;
lcd_pause();
if (!KEY_COL_1) return '1';
if (!KEY_COL_2) return '2';
if (!KEY_COL_3) return '3';
if (!KEY_COL_4) return 'A';
P0 = 0xFF;
KEY_R_2 = 0;
LCD_Pause();
if (!KEY_C_1) return '4';
if (!KEY_C_2) return '5';
if (!KEY_C_3) return '6';
if (!KEY_C_4) return 'B';
KEY_ROW_2 = 0;
lcd_pause();
if (!KEY_COL_1) return '4';
if (!KEY_COL_2) return '5';
if (!KEY_COL_3) return '6';
if (!KEY_COL_4) return 'B';
P0 = 0xFF;
KEY_R_3 = 0;
LCD_Pause();
if (!KEY_C_1) return '7';
if (!KEY_C_2) return '8';
if (!KEY_C_3) return '9';
if (!KEY_C_4) return 'C';
KEY_ROW_3 = 0;
lcd_pause();
if (!KEY_COL_1) return '7';
if (!KEY_COL_2) return '8';
if (!KEY_COL_3) return '9';
if (!KEY_COL_4) return 'C';
P0 = 0xFF;
KEY_R_4 = 0;
LCD_Pause();
if (!KEY_C_1) return '*';
if (!KEY_C_2) return '0';
if (!KEY_C_3) return '#';
if (!KEY_C_4) return 'D';
KEY_ROW_4 = 0;
lcd_pause();
if (!KEY_COL_1) return '*';
if (!KEY_COL_2) return '0';
if (!KEY_COL_3) return '#';
if (!KEY_COL_4) return 'D';
return -1;
}
/*****************************************
** Hlavni program **
*****************************************/
void main(void) {
init_interrupts();
LCD_Init();
timer_init();
lcd_init();
serial_init();
int i = 0;
delay(1);
stdout_to_serial = 1;
stdout_to_lcd = 1;
int i = 1;
while(1) {
LCD_Clear();
printf("hellOwOrld! %d", ++i);
Delay(TickPerSec);
lcd_clear();
printf("hellOwOrld! %d\n", i);
led_bar_set(i);
LED_RED = !(i & 1);
LED_YELLOW = !(i & 2);
LED_GREEN = !(i & 4);
BULB = !(i & 8);
i++;
delay(TICK_RATE);
}
}
/*****************************************
** Obsluha casovace 0 **
*****************************************/
void timer0(void) __interrupt(1) {
void timer0_handler(void) __interrupt(1) {
// Reload, 10ms
TL0=(uint8_t)NPER;
TH0=(uint8_t)(NPER >> 8);
if(TIMER!=0) TIMER--;
TL0 = (uint8_t)NPER;
TH0 = (uint8_t)(NPER >> 8);
if(TIMER != 0) TIMER--;
}

View File

@@ -6,8 +6,8 @@ use argp::FromArgs;
#[argp(description = "tulflash - Flashing utility for the TUL Výukový Přípravek v1.1™")]
pub struct Args {
#[argp(option)]
#[argp(description = "Path to the serial port. Probably will be `/dev/ttyUSBx` on Linux, `/dev/tty.usbserial-xxx` on macOS or `COMx` on Windows.")]
pub port: OsString,
#[argp(description = "Path to the serial port if auto detection fails. Probably will be `/dev/ttyUSBx` on Linux, `/dev/tty.usbserial-xxx` on macOS or `COMx` on Windows.")]
pub port: Option<OsString>,
#[argp(switch)]
#[argp(description = "Try this if it does not work the first time.")]
@@ -22,7 +22,10 @@ pub struct Args {
pub enum ArgCommand {
Read(ArgRead),
Write(ArgWrite),
Erase(ArgErase)
Erase(ArgErase),
Monitor(ArgMonitor),
Run(ArgRun),
Example(ArgExample)
}
#[derive(FromArgs)]
@@ -54,6 +57,14 @@ pub struct ArgWrite {
#[argp(description = "Path to the source Intel HEX file.")]
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(description = "Command to run before writing the file. Handy for compiling the program and running it at the same time.")]
pub cmd: Option<OsString>,
#[argp(option, default = "0")]
#[argp(description = "Start address where to write from. Only for raw binaries, defaults to 0.")]
pub start: usize,
@@ -72,7 +83,11 @@ pub struct ArgWrite {
#[argp(switch)]
#[argp(description = "Write individual sections to Flash rather than performing a single write. Only applies to Intel HEX.")]
pub write_individual: bool
pub write_individual: bool,
#[argp(switch)]
#[argp(description = "Open a serial monitor right after flashing.")]
pub monitor: bool
}
#[derive(FromArgs)]
@@ -80,6 +95,29 @@ pub struct ArgWrite {
#[argp(subcommand, name = "erase")]
pub struct ArgErase {}
#[derive(FromArgs)]
#[argp(description = "Opens the serial monitor.")]
#[argp(subcommand, name = "monitor")]
pub struct ArgMonitor {}
#[derive(FromArgs)]
#[argp(description = "Handy shorthand for `write --cmd \"sdcc <srcpath>\" --monitor <hexpath>`.")]
#[argp(subcommand, name = "run")]
pub struct ArgRun {
#[argp(positional)]
#[argp(description = "Path to the source C file.")]
pub path: std::path::PathBuf
}
#[derive(FromArgs)]
#[argp(description = "Generates a \"stub\" C file for the TUL výukový přípravek™.")]
#[argp(subcommand, name = "example")]
pub struct ArgExample {
#[argp(positional)]
#[argp(description = "Path to the source C file to be generated.")]
pub path: Option<OsString>
}
pub fn parse() -> Args {
let args: Args = argp::parse_args_or_exit(argp::DEFAULT);
args

View File

@@ -1,5 +1,9 @@
use std::{io::{Cursor, Error, Write}, time::{Duration, SystemTime}};
use std::ffi::OsString;
use std::io::{Cursor, Error, Write};
use std::path::PathBuf;
use std::time::{Duration, SystemTime};
use crossterm::event::{KeyCode, KeyModifiers};
use pbr::ProgressBar;
mod args;
@@ -8,6 +12,9 @@ use args::*;
mod ihex;
use ihex::{IntelHexWriter, IntelHexReader, DataRecord};
mod monitor;
use monitor::Monitor;
mod target;
use target::{PhysicalTarget, Target};
@@ -42,7 +49,7 @@ pub fn read_chip_into(writer: &mut impl Write, target: &mut impl Target, start:
Ok(())
}
pub fn read_chip(args: ArgRead, target: &mut impl Target) -> Result<(), Error> {
fn read_chip(args: ArgRead, target: &mut PhysicalTarget) -> Result<(), Error> {
let mut file = std::fs::File::create(args.path)?;
match args.bin {
@@ -128,9 +135,9 @@ pub fn write_chip_chunk(data: &[u8], target: &mut impl Target, mut start: usize,
Ok(())
}
pub fn write_chip(args: ArgWrite, target: &mut impl Target) -> Result<(), Error> {
fn write_chip_data(args: &ArgWrite, target: &mut PhysicalTarget) -> Result<(), Error> {
if args.bin {
let mut file = std::fs::read(args.path)?;
let mut file = std::fs::read(&args.path)?;
let size = args.end - args.start + 1;
@@ -141,7 +148,7 @@ pub fn write_chip(args: ArgWrite, target: &mut impl Target) -> Result<(), Error>
return write_chip_chunk(&file, target, args.start, !args.skip_verify)
}
let hexreader = IntelHexReader::init(std::fs::File::open(args.path)?);
let hexreader = IntelHexReader::init(std::fs::File::open(&args.path)?);
if args.write_individual {
let mut last_addr = 0;
@@ -194,27 +201,152 @@ pub fn write_chip(args: ArgWrite, target: &mut impl Target) -> Result<(), Error>
write_chip_chunk(&buf[first_addr..=last_addr], target, first_addr, !args.skip_verify)
}
pub fn erase_chip(_args: ArgErase, target: &mut impl Target) -> Result<(), Error> {
fn write_chip(args: ArgWrite, target: &mut PhysicalTarget) -> Result<(), Error> {
loop {
if let Some(cmd) = args.cmd.as_ref() {
let cmd_path = &args.cmd_path;
let mut args = shlex::bytes::split(cmd.as_encoded_bytes())
.ok_or(Error::other("Error parsing commandline arguments"))?
.into_iter()
.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 {
Err(Error::other("No command provided"))?
};
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)
.output()?;
if !out.status.success() {
Err(Error::other(format!("Command failed with exit code {}:\n\n{}",
out.status.code().unwrap_or(1),
String::from_utf8_lossy(&out.stderr))))?
}
println!("Command `{}` successful.", cmd.to_string_lossy());
}
write_chip_data(&args, target)?;
if !args.monitor { break }
let mut mon = Monitor::new();
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()?;
}
Ok(())
}
fn erase_chip(_args: ArgErase, target: &mut PhysicalTarget) -> Result<(), Error> {
target.erase()?;
Ok(())
}
fn monitor_chip(_args: ArgMonitor, target: &mut PhysicalTarget) -> Result<(), Error> {
let _ = Monitor::new().run(target.port())?;
Ok(())
}
fn run_chip(args: ArgRun, target: &mut PhysicalTarget) -> Result<(), Error> {
let build_dir = args.path.parent().unwrap().join("tulflash");
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 {
path: output_file.into_os_string(),
cmd_path,
cmd,
start: 0,
end: 65535,
bin: false,
skip_verify: false,
write_individual: false,
monitor: true
}, 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() {
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 mut target = PhysicalTarget::init(args.port, if args.slow { 57600 } else { 312500 }).unwrap();
let port = args.port.or_else(|| {
for port in serial_enumerator::get_serial_list() {
if let Some(vendor) = port.vendor && vendor.as_str() == "TUL" {
return Some(port.name.into())
}
}
None
});
let Some(port) = port else {
println!("Could not find any compatible serial port. Please make sure that the target is connected.");
println!("If the issue persists, please specify the port manually with the `--port ...` argument.");
std::process::exit(1);
};
let mut target = PhysicalTarget::init(port, if args.slow { 57600 } else { 312500 }).unwrap();
let res = match args.command {
ArgCommand::Read(args) => read_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::Run(args) => run_chip(args, &mut target),
ArgCommand::Example(_) => unreachable!()
};
if let Err(err) = res {
println!("An error occured during the operation: {}", err);
std::process::exit(1);
}
let end = SystemTime::now();

112
src/monitor.rs Normal file
View File

@@ -0,0 +1,112 @@
use std::io::{Error, ErrorKind, Write};
use std::time::Duration;
use crossterm::event::{Event, KeyCode, KeyModifiers};
use serial2::SerialPort;
struct RawMode {}
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 {
hooks: Vec<(KeyCode, KeyModifiers, &'static str)>
}
impl Monitor {
pub fn new() -> Self {
let mut hooks = Vec::new();
hooks.push((KeyCode::Char('c'), KeyModifiers::CONTROL, "Exit monitor"));
hooks.push((KeyCode::Char('r'), KeyModifiers::CONTROL, "Reboot target"));
Self { hooks }
}
pub fn add_hook(&mut self, key: KeyCode, mods: KeyModifiers, desc: &'static str) -> usize {
let idx = self.hooks.len();
self.hooks.push((key, mods, desc));
idx
}
pub fn run(&mut self, port: &mut SerialPort) -> Result<usize, Error> {
port.set_dtr(true)?;
port.set_rts(true)?;
std::thread::sleep(Duration::from_millis(100));
port.set_dtr(false)?;
port.set_rts(false)?;
println!();
println!("Monitor controls:");
for (key, mods, desc) in &self.hooks {
let key = match (key, *mods) {
(KeyCode::Char(c), KeyModifiers::NONE) => format!("{}", c.to_uppercase()),
(KeyCode::Char(c), KeyModifiers::CONTROL) => format!("Ctrl+{}", c.to_uppercase()),
key => format!("{:?}", key)
};
println!(" {} - {}", key, desc);
}
println!();
let _raw = RawMode::init()?;
let mut stdout = std::io::stdout();
'main: loop {
let mut buf = [0u8; 1];
let res = port.read_exact(&mut buf);
if res.is_ok() {
if buf[0] == b'\n' {
stdout.write_all(b"\r")?;
}
stdout.write_all(&buf)?;
stdout.flush()?;
}
if let Err(err) = res && err.kind() != ErrorKind::TimedOut {
Err(err)?
}
if crossterm::event::poll(Duration::ZERO)? {
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")?;
port.set_dtr(true)?;
port.set_rts(true)?;
std::thread::sleep(Duration::from_millis(10));
port.set_dtr(false)?;
port.set_rts(false)?;
continue
}
for (idx, (hook_key, hook_mods, _)) in self.hooks.iter().enumerate() {
if hook_key == &key && hook_mods == &mods {
stdout.write_all(b"\r\n")?;
break 'main Ok(idx)
}
}
}
}
}
}

View File

@@ -22,14 +22,33 @@ impl PhysicalTarget {
port.set_read_timeout(Duration::from_millis(100))?;
port.set_dtr(false)?;
let mut new = Self { port };
new.resync_target()?;
let manufacturer = new.read_info(0x00, 0x00).unwrap();
let family = new.read_info(0x00, 0x01).unwrap();
let name = new.read_info(0x00, 0x02).unwrap();
let rev = new.read_info(0x00, 0x03).unwrap();
println!("Detected chip ID: {manufacturer:02X} {family:02X} {name:02X} {rev:02X} (whatever that means)");
Ok(new)
}
pub fn resync_target(&mut self) -> Result<(), Error> {
self.port.discard_buffers()?;
self.port.set_dtr(true)?;
self.port.set_rts(true)?;
std::thread::sleep(Duration::from_millis(10));
self.port.set_dtr(false)?;
std::thread::sleep(Duration::from_millis(100));
for i in (0..5).rev() {
port.write(b"U")?;
self.port.write(b"U")?;
let mut buf = [0u8; 1];
port.read(&mut buf)?;
self.port.read(&mut buf)?;
if buf[0] == b'U' { break }
@@ -38,17 +57,8 @@ impl PhysicalTarget {
}
}
let mut new = Self { port };
let manufacturer = new.read_info(0x00, 0x00).unwrap();
let family = new.read_info(0x00, 0x01).unwrap();
let name = new.read_info(0x00, 0x02).unwrap();
let rev = new.read_info(0x00, 0x03).unwrap();
println!("Detected chip ID: {manufacturer:02X} {family:02X} {name:02X} {rev:02X} (whatever the fuck that means)");
Ok(new)
}
Ok(())
}
pub fn read_info(&mut self, category: u8, idx: u8) -> Result<u8, Error> {
self.send_command(0x05, 0, &[category, idx])?;
@@ -126,6 +136,10 @@ impl PhysicalTarget {
Ok(())
}
pub fn port(&mut self) -> &mut SerialPort {
&mut self.port
}
}
impl Target for PhysicalTarget {
@@ -229,6 +243,10 @@ impl Target for PhysicalTarget {
impl Drop for PhysicalTarget {
fn drop(&mut self) {
let _ = self.port.set_dtr(true);
let _ = self.port.set_rts(true);
std::thread::sleep(Duration::from_millis(100));
let _ = self.port.set_dtr(false);
let _ = self.port.set_rts(false);
}
}