Compare commits
12 Commits
f6b63b2da9
...
4bf8f6a8e7
Author | SHA1 | Date | |
---|---|---|---|
4bf8f6a8e7 | |||
2ef84e6aa6 | |||
dd49c30ac9 | |||
1b9f1ea4c1 | |||
b6b79e7fcf | |||
ffd1aa4874 | |||
dcbdc9ff89 | |||
80dd1c1a70 | |||
1dbbaab197 | |||
d298db44d2 | |||
ebd24ae7b5 | |||
c803e6514f |
163
Cargo.lock
generated
163
Cargo.lock
generated
@@ -2,6 +2,27 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
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]]
|
[[package]]
|
||||||
name = "argp"
|
name = "argp"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -50,6 +71,12 @@ 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 = "defer-lite"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6a1ef0750c0fcdb9bd00e7829fcad58e9a0a2ab7078b57c39743b973f3878ce"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getopts"
|
name = "getopts"
|
||||||
version = "0.2.24"
|
version = "0.2.24"
|
||||||
@@ -65,12 +92,54 @@ version = "0.2.175"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libredox"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mach"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.5"
|
version = "2.7.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minimal-lexical"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
|
[[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 = "numtoa"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pbr"
|
name = "pbr"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
@@ -112,6 +181,21 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"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 = "redox_termios"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serial2"
|
name = "serial2"
|
||||||
version = "0.2.32"
|
version = "0.2.32"
|
||||||
@@ -123,6 +207,27 @@ dependencies = [
|
|||||||
"winapi",
|
"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]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.106"
|
version = "2.0.106"
|
||||||
@@ -134,6 +239,18 @@ 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"
|
||||||
@@ -141,6 +258,9 @@ dependencies = [
|
|||||||
"argp",
|
"argp",
|
||||||
"pbr",
|
"pbr",
|
||||||
"serial2",
|
"serial2",
|
||||||
|
"serial_enumerator",
|
||||||
|
"shlex",
|
||||||
|
"termion",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -182,3 +302,46 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
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",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.29.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3d027175d00b01e0cbeb97d6ab6ebe03b12330a35786cbaca5252b1c4bf5d9b"
|
||||||
|
|
||||||
|
[[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_msvc"
|
||||||
|
version = "0.29.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8602f6c418b67024be2996c512f5f995de3ba417f4c75af68401ab8756796ae4"
|
||||||
|
|
||||||
|
[[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_msvc"
|
||||||
|
version = "0.29.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "11d95421d9ed3672c280884da53201a5c46b7b2765ca6faf34b0d71cf34a3561"
|
||||||
|
@@ -7,3 +7,6 @@ edition = "2024"
|
|||||||
argp = "0.4.0"
|
argp = "0.4.0"
|
||||||
pbr = "1.1.1"
|
pbr = "1.1.1"
|
||||||
serial2 = "0.2.32"
|
serial2 = "0.2.32"
|
||||||
|
serial_enumerator = "0.2.12"
|
||||||
|
shlex = "1.3.0"
|
||||||
|
termion = "4.0.5"
|
||||||
|
17
README.md
17
README.md
@@ -12,17 +12,11 @@ cargo install --git https://git.zumepro.cz/michal.prochazka/tulflash
|
|||||||
## Flashing Intel HEX binaries
|
## Flashing Intel HEX binaries
|
||||||
|
|
||||||
```
|
```
|
||||||
# Linux
|
# All OSes, automatically detects all ports
|
||||||
tulflash --port /dev/ttyUSBx write <path-to-hex>
|
tulflash write <path-to-hex>
|
||||||
|
|
||||||
# macOS
|
|
||||||
tulflash --port /dev/tty.usbserial-xxx write <path-to-hex>
|
|
||||||
|
|
||||||
# Wokňous
|
|
||||||
tulflash --port COMx write <path-to-hex>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
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 `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).
|
||||||
|
|
||||||
@@ -31,7 +25,8 @@ The tool also allows reading and erasing the chip, figure that out on your own i
|
|||||||
You'll need to clone this repo (or just [download the file](example.c)) and install SDCC:
|
You'll need to clone this repo (or just [download the file](example.c)) and install SDCC:
|
||||||
|
|
||||||
```
|
```
|
||||||
sdcc example.c
|
tulflash run example.c
|
||||||
tulflash --port ... write example.ihx
|
|
||||||
|
# Same thing as `tulflash write --cmd "sdcc example.c" --monitor example.ihx`
|
||||||
```
|
```
|
||||||
|
|
||||||
|
452
example.c
452
example.c
@@ -3,362 +3,324 @@
|
|||||||
//*** ***
|
//*** ***
|
||||||
//*** K O P Y T O V1.1 ***
|
//*** K O P Y T O V1.1 ***
|
||||||
//*** ***
|
//*** ***
|
||||||
//*** vandalizoval Michal Procházka ***
|
//*** vandalized by Michal Procházka ***
|
||||||
//*** ***
|
//*** ***
|
||||||
//**********************************************************************
|
//**********************************************************************
|
||||||
//**********************************************************************
|
//**********************************************************************
|
||||||
|
|
||||||
#include <8051.h>
|
#include <at89c55.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define TickPerSec 100
|
#define TICK_RATE 100
|
||||||
#define NPER (0x10000-(20000000L/12/TickPerSec))
|
#define NPER (0x10000 - (20000000 / 12 / TICK_RATE))
|
||||||
|
|
||||||
// Definice vstupu a vystupu
|
// Missing port definitions
|
||||||
#define _P0 0x80
|
__sbit __at (0xC4) P4_4;
|
||||||
#define _P1 0x90
|
__sbit __at (0xC3) P4_3;
|
||||||
#define _P2 0xa0
|
__sbit __at (0xC2) P4_2;
|
||||||
#define _P3 0xb0
|
__sbit __at (0xC1) P4_1;
|
||||||
#define _P4 0xc0
|
__sbit __at (0xC0) P4_0;
|
||||||
|
|
||||||
#define Tlac1 P3_2
|
// I/O definitions
|
||||||
#define Tlac2 P3_3
|
#define BUTTON_1 P3_2
|
||||||
#define Buzzer P3_6
|
#define BUTTON_2 P3_3
|
||||||
#define LED1 P4_2
|
#define PIEZO P3_6
|
||||||
#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 POT P1_0
|
||||||
#define SMT P1_1
|
#define THERM P1_1
|
||||||
#define ZAR P1_2
|
#define BULB 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
|
|
||||||
|
|
||||||
// TIMER se odecita v casovem preruseni
|
#define BAR_DAT P1_3
|
||||||
volatile uint16_t TIMER;
|
#define BAR_SCK P1_4
|
||||||
uint8_t LCD_Pos;
|
#define BAR_SCL P1_5
|
||||||
|
#define BAR_RCK P1_6
|
||||||
/*************************************************************************\
|
#define BAR_OE P1_7
|
||||||
* 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 LCD_RS_PIN P2_4
|
#define LCD_RS_PIN P2_4
|
||||||
#define LCD_RW_PIN P2_5
|
#define LCD_RW_PIN P2_5
|
||||||
#define LCD_EN_PIN P2_6
|
#define LCD_EN_PIN P2_6
|
||||||
|
|
||||||
#define LCD_RS 0x10 /* rgister select */
|
#define KEY_COL_1 P0_0
|
||||||
#define LCD_RW 0x20 /* read/write */
|
#define KEY_COL_2 P0_1
|
||||||
#define LCD_EN 0x40 /* chip enable */
|
#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
|
// Timer-based delay, waits for pause * 10 ms
|
||||||
#define cmd_lcd_home 0x02
|
void delay(int pause) {
|
||||||
|
|
||||||
#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 = 1 + pause;
|
TIMER = 1 + pause;
|
||||||
while(TIMER);
|
while(TIMER);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LCD_Pause(void) {
|
uint8_t lcd_pos;
|
||||||
// Hnus, ale funguje to
|
|
||||||
|
#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) {
|
||||||
int i = 30;
|
int i = 30;
|
||||||
while(i--);
|
while(i--);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t LCD_State(void) {
|
// Reads the status register from the LCD.
|
||||||
|
uint8_t lcd_read_status(void) {
|
||||||
uint8_t temp;
|
uint8_t temp;
|
||||||
|
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
P2 = LCD_RW | 0x0F;
|
P2 = LCD_RW | 0x0F;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
LCD_EN_PIN = 1;
|
LCD_EN_PIN = 1;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
temp = (P2 & 0x0F) << 4;
|
temp = (P2 & 0x0F) << 4;
|
||||||
LCD_EN_PIN = 0;
|
LCD_EN_PIN = 0;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
LCD_EN_PIN = 1;
|
LCD_EN_PIN = 1;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
temp = temp + (P2 & 0x0F);
|
temp = temp + (P2 & 0x0F);
|
||||||
LCD_EN_PIN = 0;
|
LCD_EN_PIN = 0;
|
||||||
|
|
||||||
return temp;
|
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;
|
P2 = (val >> 4) & 0x0F;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
LCD_EN_PIN = 1;
|
LCD_EN_PIN = 1;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
LCD_EN_PIN = 0;
|
LCD_EN_PIN = 0;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
P2 = (val & 0x0F);
|
P2 = (val & 0x0F);
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
LCD_EN_PIN = 1;
|
LCD_EN_PIN = 1;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
LCD_EN_PIN = 0;
|
LCD_EN_PIN = 0;
|
||||||
|
|
||||||
while(LCD_State() & 0x80);
|
while(lcd_read_status() & 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LCD_SendData(uint8_t val) {
|
// Writes a data value to the LCD.
|
||||||
LCD_Pause();
|
void lcd_send_data(uint8_t val) {
|
||||||
|
lcd_pause();
|
||||||
P2 = LCD_RS | ((val >> 4) & 0x0F);
|
P2 = LCD_RS | ((val >> 4) & 0x0F);
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
LCD_EN_PIN = 1;
|
LCD_EN_PIN = 1;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
LCD_EN_PIN = 0;
|
LCD_EN_PIN = 0;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
P2 = LCD_RS | (val & 0x0F);
|
P2 = LCD_RS | (val & 0x0F);
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
LCD_EN_PIN = 1;
|
LCD_EN_PIN = 1;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
LCD_EN_PIN = 0;
|
LCD_EN_PIN = 0;
|
||||||
|
|
||||||
while(LCD_State() & 0x80);
|
while(lcd_read_status() & 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LCD_Clear(void) {
|
// Clears the LCD.
|
||||||
LCD_SendCmd(0x01); /* display clear */
|
void lcd_clear(void) {
|
||||||
LCD_Pos=0;
|
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 */
|
P2 = 0; /* set RS, RW and EN low */
|
||||||
/* all delays are vital */
|
/* 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++) {
|
for(uint8_t i = 0; i < 3; i++) {
|
||||||
P2 = 0x03; /* lce enable low */
|
P2 = 0x03; /* lce enable low */
|
||||||
Delay(1); /* wait more than 100us */
|
delay(1); /* wait more than 100us */
|
||||||
P2 = LCD_EN | 0x03; /* lcd enable high */
|
P2 = LCD_EN | 0x03; /* lcd enable high */
|
||||||
Delay(1); /* wait more than 100us */
|
delay(1); /* wait more than 100us */
|
||||||
P2 = 0x03; /* lce enable low */
|
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 */
|
P2 = 0x02; /* lcd enable low */
|
||||||
Delay(1); /* wait more than 100us */
|
delay(1); /* wait more than 100us */
|
||||||
P2 = LCD_EN | 0x02; /* lcd enable high */
|
P2 = LCD_EN | 0x02; /* lcd enable high */
|
||||||
Delay(1); /* wait more than 100us */
|
delay(1); /* wait more than 100us */
|
||||||
P2 = 0x02; /* lcd enable low */
|
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_send_cmd(0x28); /* 4 bit mode, 1/16 duty, 5x8 font */
|
||||||
LCD_SendCmd(0x08); /* display off */
|
lcd_send_cmd(0x08); /* display off */
|
||||||
LCD_Clear();
|
lcd_clear();
|
||||||
LCD_SendCmd(0x06); /* entry mode */
|
lcd_send_cmd(0x06); /* entry mode */
|
||||||
LCD_SendCmd(0x0C); /* display on, blinking cursor off */
|
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) {
|
if(c == 10) {
|
||||||
while((LCD_Pos != 0) && (LCD_Pos != 40)) {
|
while((lcd_pos != 0) && (lcd_pos != 40)) {
|
||||||
LCD_SendData(32);
|
lcd_send_data(32);
|
||||||
LCD_Pos++;
|
lcd_pos++;
|
||||||
if(LCD_Pos == 80) LCD_Pos=0;
|
if(lcd_pos == 80) lcd_pos=0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LCD_SendData(c);
|
lcd_send_data(c);
|
||||||
LCD_Pos++;
|
lcd_pos++;
|
||||||
if(LCD_Pos == 80) LCD_Pos=0;
|
if(lcd_pos == 80) lcd_pos=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializes the background tick timer (for delays).
|
||||||
|
void timer_init(void) {
|
||||||
|
// 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
|
||||||
|
|
||||||
|
IE = 0x82;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 = 0xFE;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
__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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************
|
// Writes a 10-bit value to the LED bar. Bit 0 = bottom LED, bit 9 = top LED.
|
||||||
** Nastaveni preruseni **
|
void led_bar_set(uint16_t n) {
|
||||||
*****************************************/
|
|
||||||
|
|
||||||
/* 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) {
|
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
LB_RCK = 0;
|
BAR_RCK = 0;
|
||||||
LB_SCL = 0;
|
BAR_SCL = 0;
|
||||||
LB_SCL = 1;
|
BAR_SCL = 1;
|
||||||
LB_SCK = 0;
|
BAR_SCK = 0;
|
||||||
|
|
||||||
for(i = 0; i < 10; i++) {
|
for(i = 0; i < 10; i++) {
|
||||||
LB_Data = !(n & 1);
|
BAR_DAT = !(n & 1);
|
||||||
n >>= 1; // n = n >> 1
|
n >>= 1; // n = n >> 1
|
||||||
LB_SCK = 1;
|
BAR_SCK = 1;
|
||||||
LB_SCK = 0;
|
BAR_SCK = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LB_RCK = 1;
|
BAR_RCK = 1;
|
||||||
LB_OE = 0;
|
BAR_OE = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************
|
// Reads a character from the keypad.
|
||||||
** Obsluha Klavesnice **
|
char keypad_read(void) {
|
||||||
*****************************************/
|
|
||||||
|
|
||||||
#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) {
|
|
||||||
P0 = 0xFF;
|
P0 = 0xFF;
|
||||||
KEY_R_1 = 0;
|
KEY_ROW_1 = 0;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
if (!KEY_C_1) return '1';
|
if (!KEY_COL_1) return '1';
|
||||||
if (!KEY_C_2) return '2';
|
if (!KEY_COL_2) return '2';
|
||||||
if (!KEY_C_3) return '3';
|
if (!KEY_COL_3) return '3';
|
||||||
if (!KEY_C_4) return 'A';
|
if (!KEY_COL_4) return 'A';
|
||||||
|
|
||||||
P0 = 0xFF;
|
P0 = 0xFF;
|
||||||
KEY_R_2 = 0;
|
KEY_ROW_2 = 0;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
if (!KEY_C_1) return '4';
|
if (!KEY_COL_1) return '4';
|
||||||
if (!KEY_C_2) return '5';
|
if (!KEY_COL_2) return '5';
|
||||||
if (!KEY_C_3) return '6';
|
if (!KEY_COL_3) return '6';
|
||||||
if (!KEY_C_4) return 'B';
|
if (!KEY_COL_4) return 'B';
|
||||||
|
|
||||||
P0 = 0xFF;
|
P0 = 0xFF;
|
||||||
KEY_R_3 = 0;
|
KEY_ROW_3 = 0;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
if (!KEY_C_1) return '7';
|
if (!KEY_COL_1) return '7';
|
||||||
if (!KEY_C_2) return '8';
|
if (!KEY_COL_2) return '8';
|
||||||
if (!KEY_C_3) return '9';
|
if (!KEY_COL_3) return '9';
|
||||||
if (!KEY_C_4) return 'C';
|
if (!KEY_COL_4) return 'C';
|
||||||
|
|
||||||
P0 = 0xFF;
|
P0 = 0xFF;
|
||||||
KEY_R_4 = 0;
|
KEY_ROW_4 = 0;
|
||||||
LCD_Pause();
|
lcd_pause();
|
||||||
if (!KEY_C_1) return '*';
|
if (!KEY_COL_1) return '*';
|
||||||
if (!KEY_C_2) return '0';
|
if (!KEY_COL_2) return '0';
|
||||||
if (!KEY_C_3) return '#';
|
if (!KEY_COL_3) return '#';
|
||||||
if (!KEY_C_4) return 'D';
|
if (!KEY_COL_4) return 'D';
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************
|
|
||||||
** Hlavni program **
|
|
||||||
*****************************************/
|
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
init_interrupts();
|
timer_init();
|
||||||
LCD_Init();
|
lcd_init();
|
||||||
|
serial_init();
|
||||||
|
|
||||||
int i = 0;
|
stdout_to_serial = 1;
|
||||||
|
stdout_to_lcd = 1;
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
LCD_Clear();
|
lcd_clear();
|
||||||
printf("hellOwOrld! %d", ++i);
|
printf("hellOwOrld! %d\n", i);
|
||||||
Delay(TickPerSec);
|
led_bar_set(i);
|
||||||
|
|
||||||
|
LED_RED = !(i & 1);
|
||||||
|
LED_YELLOW = !(i & 2);
|
||||||
|
LED_GREEN = !(i & 4);
|
||||||
|
BULB = !(i & 8);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
|
||||||
|
delay(TICK_RATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************
|
void timer0_handler(void) __interrupt(1) {
|
||||||
** Obsluha casovace 0 **
|
|
||||||
*****************************************/
|
|
||||||
|
|
||||||
|
|
||||||
void timer0(void) __interrupt(1) {
|
|
||||||
// Reload, 10ms
|
// Reload, 10ms
|
||||||
TL0=(uint8_t)NPER;
|
TL0 = (uint8_t)NPER;
|
||||||
TH0=(uint8_t)(NPER >> 8);
|
TH0 = (uint8_t)(NPER >> 8);
|
||||||
if(TIMER!=0) TIMER--;
|
if(TIMER != 0) TIMER--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
32
src/args.rs
32
src/args.rs
@@ -6,8 +6,8 @@ use argp::FromArgs;
|
|||||||
#[argp(description = "tulflash - Flashing utility for the TUL Výukový Přípravek v1.1™")]
|
#[argp(description = "tulflash - Flashing utility for the TUL Výukový Přípravek v1.1™")]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
#[argp(option)]
|
#[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.")]
|
#[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: OsString,
|
pub port: Option<OsString>,
|
||||||
|
|
||||||
#[argp(switch)]
|
#[argp(switch)]
|
||||||
#[argp(description = "Try this if it does not work the first time.")]
|
#[argp(description = "Try this if it does not work the first time.")]
|
||||||
@@ -22,7 +22,9 @@ pub struct Args {
|
|||||||
pub enum ArgCommand {
|
pub enum ArgCommand {
|
||||||
Read(ArgRead),
|
Read(ArgRead),
|
||||||
Write(ArgWrite),
|
Write(ArgWrite),
|
||||||
Erase(ArgErase)
|
Erase(ArgErase),
|
||||||
|
Monitor(ArgMonitor),
|
||||||
|
Run(ArgRun)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromArgs)]
|
#[derive(FromArgs)]
|
||||||
@@ -54,6 +56,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 = "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(option, default = "0")]
|
||||||
#[argp(description = "Start address where to write from. Only for raw binaries, defaults to 0.")]
|
#[argp(description = "Start address where to write from. Only for raw binaries, defaults to 0.")]
|
||||||
pub start: usize,
|
pub start: usize,
|
||||||
@@ -72,7 +78,11 @@ pub struct ArgWrite {
|
|||||||
|
|
||||||
#[argp(switch)]
|
#[argp(switch)]
|
||||||
#[argp(description = "Write individual sections to Flash rather than performing a single write. Only applies to Intel HEX.")]
|
#[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)]
|
#[derive(FromArgs)]
|
||||||
@@ -80,6 +90,20 @@ pub struct ArgWrite {
|
|||||||
#[argp(subcommand, name = "erase")]
|
#[argp(subcommand, name = "erase")]
|
||||||
pub struct ArgErase {}
|
pub struct ArgErase {}
|
||||||
|
|
||||||
|
#[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: OsString
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromArgs)]
|
||||||
|
#[argp(description = "Opens the serial monitor.")]
|
||||||
|
#[argp(subcommand, name = "monitor")]
|
||||||
|
pub struct ArgMonitor {}
|
||||||
|
|
||||||
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);
|
||||||
args
|
args
|
||||||
|
105
src/main.rs
105
src/main.rs
@@ -1,4 +1,7 @@
|
|||||||
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 pbr::ProgressBar;
|
use pbr::ProgressBar;
|
||||||
|
|
||||||
@@ -8,8 +11,12 @@ use args::*;
|
|||||||
mod ihex;
|
mod ihex;
|
||||||
use ihex::{IntelHexWriter, IntelHexReader, DataRecord};
|
use ihex::{IntelHexWriter, IntelHexReader, DataRecord};
|
||||||
|
|
||||||
|
mod monitor;
|
||||||
|
use monitor::Monitor;
|
||||||
|
|
||||||
mod target;
|
mod target;
|
||||||
use target::{PhysicalTarget, Target};
|
use target::{PhysicalTarget, Target};
|
||||||
|
use termion::event::Key;
|
||||||
|
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
@@ -42,7 +49,7 @@ pub fn read_chip_into(writer: &mut impl Write, target: &mut impl Target, start:
|
|||||||
Ok(())
|
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)?;
|
let mut file = std::fs::File::create(args.path)?;
|
||||||
|
|
||||||
match args.bin {
|
match args.bin {
|
||||||
@@ -128,9 +135,9 @@ pub fn write_chip_chunk(data: &[u8], target: &mut impl Target, mut start: usize,
|
|||||||
Ok(())
|
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 {
|
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;
|
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)
|
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 {
|
if args.write_individual {
|
||||||
let mut last_addr = 0;
|
let mut last_addr = 0;
|
||||||
@@ -194,27 +201,109 @@ 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)
|
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 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) });
|
||||||
|
|
||||||
|
let Some(name) = args.next() else {
|
||||||
|
Err(Error::other("No command provided"))?
|
||||||
|
};
|
||||||
|
|
||||||
|
let out = std::process::Command::new(name)
|
||||||
|
.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 cause = 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 }
|
||||||
|
|
||||||
|
target.resync_target()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn erase_chip(_args: ArgErase, target: &mut PhysicalTarget) -> Result<(), Error> {
|
||||||
target.erase()?;
|
target.erase()?;
|
||||||
|
|
||||||
Ok(())
|
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 path = PathBuf::from(&args.path).with_extension("ihx").into_os_string();
|
||||||
|
let cmd = Some(OsString::from(format!("sdcc \"{}\"", unsafe { String::from_utf8_unchecked(args.path.into_encoded_bytes()) })));
|
||||||
|
|
||||||
|
write_chip(ArgWrite {
|
||||||
|
path,
|
||||||
|
cmd,
|
||||||
|
start: 0,
|
||||||
|
end: 65535,
|
||||||
|
bin: false,
|
||||||
|
skip_verify: false,
|
||||||
|
write_individual: false,
|
||||||
|
monitor: true
|
||||||
|
}, target)
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = args::parse();
|
let args = args::parse();
|
||||||
|
|
||||||
let start = SystemTime::now();
|
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 {
|
let res = match args.command {
|
||||||
ArgCommand::Read(args) => read_chip(args, &mut target),
|
ArgCommand::Read(args) => read_chip(args, &mut target),
|
||||||
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::Run(args) => run_chip(args, &mut target)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(err) = res {
|
if let Err(err) = res {
|
||||||
println!("An error occured during the operation: {}", err);
|
println!("An error occured during the operation: {}", err);
|
||||||
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let end = SystemTime::now();
|
let end = SystemTime::now();
|
||||||
|
94
src/monitor.rs
Normal file
94
src/monitor.rs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
use std::io::{Error, ErrorKind, Write};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use serial2::SerialPort;
|
||||||
|
|
||||||
|
use termion::raw::IntoRawMode;
|
||||||
|
use termion::event::Key;
|
||||||
|
use termion::input::TermRead;
|
||||||
|
|
||||||
|
pub struct Monitor {
|
||||||
|
hooks: Vec<(Key, &'static str)>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Monitor {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut hooks = Vec::new();
|
||||||
|
|
||||||
|
hooks.push((Key::Ctrl('c'), "Exit monitor"));
|
||||||
|
hooks.push((Key::Ctrl('r'), "Reboot target"));
|
||||||
|
|
||||||
|
Self { hooks }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_hook(&mut self, key: Key, desc: &'static str) -> &mut Self {
|
||||||
|
self.hooks.push((key, desc));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self, port: &mut SerialPort) -> Result<Key, 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, desc) in &self.hooks {
|
||||||
|
let key = match key {
|
||||||
|
Key::Char(c) => format!("{}", c.to_uppercase()),
|
||||||
|
Key::Ctrl(c) => format!("Ctrl+{}", c.to_uppercase()),
|
||||||
|
key => format!("{:?}", key)
|
||||||
|
};
|
||||||
|
|
||||||
|
println!(" {} - {}", key, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!();
|
||||||
|
|
||||||
|
let mut stdout = std::io::stdout().into_raw_mode().unwrap();
|
||||||
|
|
||||||
|
let mut stdin = termion::async_stdin().keys();
|
||||||
|
|
||||||
|
'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 let Some(Ok(key)) = stdin.next() {
|
||||||
|
if let Key::Ctrl('r') = key {
|
||||||
|
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 (hook_key, _) in &self.hooks {
|
||||||
|
if hook_key == &key {
|
||||||
|
stdout.write_all(b"\r\n")?;
|
||||||
|
break 'main Ok(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -22,24 +22,10 @@ impl PhysicalTarget {
|
|||||||
|
|
||||||
port.set_read_timeout(Duration::from_millis(100))?;
|
port.set_read_timeout(Duration::from_millis(100))?;
|
||||||
|
|
||||||
port.set_dtr(false)?;
|
|
||||||
std::thread::sleep(Duration::from_millis(100));
|
|
||||||
|
|
||||||
for i in (0..5).rev() {
|
|
||||||
port.write(b"U")?;
|
|
||||||
|
|
||||||
let mut buf = [0u8; 1];
|
|
||||||
port.read(&mut buf)?;
|
|
||||||
|
|
||||||
if buf[0] == b'U' { break }
|
|
||||||
|
|
||||||
if i == 0 {
|
|
||||||
Err(Error::other(format!("Invalid sync response: 0x{:02X}", buf[0])))?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut new = Self { port };
|
let mut new = Self { port };
|
||||||
|
|
||||||
|
new.resync_target()?;
|
||||||
|
|
||||||
let manufacturer = new.read_info(0x00, 0x00).unwrap();
|
let manufacturer = new.read_info(0x00, 0x00).unwrap();
|
||||||
let family = new.read_info(0x00, 0x01).unwrap();
|
let family = new.read_info(0x00, 0x01).unwrap();
|
||||||
let name = new.read_info(0x00, 0x02).unwrap();
|
let name = new.read_info(0x00, 0x02).unwrap();
|
||||||
@@ -50,6 +36,30 @@ impl PhysicalTarget {
|
|||||||
Ok(new)
|
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() {
|
||||||
|
self.port.write(b"U")?;
|
||||||
|
|
||||||
|
let mut buf = [0u8; 1];
|
||||||
|
self.port.read(&mut buf)?;
|
||||||
|
|
||||||
|
if buf[0] == b'U' { break }
|
||||||
|
|
||||||
|
if i == 0 {
|
||||||
|
Err(Error::other(format!("Invalid sync response: 0x{:02X}", buf[0])))?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_info(&mut self, category: u8, idx: u8) -> Result<u8, Error> {
|
pub fn read_info(&mut self, category: u8, idx: u8) -> Result<u8, Error> {
|
||||||
self.send_command(0x05, 0, &[category, idx])?;
|
self.send_command(0x05, 0, &[category, idx])?;
|
||||||
|
|
||||||
@@ -126,6 +136,10 @@ impl PhysicalTarget {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn port(&mut self) -> &mut SerialPort {
|
||||||
|
&mut self.port
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Target for PhysicalTarget {
|
impl Target for PhysicalTarget {
|
||||||
@@ -229,6 +243,10 @@ impl Target for PhysicalTarget {
|
|||||||
impl Drop for PhysicalTarget {
|
impl Drop for PhysicalTarget {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let _ = self.port.set_dtr(true);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user