Compare commits
1 Commits
stc8
...
no_verific
Author | SHA1 | Date | |
---|---|---|---|
05d0ff0576 |
7
.gitignore
vendored
7
.gitignore
vendored
@ -1,12 +1,7 @@
|
|||||||
*~
|
*~
|
||||||
*.pyc
|
*.pyc
|
||||||
*.egg-info
|
*.egg-info
|
||||||
*.eggs/
|
__pycache__
|
||||||
*.pybuild/
|
|
||||||
__pycache__/
|
|
||||||
/build
|
/build
|
||||||
/dist
|
/dist
|
||||||
/deb_dist
|
/deb_dist
|
||||||
/debian/stcgal*
|
|
||||||
/debian/files
|
|
||||||
/.vscode
|
|
33
.travis.yml
33
.travis.yml
@ -1,33 +0,0 @@
|
|||||||
sudo: required
|
|
||||||
dist: trusty
|
|
||||||
language: python
|
|
||||||
cache:
|
|
||||||
- pip
|
|
||||||
python:
|
|
||||||
- "3.4"
|
|
||||||
- "3.5"
|
|
||||||
- "3.6"
|
|
||||||
- "pypy3"
|
|
||||||
before_install:
|
|
||||||
- sudo apt install rpm dpkg-dev debhelper dh-python python3-setuptools fakeroot python3-serial python3-yaml
|
|
||||||
install:
|
|
||||||
- pip install pyserial pyusb tqdm
|
|
||||||
script:
|
|
||||||
- python setup.py build
|
|
||||||
- python setup.py test
|
|
||||||
before_deploy:
|
|
||||||
- deactivate
|
|
||||||
- python3 setup.py bdist_rpm
|
|
||||||
- dpkg-buildpackage -uc -us
|
|
||||||
- cp ../*.deb dist/
|
|
||||||
deploy:
|
|
||||||
provider: releases
|
|
||||||
api_key: $GH_TOKEN
|
|
||||||
file_glob: true
|
|
||||||
file:
|
|
||||||
- dist/stcgal*_all.deb
|
|
||||||
- dist/stcgal*.noarch.rpm
|
|
||||||
skip_cleanup: true
|
|
||||||
on:
|
|
||||||
tags: true
|
|
||||||
python: "3.4"
|
|
45
README.md
45
README.md
@ -1,5 +1,3 @@
|
|||||||
[](https://travis-ci.org/grigorig/stcgal)
|
|
||||||
|
|
||||||
stcgal - STC MCU ISP flash tool
|
stcgal - STC MCU ISP flash tool
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
@ -23,18 +21,18 @@ suitable for automation.
|
|||||||
Supported MCU models
|
Supported MCU models
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
stcgal should fully support STC 89/90/10/11/12/15 series MCUs. Support for STC8 series MCUs is work in progress.
|
stcgal should fully support STC 89/90/10/11/12/15 series MCUs.
|
||||||
|
|
||||||
So far, stcgal was tested with the following MCU models:
|
So far, stcgal was tested with the following MCU models:
|
||||||
|
|
||||||
* STC89C52RC (BSL version: 4.3C/6.6C)
|
* STC89C52RC (BSL version: 4.3C)
|
||||||
* STC90C52RC (BSL version: 4.3C)
|
* STC90C52RC (BSL version: 4.3C)
|
||||||
* STC89C54RD+ (BSL version: 4.3C)
|
* STC89C54RD+ (BSL version: 4.3C)
|
||||||
* STC12C2052 (BSL version: 5.8D)
|
* STC12C2052 (BSL version: 5.8D)
|
||||||
* STC12C2052AD (BSL version: 5.8D)
|
* STC12C2052AD (BSL version: 5.8D)
|
||||||
* STC12C5608AD (BSL version: 6.0G)
|
* STC12C5608AD (BSL version: 6.0G)
|
||||||
* STC12C5A16S2 (BSL version: 6.2I)
|
* STC12C5A16S2 (BSL version: 6.2I)
|
||||||
* STC12C5A60S2 (BSL version: 6.2I/7.1I)
|
* STC12C5A60S2 (BSL version: 6.2I)
|
||||||
* STC11F02E (BSL version: 6.5K)
|
* STC11F02E (BSL version: 6.5K)
|
||||||
* STC10F04XE (BSL version: 6.5J)
|
* STC10F04XE (BSL version: 6.5J)
|
||||||
* STC11F08XE (BSL version: 6.5M)
|
* STC11F08XE (BSL version: 6.5M)
|
||||||
@ -47,7 +45,6 @@ So far, stcgal was tested with the following MCU models:
|
|||||||
* STC15L2K16S2 (BSL version: 7.2.4S)
|
* STC15L2K16S2 (BSL version: 7.2.4S)
|
||||||
* STC15W408AS (BSL version: 7.2.4T)
|
* STC15W408AS (BSL version: 7.2.4T)
|
||||||
* STC15W4K56S4 (BSL version: 7.3.4T, UART and USB mode)
|
* STC15W4K56S4 (BSL version: 7.3.4T, UART and USB mode)
|
||||||
* STC8A8K64S4A12 (BSL version: 7.3.9U)
|
|
||||||
|
|
||||||
Compatibility reports, both negative and positive, are welcome.
|
Compatibility reports, both negative and positive, are welcome.
|
||||||
|
|
||||||
@ -60,9 +57,9 @@ Features
|
|||||||
* Program flash memory
|
* Program flash memory
|
||||||
* Program IAP/EEPROM
|
* Program IAP/EEPROM
|
||||||
* Set device options
|
* Set device options
|
||||||
* Read unique device ID (STC 10/11/12/15/8)
|
* Read unique device ID (STC 10/11/12/15)
|
||||||
* Trim RC oscillator frequency (STC 15/8)
|
* Trim RC oscillator frequency (STC 15)
|
||||||
* Automatic power-cycling with DTR toggle or a custom shell command
|
* Automatic power-cycling with DTR toggle
|
||||||
* Automatic UART protocol detection
|
* Automatic UART protocol detection
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
@ -97,9 +94,6 @@ positional arguments:
|
|||||||
optional arguments:
|
optional arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
-a, --autoreset cycle power automatically by asserting DTR
|
-a, --autoreset cycle power automatically by asserting DTR
|
||||||
-r RESETCMD, --resetcmd RESETCMD
|
|
||||||
Use this shell command for board power-cycling
|
|
||||||
(instead of DTR assertion)
|
|
||||||
-P {stc89,stc12a,stc12,stc15a,stc15,auto}, --protocol {stc89,stc12a,stc12,stc15a,stc15,auto}
|
-P {stc89,stc12a,stc12,stc15a,stc15,auto}, --protocol {stc89,stc12a,stc12,stc15a,stc15,auto}
|
||||||
protocol version
|
protocol version
|
||||||
-p PORT, --port PORT serial port device
|
-p PORT, --port PORT serial port device
|
||||||
@ -127,7 +121,6 @@ and MCU series is as follows:
|
|||||||
* ```stc12``` Most STC10/11/12 series
|
* ```stc12``` Most STC10/11/12 series
|
||||||
* ```stc15a``` STC15x104E and STC15x204E(A) series
|
* ```stc15a``` STC15x104E and STC15x204E(A) series
|
||||||
* ```stc15``` Most STC15 series
|
* ```stc15``` Most STC15 series
|
||||||
* ```stc8``` STC8 series
|
|
||||||
* ```usb15``` USB support on STC15W4 series
|
* ```usb15``` USB support on STC15W4 series
|
||||||
* ```auto``` Automatic detection of UART based protocols (default)
|
* ```auto``` Automatic detection of UART based protocols (default)
|
||||||
|
|
||||||
@ -259,20 +252,17 @@ Option key | Possible values | Protocols/Models | Descri
|
|||||||
```por_reset_delay``` | short/long | STC12+ | Power-on reset (POR) delay
|
```por_reset_delay``` | short/long | STC12+ | Power-on reset (POR) delay
|
||||||
```low_voltage_threshold``` | 0...7 | STC15A+ | Low-voltage detection threshold. Model specific.
|
```low_voltage_threshold``` | 0...7 | STC15A+ | Low-voltage detection threshold. Model specific.
|
||||||
```eeprom_lvd_inhibit``` | true/false | STC15A+ | Ignore EEPROM writes in low-voltage situations
|
```eeprom_lvd_inhibit``` | true/false | STC15A+ | Ignore EEPROM writes in low-voltage situations
|
||||||
```rstout_por_state``` | low/high | STC15+ | RSTOUT/RSTSV pin state after power-on reset
|
```rstout_por_state``` | low/high | STC15+ | RSTOUT pin state after power-on reset
|
||||||
```uart1_remap``` | true/false | STC8 | Remap UART1 pins (P3.0/P3.1) to UART2 pins (P3.6/P3.7)
|
|
||||||
```uart2_passthrough``` | true/false | STC15+ | Pass-through UART1 to UART2 pins (for single-wire UART mode)
|
```uart2_passthrough``` | true/false | STC15+ | Pass-through UART1 to UART2 pins (for single-wire UART mode)
|
||||||
```uart2_pin_mode``` | push-pull/normal | STC15+ | Output mode of UART2 TX pin
|
```uart2_pin_mode``` | push-pull/normal | STC15+ | Output mode of UART2 TX pin
|
||||||
```cpu_core_voltage``` | low/mid/high | STC15W+ | CPU core voltage (low: ~2.7V, mid: ~3.3V, high: ~3.6V)
|
```cpu_core_voltage``` | low/mid/high | STC15W+ | CPU core voltage (low: ~2.7V, mid: ~3.3V, high: ~3.6V)
|
||||||
```epwm_open_drain``` | true/false | STC8 | Use open-drain pin mode for EPWM pins after power-on reset
|
|
||||||
```program_eeprom_split``` | 512 - 65024 | STC8A8 w/ 64 KB | Select split between code flash and EEPROM flash (in 512 byte blocks)
|
|
||||||
|
|
||||||
### Frequency trimming
|
### Frequency trimming
|
||||||
|
|
||||||
If the internal RC oscillator is used (```clock_source=internal```),
|
If the internal RC oscillator is used (```clock_source=internal```),
|
||||||
stcgal can execute a trim procedure to adjust it to a given value. This
|
stcgal can execute a trim procedure to adjust it to a given value. This
|
||||||
is only supported by STC15 series and newer. The trim values are stored
|
is only supported by STC15 series. The trim values are stored with
|
||||||
with device options. Use the ```-t``` flag to request trimming to a certain
|
device options. Use the ```-t``` flag to request trimming to a certain
|
||||||
value. Generally, frequencies between 4 and 35 MHz can be achieved. If
|
value. Generally, frequencies between 4 and 35 MHz can be achieved. If
|
||||||
trimming fails, stcgal will abort.
|
trimming fails, stcgal will abort.
|
||||||
|
|
||||||
@ -284,22 +274,7 @@ serial interface to automate this. The DTR signal is asserted for
|
|||||||
approximately 500 ms when the autoreset feature is enabled with the
|
approximately 500 ms when the autoreset feature is enabled with the
|
||||||
```-a``` flag. This requires external circuitry to actually switch the
|
```-a``` flag. This requires external circuitry to actually switch the
|
||||||
power. In some cases, when the microcontroller draws only little power,
|
power. In some cases, when the microcontroller draws only little power,
|
||||||
it is possible to directly supply power from the DTR signal.
|
it is possible to directly supply power from the DTR signal, however.
|
||||||
|
|
||||||
As an alternative to DTR, you can use a custom shell command or an external
|
|
||||||
script (via -r option) to reset the device. You should specify the command
|
|
||||||
along with -a option. Do not forget the quotes!
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ./stcgal.py -P stc15 -a -r "echo 1 > /sys/class/gpio/gpio666/value"
|
|
||||||
```
|
|
||||||
or
|
|
||||||
|
|
||||||
```
|
|
||||||
$ ./stcgal.py -P stc15 -a -r "./powercycle.sh"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Exit status
|
### Exit status
|
||||||
|
|
||||||
|
12
debian/changelog
vendored
12
debian/changelog
vendored
@ -1,15 +1,3 @@
|
|||||||
stcgal (1.4) unstable; urgency=low
|
|
||||||
|
|
||||||
* Update to 1.4
|
|
||||||
|
|
||||||
-- Grigori <greg@chown.ath.cx> Tue, 19 Sep 2017 17:57:11 +0200
|
|
||||||
|
|
||||||
stcgal (1.3) unstable; urgency=low
|
|
||||||
|
|
||||||
* Update to 1.3
|
|
||||||
|
|
||||||
-- Grigori Goronzy <greg@chown.ath.cx> Sat, 10 Jun 2017 10:01:07 +0200
|
|
||||||
|
|
||||||
stcgal (1.2) unstable; urgency=low
|
stcgal (1.2) unstable; urgency=low
|
||||||
|
|
||||||
* Update to 1.2
|
* Update to 1.2
|
||||||
|
4
debian/control
vendored
4
debian/control
vendored
@ -2,14 +2,14 @@ Source: stcgal
|
|||||||
Section: electronics
|
Section: electronics
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Andrew Andrianov <andrew@ncrmnt.org>
|
Maintainer: Andrew Andrianov <andrew@ncrmnt.org>
|
||||||
Build-Depends: debhelper (>= 9), python3, python3-setuptools, dh-python, python3-serial, python3-tqdm, python3-yaml
|
Build-Depends: debhelper (>= 9), python3, python3-setuptools, dh-python
|
||||||
Standards-Version: 3.9.5
|
Standards-Version: 3.9.5
|
||||||
Homepage: https://github.com/grigorig/stcgal
|
Homepage: https://github.com/grigorig/stcgal
|
||||||
X-Python3-Version: >= 3.2
|
X-Python3-Version: >= 3.2
|
||||||
|
|
||||||
Package: stcgal
|
Package: stcgal
|
||||||
Architecture: all
|
Architecture: all
|
||||||
Depends: ${misc:Depends}, python3, python3-serial, python3-tqdm
|
Depends: ${misc:Depends}, python3, python3-serial
|
||||||
Recommends: python3-usb (>= 1.0.0~b2)
|
Recommends: python3-usb (>= 1.0.0~b2)
|
||||||
Description: STC MCU ISP flash tool
|
Description: STC MCU ISP flash tool
|
||||||
stcgal is a command line flash programming tool for STC MCU Ltd.
|
stcgal is a command line flash programming tool for STC MCU Ltd.
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
STC15 series USB ISP protocol
|
|
||||||
=============================
|
|
||||||
|
|
||||||
General principle
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
- host does OUT and IN control transfers for write and read
|
|
||||||
- IN transfer with wLength = 132, wValue = 0, wIndex = 0, bRequest = 0 are used for all reads
|
|
||||||
- OUT transfers with with specific bRequest, wValue, wIndex are used for writes
|
|
||||||
|
|
||||||
|
|
||||||
Packet coding
|
|
||||||
-------------
|
|
||||||
|
|
||||||
- packets from MCU
|
|
||||||
always start with 0x46 0xb9, similar to serial protocols
|
|
||||||
third byte is packet length, followed by data bytes
|
|
||||||
checksum at the end: 8 bit modular sum
|
|
||||||
|
|
||||||
- packets from host
|
|
||||||
no header bytes
|
|
||||||
bRequest sets packet type
|
|
||||||
wValue, wIndex interpretation according to packet type
|
|
||||||
8 bit modular checksum for every 7 bytes, interleaved
|
|
||||||
|
|
||||||
- packet types derived from the serial protocol
|
|
||||||
|
|
||||||
Specific packet information
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
- flash data
|
|
||||||
wIndex specifies write address
|
|
||||||
wValue is 0xa55a
|
|
||||||
bRequest is 0x22 for first packet, 0x02 for the following ones
|
|
||||||
unusually encoded: a total of 128 bytes per packet,
|
|
||||||
with every 7 byte checksummed in some way,
|
|
||||||
for a total of 18x7 byte segments and a final 2 byte segment
|
|
||||||
checksum: 8 bit modular sum
|
|
||||||
|
|
||||||
- option packet
|
|
||||||
generally same as with serial protocol, some header stuff omitted
|
|
||||||
wIndex is 0
|
|
||||||
wValue is 0xa55a
|
|
||||||
bRequest is 4
|
|
||||||
seems to use the same checksumming scheme as flash writes
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
|||||||
MCS bytes
|
|
||||||
=========
|
|
||||||
|
|
||||||
46 b9 6a 00 33 04 00 00 5a a5 ff ff ff 00 ff ff
|
|
||||||
00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
|
|
||||||
00 ff 01 31 20 80 34 00 01 ff ff ff ff ff 8b bf
|
|
||||||
^^^^^^^^^^^ ^^ ^^ ^^ ^^
|
|
||||||
frequency clkdiv 5) 1) 3)
|
|
||||||
^^^^^
|
|
||||||
trim?
|
|
||||||
f7 fe 1f cc 16
|
|
||||||
^^ ^^
|
|
||||||
4) 2)
|
|
||||||
|
|
||||||
1) not stricty related to some register
|
|
||||||
aka MCS1
|
|
||||||
bit 0: ? always 1
|
|
||||||
bit 1: oscillator high gain
|
|
||||||
bit 2: EPWM push-pull enabled
|
|
||||||
bit 3: p2.0 state after boot
|
|
||||||
bit 4: TXD signal source from RXD
|
|
||||||
bit 5: p3.7 push-pull enabled
|
|
||||||
bit 6: UART1 remap enabled
|
|
||||||
bit 7: long power-on reset delay
|
|
||||||
|
|
||||||
2) not strictly related to some register
|
|
||||||
aka MCS4
|
|
||||||
eeprom size / code space upper limit (in pages)
|
|
||||||
only seems to apply to devices with max. flash size
|
|
||||||
e.g. fe -> 63.5K, e0 -> 56K
|
|
||||||
|
|
||||||
3) like RSTCFG? inverted?
|
|
||||||
aka MCS2
|
|
||||||
bit 0: LVD0
|
|
||||||
bit 1: LVD1
|
|
||||||
bit 2: ? always 1
|
|
||||||
bit 3: ? always 1
|
|
||||||
bit 4: ~reset pin enabled
|
|
||||||
bit 5: ? always 1
|
|
||||||
bit 6: ~enable lvd reset
|
|
||||||
bit 7: ? always 1
|
|
||||||
|
|
||||||
LVD:
|
|
||||||
2.20V -> 0xbf
|
|
||||||
2.40V -> 0xbe
|
|
||||||
2.70V -> 0xbd
|
|
||||||
3.00V -> 0xbc
|
|
||||||
|
|
||||||
4) like WDT_CONTR
|
|
||||||
aka MCS3
|
|
||||||
bit 0: WDPS0
|
|
||||||
bit 1: WDPS1
|
|
||||||
bit 2: WDPS2
|
|
||||||
bit 3: ~stop wdt in idle
|
|
||||||
bit 4: ? always 1
|
|
||||||
bit 5: ~enable wdt on por
|
|
||||||
bit 6: ? always 1
|
|
||||||
bit 7: ? always 1
|
|
||||||
|
|
||||||
WDPS like in datasheet
|
|
||||||
|
|
||||||
5)
|
|
||||||
aka MCS0
|
|
||||||
bit 0: ? ~BSLD / bootloader enabled
|
|
||||||
bit 1: erase eeprom enabled
|
|
||||||
bit 2: ?
|
|
||||||
bit 3: ?
|
|
||||||
bit 4: ?
|
|
||||||
bit 5: ?
|
|
||||||
bit 6: ?
|
|
||||||
bit 7: ?
|
|
@ -1,137 +0,0 @@
|
|||||||
Overview of changes
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
The following changes have been observed compared to STC15:
|
|
||||||
|
|
||||||
- Many differences in the status packet
|
|
||||||
- At least some differences in MCS
|
|
||||||
- Different challenge
|
|
||||||
- no separate program speed
|
|
||||||
- clock division was introduced; calibration always in the ~20-30 MHz range, lower clocks
|
|
||||||
use division
|
|
||||||
- the meaning of the calibration ranges and trim has changed
|
|
||||||
|
|
||||||
The good:
|
|
||||||
|
|
||||||
- Erase, Program, etc. operations are apparently unchanged. :)
|
|
||||||
|
|
||||||
|
|
||||||
Status packet
|
|
||||||
-------------
|
|
||||||
|
|
||||||
46 B9 68 00 30 50 00 54 62 58 5D 00 04 FF FD 8B BF FF 27 4A F7 FE 73 55 00 F6 28 09 85 E3 5F 80 07 20 20 20 01 00 00 FE 05 3A 17 05 25 91 FF 10 AE 16
|
|
||||||
^^^^^ wakeup clock
|
|
||||||
|
|
||||||
Clock set to 20 MHz by STC-ISP (encoding is different compared to STC15):
|
|
||||||
|
|
||||||
46 B9 68 00 30 50 01 31 2E 90 38 01 01 FF FD 8B BF FF 27 35 F7 FE 73 55 00 F6 28 09 85 E3 5F 80 07 20 20 20 01 00 00 FE 05 3A 17 05 25 91 FF 10 54 16
|
|
||||||
46 B9 68 00 30 50 01 31 2E 90 38 01 01 FF FD 8B BF FF 27 3B F7 FE 73 55 00 F6 28 09 85 E3 5F 80 07 20 20 20 01 00 00 FE 05 3A 17 05 25 91 FF 10 5A 16
|
|
||||||
^^^^^ some 24 MHz reference or other clk measurement?
|
|
||||||
^^^^^ trim/adjust?
|
|
||||||
^^ clkdiv
|
|
||||||
^^^^^^^^^^^ clk
|
|
||||||
|
|
||||||
MCS bytes
|
|
||||||
|
|
||||||
46 B9 68 00 30 50 01 31 2E 90 38 01 01 FF FD 8B BF FF 27 35 F7 FE 73 55 00 F6 28 09 85 E3 5F 80 07 20 20 20 01 00 00 FE 05 3A 17 05 25 91 FF 10 54 16
|
|
||||||
^^^^^^^^ ^^^^^
|
|
||||||
|
|
||||||
Disconnect
|
|
||||||
----------
|
|
||||||
|
|
||||||
Uses FF command byte.
|
|
||||||
|
|
||||||
|
|
||||||
Basic challenge operation
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
Host sends a challenge of some kind, followed by 0xfe pulsing
|
|
||||||
|
|
||||||
46 B9 6A 00 0C 00 02 00 00 80 00 00 F8 16
|
|
||||||
|
|
||||||
Much simpler than in STC15
|
|
||||||
|
|
||||||
MCU sends back some response:
|
|
||||||
|
|
||||||
46 B9 68 00 0C 00 02 36 AD 4E 83 02 2A 16
|
|
||||||
|
|
||||||
Host now sends some longer challenge, followed by more pulses:
|
|
||||||
|
|
||||||
46 B9 6A 00 20 00 0C 7C 00 7C 01 7C 02 7C 03 7D 00 7D 01 7D 02 7D 03 7E 00 7E 01 7E 02 7E 03 06 84 16
|
|
||||||
|
|
||||||
MCU sends back some response:
|
|
||||||
|
|
||||||
46 B9 68 00 20 00 0C 4D C6 4D DB 4D E7 4D F3 4D F6 4E 0E 4E 11 4E 26 4E 26 4E 32 4E 41 4E 56 09 DC 16
|
|
||||||
|
|
||||||
Host now seems to initiate a baud switch or something like that
|
|
||||||
|
|
||||||
46 B9 6A 00 0E 01 00 00 FF CC 01 7C 80 03 41 16
|
|
||||||
|
|
||||||
MCU acknowlegdes it:
|
|
||||||
|
|
||||||
46 B9 68 00 07 01 00 70 16
|
|
||||||
|
|
||||||
Now the MCU switches to the new baud rate.
|
|
||||||
|
|
||||||
|
|
||||||
Challenges observed
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
6 MHz:
|
|
||||||
|
|
||||||
46B96A0020000C 1400 1401 1402 1403 1500 1501 1502 1503 1600 1601 1602 1603 01A416
|
|
||||||
|
|
||||||
5.5 MHz:
|
|
||||||
|
|
||||||
46B96A0020000C 5C00 5C01 5C02 5C03 5D00 5D01 5D02 5D03 5E00 5E01 5E02 5E03 050416
|
|
||||||
|
|
||||||
|
|
||||||
11 MHz:
|
|
||||||
|
|
||||||
46B96A0020000C 5B00 5B01 5B02 5B03 5C00 5C01 5C02 5C03 5D00 5D01 5D02 5D03 04F816
|
|
||||||
|
|
||||||
20 MHz:
|
|
||||||
|
|
||||||
46B96A0020000C 3600 3601 3602 3603 3700 3701 3702 3703 3800 3801 3802 3803 033C16
|
|
||||||
|
|
||||||
24 MHz:
|
|
||||||
|
|
||||||
46B96A0020000C 7C00 7C01 7C02 7C03 7D00 7D01 7D02 7D03 7E00 7E01 7E02 7E03 068416
|
|
||||||
|
|
||||||
27 MHz:
|
|
||||||
|
|
||||||
46B96A0020000C B000 B001 B002 B003 B100 B101 B102 B103 B200 B201 B202 B203 08F416
|
|
||||||
|
|
||||||
|
|
||||||
Ranges vs trim value
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
46 B9 6A 00 20 00 0C 00 00 80 00 FF 00 00 01 80 01 FF 01 00 02 80 02 FF 02 00 03 80 03 FF 03 06 A4 16
|
|
||||||
46 B9 68 00 20 00 0C 36 9B 4E 92 65 E4 36 CB 4E 7D 66 29 36 D1 4E 83 66 05 36 CB 4E C2 66 47 0A EA 16
|
|
||||||
|
|
||||||
first byte determines general trim value... range of ~16 to ~30 MHz, the second byte (00..03) is a fine adjustment.
|
|
||||||
|
|
||||||
|
|
||||||
Clock division?
|
|
||||||
---------------
|
|
||||||
|
|
||||||
5.5 MHz vs 11 Mhz: challenge is about the same. it's likely some kind of clock divider is used!
|
|
||||||
|
|
||||||
5.5 Mhz switch: 01 00 00 FF CC 01 5C 80 clkdiv = 4?
|
|
||||||
11 MHz switch: 01 00 00 FF CC 01 5B 80 clkdiv = 2?
|
|
||||||
22 MHz switch: 01 00 00 FF CC 01 5C 80 clkdiv = 1?
|
|
||||||
|
|
||||||
22 Mhz option packet: 0400005AA5FFFFFF00FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF01516D405D0201FFFDFFFFFF8BBFF7FE
|
|
||||||
11 MHz option packet: 0400005AA5FFFFFF00FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF00A8AF985D0102FFFDFFFFFF8BBFF7FE
|
|
||||||
5.5 MHz option packet: 0400005AA5FFFFFF00FFFF00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00FF005462585D0004FFFDFFFFFF8BBFF7FE
|
|
||||||
^^ clkdiv?
|
|
||||||
^^^^^^^^ clkspeed
|
|
||||||
|
|
||||||
Always 24 MHz for programming
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
Calibration for anything but 24 Mhz (and around that) fails when switching baud. Another observation is that there is no
|
|
||||||
programming speed being calibrated anymore. This may suggest that a fixed speed is used for programming.
|
|
||||||
|
|
||||||
Adjusting BRT calculation to 24 MHz in the switch packet seems to work. So it is really using 24 MHz by default;
|
|
||||||
probably some pre-calibrated value.
|
|
13
setup.py
13
setup.py
@ -24,13 +24,10 @@
|
|||||||
import stcgal
|
import stcgal
|
||||||
from setuptools import setup, find_packages
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
with open("README.md", "r") as fh:
|
|
||||||
long_description = fh.read()
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name = "stcgal",
|
name = "stcgal",
|
||||||
version = stcgal.__version__,
|
version = stcgal.__version__,
|
||||||
packages = find_packages(exclude=["doc", "tests"]),
|
packages = find_packages(exclude=["doc"]),
|
||||||
install_requires = ["pyserial"],
|
install_requires = ["pyserial"],
|
||||||
extras_require = {
|
extras_require = {
|
||||||
"usb": ["pyusb>=1.0.0"]
|
"usb": ["pyusb>=1.0.0"]
|
||||||
@ -41,9 +38,6 @@ setup(
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
description = "STC MCU ISP flash tool",
|
description = "STC MCU ISP flash tool",
|
||||||
long_description = long_description,
|
|
||||||
long_description_content_type = "text/markdown",
|
|
||||||
keywords = "stc mcu microcontroller 8051 mcs-51",
|
|
||||||
url = "https://github.com/grigorig/stcgal",
|
url = "https://github.com/grigorig/stcgal",
|
||||||
author = "Grigori Goronzy",
|
author = "Grigori Goronzy",
|
||||||
author_email = "greg@kinoho.net",
|
author_email = "greg@kinoho.net",
|
||||||
@ -58,12 +52,7 @@ setup(
|
|||||||
"Operating System :: Microsoft :: Windows",
|
"Operating System :: Microsoft :: Windows",
|
||||||
"Operating System :: MacOS",
|
"Operating System :: MacOS",
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.4",
|
|
||||||
"Programming Language :: Python :: 3.5",
|
|
||||||
"Programming Language :: Python :: 3.6",
|
|
||||||
"Topic :: Software Development :: Embedded Systems",
|
"Topic :: Software Development :: Embedded Systems",
|
||||||
"Topic :: Software Development",
|
"Topic :: Software Development",
|
||||||
],
|
],
|
||||||
test_suite = "tests",
|
|
||||||
tests_require = ["PyYAML"],
|
|
||||||
)
|
)
|
||||||
|
@ -1 +1 @@
|
|||||||
__version__ = "1.4"
|
__version__ = "1.2"
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2013-2015 Grigori Goronzy <greg@chown.ath.cx>
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
|
||||||
# in the Software without restriction, including without limitation the rights
|
|
||||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
# copies of the Software, and to permit persons to whom the Software is
|
|
||||||
# furnished to do so, subject to the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be included in all
|
|
||||||
# copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
# SOFTWARE.
|
|
||||||
#
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import stcgal.frontend
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(stcgal.frontend.cli())
|
|
@ -20,22 +20,11 @@
|
|||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
import sys
|
import sys, os, time, struct
|
||||||
import argparse
|
import argparse
|
||||||
import stcgal
|
import stcgal
|
||||||
import serial
|
from stcgal.utils import Utils, BaudType
|
||||||
from stcgal.utils import BaudType
|
from stcgal.protocols import *
|
||||||
from stcgal.protocols import Stc89Protocol
|
|
||||||
from stcgal.protocols import Stc12AProtocol
|
|
||||||
from stcgal.protocols import Stc12BProtocol
|
|
||||||
from stcgal.protocols import Stc12Protocol
|
|
||||||
from stcgal.protocols import Stc15Protocol
|
|
||||||
from stcgal.protocols import Stc15AProtocol
|
|
||||||
from stcgal.protocols import StcUsb15Protocol
|
|
||||||
from stcgal.protocols import Stc8Protocol
|
|
||||||
from stcgal.protocols import StcAutoProtocol
|
|
||||||
from stcgal.protocols import StcProtocolException
|
|
||||||
from stcgal.protocols import StcFramingException
|
|
||||||
from stcgal.ihex import IHex
|
from stcgal.ihex import IHex
|
||||||
|
|
||||||
class StcGal:
|
class StcGal:
|
||||||
@ -43,10 +32,7 @@ class StcGal:
|
|||||||
|
|
||||||
def __init__(self, opts):
|
def __init__(self, opts):
|
||||||
self.opts = opts
|
self.opts = opts
|
||||||
self.initialize_protocol(opts)
|
|
||||||
|
|
||||||
def initialize_protocol(self, opts):
|
|
||||||
"""Initialize protocol backend"""
|
|
||||||
if opts.protocol == "stc89":
|
if opts.protocol == "stc89":
|
||||||
self.protocol = Stc89Protocol(opts.port, opts.handshake, opts.baud)
|
self.protocol = Stc89Protocol(opts.port, opts.handshake, opts.baud)
|
||||||
elif opts.protocol == "stc12a":
|
elif opts.protocol == "stc12a":
|
||||||
@ -61,26 +47,21 @@ class StcGal:
|
|||||||
elif opts.protocol == "stc15":
|
elif opts.protocol == "stc15":
|
||||||
self.protocol = Stc15Protocol(opts.port, opts.handshake, opts.baud,
|
self.protocol = Stc15Protocol(opts.port, opts.handshake, opts.baud,
|
||||||
round(opts.trim * 1000))
|
round(opts.trim * 1000))
|
||||||
elif opts.protocol == "stc8":
|
|
||||||
self.protocol = Stc8Protocol(opts.port, opts.handshake, opts.baud,
|
|
||||||
round(opts.trim * 1000))
|
|
||||||
elif opts.protocol == "usb15":
|
elif opts.protocol == "usb15":
|
||||||
self.protocol = StcUsb15Protocol()
|
self.protocol = StcUsb15Protocol()
|
||||||
else:
|
else:
|
||||||
self.protocol = StcAutoProtocol(opts.port, opts.handshake, opts.baud)
|
self.protocol = StcBaseProtocol(opts.port, opts.handshake, opts.baud)
|
||||||
|
|
||||||
self.protocol.debug = opts.debug
|
self.protocol.debug = opts.debug
|
||||||
|
|
||||||
def emit_options(self, options):
|
def emit_options(self, options):
|
||||||
"""Set options from command line to protocol handler."""
|
for o in options:
|
||||||
|
|
||||||
for opt in options:
|
|
||||||
try:
|
try:
|
||||||
kv = opt.split("=", 1)
|
kv = o.split("=", 1)
|
||||||
if len(kv) < 2:
|
if len(kv) < 2: raise ValueError("incorrect format")
|
||||||
raise ValueError("incorrect format")
|
|
||||||
self.protocol.set_option(kv[0], kv[1])
|
self.protocol.set_option(kv[0], kv[1])
|
||||||
except ValueError as ex:
|
except ValueError as e:
|
||||||
raise NameError("invalid option '%s' (%s)" % (kv[0], ex))
|
raise NameError("invalid option '%s' (%s)" % (kv[0], e))
|
||||||
|
|
||||||
def load_file_auto(self, fileobj):
|
def load_file_auto(self, fileobj):
|
||||||
"""Load file with Intel Hex autodetection."""
|
"""Load file with Intel Hex autodetection."""
|
||||||
@ -93,16 +74,14 @@ class StcGal:
|
|||||||
binary = hexfile.extract_data()
|
binary = hexfile.extract_data()
|
||||||
print("%d bytes (Intel HEX)" %len(binary))
|
print("%d bytes (Intel HEX)" %len(binary))
|
||||||
return binary
|
return binary
|
||||||
except ValueError as ex:
|
except ValueError as e:
|
||||||
raise IOError("invalid Intel HEX file (%s)" %ex)
|
raise IOError("invalid Intel HEX file (%s)" %e)
|
||||||
else:
|
else:
|
||||||
binary = fileobj.read()
|
binary = fileobj.read()
|
||||||
print("%d bytes (Binary)" %len(binary))
|
print("%d bytes (Binary)" %len(binary))
|
||||||
return binary
|
return binary
|
||||||
|
|
||||||
def program_mcu(self):
|
def program_mcu(self):
|
||||||
"""Execute the standard programming flow."""
|
|
||||||
|
|
||||||
code_size = self.protocol.model.code
|
code_size = self.protocol.model.code
|
||||||
ee_size = self.protocol.model.eeprom
|
ee_size = self.protocol.model.eeprom
|
||||||
|
|
||||||
@ -145,67 +124,67 @@ class StcGal:
|
|||||||
self.protocol.disconnect()
|
self.protocol.disconnect()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Run programmer, main entry point."""
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.protocol.connect(autoreset=self.opts.autoreset, resetcmd=self.opts.resetcmd)
|
self.protocol.connect(autoreset=self.opts.autoreset)
|
||||||
if isinstance(self.protocol, StcAutoProtocol):
|
|
||||||
|
if self.opts.protocol == "auto":
|
||||||
if not self.protocol.protocol_name:
|
if not self.protocol.protocol_name:
|
||||||
raise StcProtocolException("cannot detect protocol")
|
raise StcProtocolException("cannot detect protocol")
|
||||||
base_protocol = self.protocol
|
base_protocol = self.protocol
|
||||||
self.opts.protocol = self.protocol.protocol_name
|
self.opts.protocol = self.protocol.protocol_name
|
||||||
print("Protocol detected: %s" % self.opts.protocol)
|
print("Protocol detected: %s" % self.opts.protocol)
|
||||||
# recreate self.protocol with proper protocol class
|
# recreate self.protocol with proper protocol class
|
||||||
self.initialize_protocol(self.opts)
|
self.__init__(self.opts)
|
||||||
else:
|
else:
|
||||||
base_protocol = None
|
base_protocol = None
|
||||||
|
|
||||||
self.protocol.initialize(base_protocol)
|
self.protocol.initialize(base_protocol)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
sys.stdout.flush()
|
sys.stdout.flush();
|
||||||
print("interrupted")
|
print("interrupted")
|
||||||
return 2
|
return 2
|
||||||
except (StcFramingException, StcProtocolException) as ex:
|
except (StcFramingException, StcProtocolException) as e:
|
||||||
sys.stdout.flush()
|
sys.stdout.flush();
|
||||||
print("Protocol error: %s" % ex, file=sys.stderr)
|
print("Protocol error: %s" % e, file=sys.stderr)
|
||||||
self.protocol.disconnect()
|
self.protocol.disconnect()
|
||||||
return 1
|
return 1
|
||||||
except serial.SerialException as ex:
|
except serial.SerialException as e:
|
||||||
sys.stdout.flush()
|
sys.stdout.flush();
|
||||||
print("Serial port error: %s" % ex, file=sys.stderr)
|
print("Serial port error: %s" % e, file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
except IOError as ex:
|
except IOError as e:
|
||||||
sys.stdout.flush()
|
sys.stdout.flush();
|
||||||
print("I/O error: %s" % ex, file=sys.stderr)
|
print("I/O error: %s" % e, file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self.opts.code_image:
|
if self.opts.code_image:
|
||||||
self.program_mcu()
|
self.program_mcu()
|
||||||
return 0
|
return 0
|
||||||
self.protocol.disconnect()
|
else:
|
||||||
return 0
|
self.protocol.disconnect()
|
||||||
except NameError as ex:
|
return 0
|
||||||
sys.stdout.flush()
|
except NameError as e:
|
||||||
print("Option error: %s" % ex, file=sys.stderr)
|
sys.stdout.flush();
|
||||||
|
print("Option error: %s" % e, file=sys.stderr)
|
||||||
self.protocol.disconnect()
|
self.protocol.disconnect()
|
||||||
return 1
|
return 1
|
||||||
except (StcFramingException, StcProtocolException) as ex:
|
except (StcFramingException, StcProtocolException) as e:
|
||||||
sys.stdout.flush()
|
sys.stdout.flush();
|
||||||
print("Protocol error: %s" % ex, file=sys.stderr)
|
print("Protocol error: %s" % e, file=sys.stderr)
|
||||||
self.protocol.disconnect()
|
self.protocol.disconnect()
|
||||||
return 1
|
return 1
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
sys.stdout.flush()
|
sys.stdout.flush();
|
||||||
print("interrupted", file=sys.stderr)
|
print("interrupted", file=sys.stderr)
|
||||||
self.protocol.disconnect()
|
self.protocol.disconnect()
|
||||||
return 2
|
return 2
|
||||||
except serial.SerialException as ex:
|
except serial.SerialException as e:
|
||||||
print("Serial port error: %s" % ex, file=sys.stderr)
|
print("Serial port error: %s" % e, file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
except IOError as ex:
|
except IOError as e:
|
||||||
sys.stdout.flush()
|
sys.stdout.flush();
|
||||||
print("I/O error: %s" % ex, file=sys.stderr)
|
print("I/O error: %s" % e, file=sys.stderr)
|
||||||
self.protocol.disconnect()
|
self.protocol.disconnect()
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@ -213,14 +192,11 @@ class StcGal:
|
|||||||
def cli():
|
def cli():
|
||||||
# check arguments
|
# check arguments
|
||||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
|
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
description="stcgal {} - an STC MCU ISP flash tool\n".format(stcgal.__version__) +
|
description="stcgal %s - an STC MCU ISP flash tool\n(C) 2014-2015 Grigori Goronzy\nhttps://github.com/grigorig/stcgal" %stcgal.__version__)
|
||||||
"(C) 2014-2017 Grigori Goronzy\nhttps://github.com/grigorig/stcgal")
|
|
||||||
parser.add_argument("code_image", help="code segment file to flash (BIN/HEX)", type=argparse.FileType("rb"), nargs='?')
|
parser.add_argument("code_image", help="code segment file to flash (BIN/HEX)", type=argparse.FileType("rb"), nargs='?')
|
||||||
parser.add_argument("eeprom_image", help="eeprom segment file to flash (BIN/HEX)", type=argparse.FileType("rb"), nargs='?')
|
parser.add_argument("eeprom_image", help="eeprom segment file to flash (BIN/HEX)", type=argparse.FileType("rb"), nargs='?')
|
||||||
parser.add_argument("-a", "--autoreset", help="cycle power automatically by asserting DTR", action="store_true")
|
parser.add_argument("-a", "--autoreset", help="cycle power automatically by asserting DTR", action="store_true")
|
||||||
parser.add_argument("-r", "--resetcmd", help="Use this shell command for board power-cycling (instead of DTR assertion)", action="store")
|
parser.add_argument("-P", "--protocol", help="protocol version (default: auto)", choices=["stc89", "stc12a", "stc12b", "stc12", "stc15a", "stc15", "usb15", "auto"], default="auto")
|
||||||
parser.add_argument("-P", "--protocol", help="protocol version (default: auto)",
|
|
||||||
choices=["stc89", "stc12a", "stc12b", "stc12", "stc15a", "stc15", "stc8", "usb15", "auto"], default="auto")
|
|
||||||
parser.add_argument("-p", "--port", help="serial port device", default="/dev/ttyUSB0")
|
parser.add_argument("-p", "--port", help="serial port device", default="/dev/ttyUSB0")
|
||||||
parser.add_argument("-b", "--baud", help="transfer baud rate (default: 19200)", type=BaudType(), default=19200)
|
parser.add_argument("-b", "--baud", help="transfer baud rate (default: 19200)", type=BaudType(), default=19200)
|
||||||
parser.add_argument("-l", "--handshake", help="handshake baud rate (default: 2400)", type=BaudType(), default=2400)
|
parser.add_argument("-l", "--handshake", help="handshake baud rate (default: 2400)", type=BaudType(), default=2400)
|
||||||
|
326
stcgal/ihex.py
326
stcgal/ihex.py
@ -5,213 +5,201 @@
|
|||||||
import struct
|
import struct
|
||||||
import codecs
|
import codecs
|
||||||
|
|
||||||
|
class IHex(object):
|
||||||
|
@classmethod
|
||||||
|
def read(cls, lines):
|
||||||
|
ihex = cls()
|
||||||
|
|
||||||
class IHex:
|
segbase = 0
|
||||||
"""Intel HEX parser and writer"""
|
for line in lines:
|
||||||
|
line = line.strip()
|
||||||
|
if not line: continue
|
||||||
|
|
||||||
@classmethod
|
t, a, d = ihex.parse_line(line)
|
||||||
def read(cls, lines):
|
if t == 0x00:
|
||||||
"""Read Intel HEX data from string or lines"""
|
ihex.insert_data(segbase + a, d)
|
||||||
ihex = cls()
|
|
||||||
|
|
||||||
segbase = 0
|
elif t == 0x01:
|
||||||
for line in lines:
|
break # Should we check for garbage after this?
|
||||||
line = line.strip()
|
|
||||||
if not line:
|
|
||||||
continue
|
|
||||||
|
|
||||||
t, a, d = ihex.parse_line(line)
|
elif t == 0x02:
|
||||||
if t == 0x00:
|
ihex.set_mode(16)
|
||||||
ihex.insert_data(segbase + a, d)
|
segbase = struct.unpack(">H", d[0:2])[0] << 4
|
||||||
|
|
||||||
elif t == 0x01:
|
elif t == 0x03:
|
||||||
break # Should we check for garbage after this?
|
ihex.set_mode(16)
|
||||||
|
|
||||||
elif t == 0x02:
|
cs, ip = struct.unpack(">2H", d[0:2])
|
||||||
ihex.set_mode(16)
|
ihex.set_start((cs, ip))
|
||||||
segbase = struct.unpack(">H", d[0:2])[0] << 4
|
|
||||||
|
|
||||||
elif t == 0x03:
|
elif t == 0x04:
|
||||||
ihex.set_mode(16)
|
ihex.set_mode(32)
|
||||||
|
segbase = struct.unpack(">H", d[0:2])[0] << 16
|
||||||
|
|
||||||
cs, ip = struct.unpack(">2H", d[0:2])
|
elif t == 0x05:
|
||||||
ihex.set_start((cs, ip))
|
ihex.set_mode(32)
|
||||||
|
ihex.set_start(struct.unpack(">I", d[0:4])[0])
|
||||||
|
|
||||||
elif t == 0x04:
|
else:
|
||||||
ihex.set_mode(32)
|
raise ValueError("Invalid type byte")
|
||||||
segbase = struct.unpack(">H", d[0:2])[0] << 16
|
|
||||||
|
|
||||||
elif t == 0x05:
|
return ihex
|
||||||
ihex.set_mode(32)
|
|
||||||
ihex.set_start(struct.unpack(">I", d[0:4])[0])
|
|
||||||
|
|
||||||
else:
|
@classmethod
|
||||||
raise ValueError("Invalid type byte")
|
def read_file(cls, fname):
|
||||||
|
f = open(fname, "rb")
|
||||||
|
ihex = cls.read(f)
|
||||||
|
f.close()
|
||||||
|
return ihex
|
||||||
|
|
||||||
return ihex
|
def __init__(self):
|
||||||
|
self.areas = {}
|
||||||
|
self.start = None
|
||||||
|
self.mode = 8
|
||||||
|
self.row_bytes = 16
|
||||||
|
|
||||||
@classmethod
|
def set_row_bytes(self, row_bytes):
|
||||||
def read_file(cls, fname):
|
"""Set output hex file row width (bytes represented per row)."""
|
||||||
"""Read Intel HEX data from file"""
|
if row_bytes < 1 or row_bytes > 0xff:
|
||||||
f = open(fname, "rb")
|
raise ValueError("Value out of range: (%r)" % row_bytes)
|
||||||
ihex = cls.read(f)
|
self.row_bytes = row_bytes
|
||||||
f.close()
|
|
||||||
return ihex
|
def extract_data(self, start=None, end=None):
|
||||||
|
if start is None:
|
||||||
|
start = 0
|
||||||
|
|
||||||
|
if end is None:
|
||||||
|
result = bytearray()
|
||||||
|
|
||||||
|
for addr, data in self.areas.items():
|
||||||
|
if addr >= start:
|
||||||
|
if len(result) < (addr - start):
|
||||||
|
result[len(result):addr-start] = bytes(addr-start-len(result))
|
||||||
|
result[addr-start:addr-start+len(data)] = data
|
||||||
|
|
||||||
|
return bytes(result)
|
||||||
|
|
||||||
|
else:
|
||||||
|
result = bytearray()
|
||||||
|
|
||||||
|
for addr, data in self.areas.items():
|
||||||
|
if addr >= start and addr < end:
|
||||||
|
data = data[:end-addr]
|
||||||
|
if len(result) < (addr - start):
|
||||||
|
result[len(result):addr-start] = bytes(addr-start-len(result))
|
||||||
|
result[addr-start:addr-start+len(data)] = data
|
||||||
|
|
||||||
|
return bytes(result)
|
||||||
|
|
||||||
|
def set_start(self, start=None):
|
||||||
|
self.start = start
|
||||||
|
|
||||||
def __init__(self):
|
def set_mode(self, mode):
|
||||||
self.areas = {}
|
self.mode = mode
|
||||||
self.start = None
|
|
||||||
self.mode = 8
|
|
||||||
self.row_bytes = 16
|
|
||||||
|
|
||||||
def set_row_bytes(self, row_bytes):
|
def get_area(self, addr):
|
||||||
"""Set output hex file row width (bytes represented per row)."""
|
for start, data in self.areas.items():
|
||||||
if row_bytes < 1 or row_bytes > 0xff:
|
end = start + len(data)
|
||||||
raise ValueError("Value out of range: (%r)" % row_bytes)
|
if addr >= start and addr <= end:
|
||||||
self.row_bytes = row_bytes
|
return start
|
||||||
|
|
||||||
def extract_data(self, start=None, end=None):
|
return None
|
||||||
"""Extract binary data"""
|
|
||||||
if start is None:
|
|
||||||
start = 0
|
|
||||||
|
|
||||||
if end is None:
|
def insert_data(self, istart, idata):
|
||||||
result = bytearray()
|
iend = istart + len(idata)
|
||||||
|
|
||||||
for addr, data in self.areas.items():
|
area = self.get_area(istart)
|
||||||
if addr >= start:
|
if area is None:
|
||||||
if len(result) < (addr - start):
|
self.areas[istart] = idata
|
||||||
result[len(result):addr - start] = bytes(
|
|
||||||
addr - start - len(result))
|
|
||||||
result[addr - start:addr - start + len(data)] = data
|
|
||||||
|
|
||||||
return bytes(result)
|
else:
|
||||||
|
data = self.areas[area]
|
||||||
|
# istart - iend + len(idata) + len(data)
|
||||||
|
self.areas[area] = data[:istart-area] + idata + data[iend-area:]
|
||||||
|
|
||||||
result = bytearray()
|
def calc_checksum(self, bytes):
|
||||||
|
total = sum(bytes)
|
||||||
|
return (-total) & 0xFF
|
||||||
|
|
||||||
for addr, data in self.areas.items():
|
def parse_line(self, rawline):
|
||||||
if addr >= start and addr < end:
|
if rawline[0:1] != b":":
|
||||||
data = data[:end - addr]
|
raise ValueError("Invalid line start character (%r)" % rawline[0])
|
||||||
if len(result) < (addr - start):
|
|
||||||
result[len(result):addr - start] = bytes(
|
|
||||||
addr - start - len(result))
|
|
||||||
result[addr - start:addr - start + len(data)] = data
|
|
||||||
|
|
||||||
return bytes(result)
|
try:
|
||||||
|
#line = rawline[1:].decode("hex")
|
||||||
|
line = codecs.decode(rawline[1:], "hex_codec")
|
||||||
|
except:
|
||||||
|
raise ValueError("Invalid hex data")
|
||||||
|
|
||||||
def set_start(self, start=None):
|
length, addr, type = struct.unpack(">BHB", line[:4])
|
||||||
self.start = start
|
|
||||||
|
|
||||||
def set_mode(self, mode):
|
dataend = length + 4
|
||||||
self.mode = mode
|
data = line[4:dataend]
|
||||||
|
|
||||||
def get_area(self, addr):
|
#~ print line[dataend:dataend + 2], repr(line)
|
||||||
for start, data in self.areas.items():
|
cs1 = line[dataend]
|
||||||
end = start + len(data)
|
cs2 = self.calc_checksum(line[:dataend])
|
||||||
if addr >= start and addr <= end:
|
|
||||||
return start
|
|
||||||
|
|
||||||
return None
|
if cs1 != cs2:
|
||||||
|
raise ValueError("Checksums do not match")
|
||||||
|
|
||||||
def insert_data(self, istart, idata):
|
return (type, addr, data)
|
||||||
iend = istart + len(idata)
|
|
||||||
|
|
||||||
area = self.get_area(istart)
|
def make_line(self, type, addr, data):
|
||||||
if area is None:
|
line = struct.pack(">BHB", len(data), addr, type)
|
||||||
self.areas[istart] = idata
|
line += data
|
||||||
|
line += chr(self.calc_checksum(line))
|
||||||
|
#~ return ":" + line.encode("hex")
|
||||||
|
return ":" + line.encode("hex").upper() + "\r\n"
|
||||||
|
|
||||||
else:
|
def write(self):
|
||||||
data = self.areas[area]
|
output = ""
|
||||||
# istart - iend + len(idata) + len(data)
|
|
||||||
self.areas[area] = data[
|
for start, data in sorted(self.areas.items()):
|
||||||
:istart - area] + idata + data[iend - area:]
|
i = 0
|
||||||
|
segbase = 0
|
||||||
|
|
||||||
def calc_checksum(self, data):
|
while i < len(data):
|
||||||
total = sum(data)
|
chunk = data[i:i + self.row_bytes]
|
||||||
return (-total) & 0xFF
|
|
||||||
|
|
||||||
def parse_line(self, rawline):
|
addr = start
|
||||||
if rawline[0:1] != b":":
|
newsegbase = segbase
|
||||||
raise ValueError("Invalid line start character (%r)" % rawline[0])
|
|
||||||
|
|
||||||
try:
|
if self.mode == 8:
|
||||||
line = codecs.decode(rawline[1:], "hex_codec")
|
addr = addr & 0xFFFF
|
||||||
except ValueError:
|
|
||||||
raise ValueError("Invalid hex data")
|
|
||||||
|
|
||||||
length, addr, line_type = struct.unpack(">BHB", line[:4])
|
elif self.mode == 16:
|
||||||
|
t = addr & 0xFFFF
|
||||||
|
newsegbase = (addr - t) >> 4
|
||||||
|
addr = t
|
||||||
|
|
||||||
dataend = length + 4
|
if newsegbase != segbase:
|
||||||
data = line[4:dataend]
|
output += self.make_line(0x02, 0, struct.pack(">H", newsegbase))
|
||||||
|
segbase = newsegbase
|
||||||
|
|
||||||
cs1 = line[dataend]
|
elif self.mode == 32:
|
||||||
cs2 = self.calc_checksum(line[:dataend])
|
newsegbase = addr >> 16
|
||||||
|
addr = addr & 0xFFFF
|
||||||
|
|
||||||
if cs1 != cs2:
|
if newsegbase != segbase:
|
||||||
raise ValueError("Checksums do not match")
|
output += self.make_line(0x04, 0, struct.pack(">H", newsegbase))
|
||||||
|
segbase = newsegbase
|
||||||
|
|
||||||
return (line_type, addr, data)
|
output += self.make_line(0x00, addr, chunk)
|
||||||
|
|
||||||
def make_line(self, line_type, addr, data):
|
i += self.row_bytes
|
||||||
line = struct.pack(">BHB", len(data), addr, line_type)
|
start += self.row_bytes
|
||||||
line += data
|
|
||||||
line += chr(self.calc_checksum(line))
|
|
||||||
return ":" + line.encode("hex").upper() + "\r\n"
|
|
||||||
|
|
||||||
def write(self):
|
if self.start is not None:
|
||||||
"""Write Intel HEX data to string"""
|
if self.mode == 16:
|
||||||
output = ""
|
output += self.make_line(0x03, 0, struct.pack(">2H", self.start[0], self.start[1]))
|
||||||
|
elif self.mode == 32:
|
||||||
|
output += self.make_line(0x05, 0, struct.pack(">I", self.start))
|
||||||
|
|
||||||
for start, data in sorted(self.areas.items()):
|
output += self.make_line(0x01, 0, "")
|
||||||
i = 0
|
return output
|
||||||
segbase = 0
|
|
||||||
|
|
||||||
while i < len(data):
|
def write_file(self, fname):
|
||||||
chunk = data[i:i + self.row_bytes]
|
f = open(fname, "w")
|
||||||
|
f.write(self.write())
|
||||||
addr = start
|
f.close()
|
||||||
newsegbase = segbase
|
|
||||||
|
|
||||||
if self.mode == 8:
|
|
||||||
addr = addr & 0xFFFF
|
|
||||||
|
|
||||||
elif self.mode == 16:
|
|
||||||
t = addr & 0xFFFF
|
|
||||||
newsegbase = (addr - t) >> 4
|
|
||||||
addr = t
|
|
||||||
|
|
||||||
if newsegbase != segbase:
|
|
||||||
output += self.make_line(
|
|
||||||
0x02, 0, struct.pack(">H", newsegbase))
|
|
||||||
segbase = newsegbase
|
|
||||||
|
|
||||||
elif self.mode == 32:
|
|
||||||
newsegbase = addr >> 16
|
|
||||||
addr = addr & 0xFFFF
|
|
||||||
|
|
||||||
if newsegbase != segbase:
|
|
||||||
output += self.make_line(
|
|
||||||
0x04, 0, struct.pack(">H", newsegbase))
|
|
||||||
segbase = newsegbase
|
|
||||||
|
|
||||||
output += self.make_line(0x00, addr, chunk)
|
|
||||||
|
|
||||||
i += self.row_bytes
|
|
||||||
start += self.row_bytes
|
|
||||||
|
|
||||||
if self.start is not None:
|
|
||||||
if self.mode == 16:
|
|
||||||
output += self.make_line(
|
|
||||||
0x03, 0, struct.pack(">2H", self.start[0], self.start[1]))
|
|
||||||
elif self.mode == 32:
|
|
||||||
output += self.make_line(
|
|
||||||
0x05, 0, struct.pack(">I", self.start))
|
|
||||||
|
|
||||||
output += self.make_line(0x01, 0, "")
|
|
||||||
return output
|
|
||||||
|
|
||||||
def write_file(self, fname):
|
|
||||||
"""Write Intel HEX data to file"""
|
|
||||||
f = open(fname, "w")
|
|
||||||
f.write(self.write())
|
|
||||||
f.close()
|
|
||||||
|
@ -973,46 +973,6 @@ class MCUModelDatabase:
|
|||||||
MCUModel(name='STC90LE513AD', magic=0xf18d, total=65536, code=53248, eeprom=10240),
|
MCUModel(name='STC90LE513AD', magic=0xf18d, total=65536, code=53248, eeprom=10240),
|
||||||
MCUModel(name='STC90LE514AD', magic=0xf18e, total=65536, code=57344, eeprom=6144),
|
MCUModel(name='STC90LE514AD', magic=0xf18e, total=65536, code=57344, eeprom=6144),
|
||||||
MCUModel(name='STC90LE516AD', magic=0xf190, total=65536, code=63488, eeprom=0),
|
MCUModel(name='STC90LE516AD', magic=0xf190, total=65536, code=63488, eeprom=0),
|
||||||
|
|
||||||
# Warning, these definitions lack a valid eeprom size.
|
|
||||||
MCUModel(name='STC15F04AD', magic=0xd444, total=4096, code=4096, eeprom=0),
|
|
||||||
MCUModel(name='STC15F06AD', magic=0xd446, total=6144, code=6144, eeprom=0),
|
|
||||||
MCUModel(name='STC15F08AD', magic=0xd448, total=8192, code=8192, eeprom=0),
|
|
||||||
MCUModel(name='STC15F10AD', magic=0xd44a, total=10240, code=10240, eeprom=0),
|
|
||||||
MCUModel(name='STC15F12AD', magic=0xd44c, total=12288, code=12288, eeprom=0),
|
|
||||||
MCUModel(name='STC15F04CCP', magic=0xd434, total=4096, code=4096, eeprom=0),
|
|
||||||
MCUModel(name='STC15F06CCP', magic=0xd436, total=6144, code=6144, eeprom=0),
|
|
||||||
MCUModel(name='STC15F08CCP', magic=0xd438, total=8192, code=8192, eeprom=0),
|
|
||||||
MCUModel(name='STC15F10CCP', magic=0xd43a, total=10240, code=10240, eeprom=0),
|
|
||||||
MCUModel(name='STC15F12CCP', magic=0xd43c, total=12288, code=12288, eeprom=0),
|
|
||||||
MCUModel(name='STC15F04', magic=0xd404, total=4096, code=4096, eeprom=0),
|
|
||||||
MCUModel(name='STC15F06', magic=0xd406, total=6144, code=6144, eeprom=0),
|
|
||||||
MCUModel(name='STC15F08', magic=0xd408, total=8192, code=8192, eeprom=0),
|
|
||||||
MCUModel(name='STC15F10', magic=0xd40a, total=10240, code=10240, eeprom=0),
|
|
||||||
MCUModel(name='STC15F12', magic=0xd40c, total=12288, code=12288, eeprom=0),
|
|
||||||
MCUModel(name='IAP15F08AD', magic=0xd458, total=8192, code=8192, eeprom=0),
|
|
||||||
MCUModel(name='IAP15F10AD', magic=0xd45a, total=10240, code=10240, eeprom=0),
|
|
||||||
MCUModel(name='IAP15F12AD', magic=0xd45c, total=12288, code=12288, eeprom=0),
|
|
||||||
MCUModel(name='IAP15F14AD', magic=0xd45e, total=14336, code=14336, eeprom=0),
|
|
||||||
MCUModel(name='STC15L04AD', magic=0xd4c4, total=4096, code=4096, eeprom=0),
|
|
||||||
MCUModel(name='STC15L06AD', magic=0xd4c6, total=6144, code=6144, eeprom=0),
|
|
||||||
MCUModel(name='STC15L08AD', magic=0xd4c8, total=8192, code=8192, eeprom=0),
|
|
||||||
MCUModel(name='STC15L10AD', magic=0xd4ca, total=10240, code=10240, eeprom=0),
|
|
||||||
MCUModel(name='STC15L12AD', magic=0xd4cc, total=12288, code=12288, eeprom=0),
|
|
||||||
MCUModel(name='STC15L04CCP', magic=0xd4b4, total=4096, code=4096, eeprom=0),
|
|
||||||
MCUModel(name='STC15L06CCP', magic=0xd4b6, total=6144, code=6144, eeprom=0),
|
|
||||||
MCUModel(name='STC15L08CCP', magic=0xd4b8, total=8192, code=8192, eeprom=0),
|
|
||||||
MCUModel(name='STC15L10CCP', magic=0xd4ba, total=10240, code=10240, eeprom=0),
|
|
||||||
MCUModel(name='STC15L12CCP', magic=0xd4bc, total=12288, code=12288, eeprom=0),
|
|
||||||
MCUModel(name='STC15L04', magic=0xd484, total=4096, code=4096, eeprom=0),
|
|
||||||
MCUModel(name='STC15L06', magic=0xd486, total=6144, code=6144, eeprom=0),
|
|
||||||
MCUModel(name='STC15L08', magic=0xd488, total=8192, code=8192, eeprom=0),
|
|
||||||
MCUModel(name='STC15L10', magic=0xd48a, total=10240, code=10240, eeprom=0),
|
|
||||||
MCUModel(name='STC15L12', magic=0xd48c, total=12288, code=12288, eeprom=0),
|
|
||||||
MCUModel(name='IAP15L08AD', magic=0xd4d8, total=8192, code=8192, eeprom=0),
|
|
||||||
MCUModel(name='IAP15L10AD', magic=0xd4da, total=10240, code=10240, eeprom=0),
|
|
||||||
MCUModel(name='IAP15L12AD', magic=0xd4dc, total=12288, code=12288, eeprom=0),
|
|
||||||
MCUModel(name='IAP15L14AD', magic=0xd4de, total=14336, code=14336, eeprom=0),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -1028,3 +988,6 @@ class MCUModelDatabase:
|
|||||||
print(" Magic: %02X%02X" % (model.magic >> 8, model.magic & 0xff))
|
print(" Magic: %02X%02X" % (model.magic >> 8, model.magic & 0xff))
|
||||||
print(" Code flash: %.1f KB" % (model.code / 1024.0))
|
print(" Code flash: %.1f KB" % (model.code / 1024.0))
|
||||||
print(" EEPROM flash: %.1f KB" % (model.eeprom / 1024.0))
|
print(" EEPROM flash: %.1f KB" % (model.eeprom / 1024.0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,24 +21,15 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import struct
|
import struct
|
||||||
from abc import ABC
|
|
||||||
from stcgal.utils import Utils
|
from stcgal.utils import Utils
|
||||||
|
|
||||||
class BaseOption(ABC):
|
class BaseOption:
|
||||||
"""Base class for options"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.options = ()
|
|
||||||
self.msr = None
|
|
||||||
|
|
||||||
def print(self):
|
def print(self):
|
||||||
"""Print current configuration to standard output"""
|
|
||||||
print("Target options:")
|
print("Target options:")
|
||||||
for name, get_func, _ in self.options:
|
for name, get_func, _ in self.options:
|
||||||
print(" %s=%s" % (name, get_func()))
|
print(" %s=%s" % (name, get_func()))
|
||||||
|
|
||||||
def set_option(self, name, value):
|
def set_option(self, name, value):
|
||||||
"""Set value of a specific option"""
|
|
||||||
for opt, _, set_func in self.options:
|
for opt, _, set_func in self.options:
|
||||||
if opt == name:
|
if opt == name:
|
||||||
print("Option %s=%s" % (name, value))
|
print("Option %s=%s" % (name, value))
|
||||||
@ -47,14 +38,12 @@ class BaseOption(ABC):
|
|||||||
raise ValueError("unknown")
|
raise ValueError("unknown")
|
||||||
|
|
||||||
def get_option(self, name):
|
def get_option(self, name):
|
||||||
"""Get option value for a specific option"""
|
|
||||||
for opt, get_func, _ in self.options:
|
for opt, get_func, _ in self.options:
|
||||||
if opt == name:
|
if opt == name:
|
||||||
return get_func(name)
|
return get_func(name)
|
||||||
raise ValueError("unknown")
|
raise ValueError("unknown")
|
||||||
|
|
||||||
def get_msr(self):
|
def get_msr(self):
|
||||||
"""Get array of model-specific configuration registers"""
|
|
||||||
return bytes(self.msr)
|
return bytes(self.msr)
|
||||||
|
|
||||||
|
|
||||||
@ -62,7 +51,6 @@ class Stc89Option(BaseOption):
|
|||||||
"""Manipulation STC89 series option byte"""
|
"""Manipulation STC89 series option byte"""
|
||||||
|
|
||||||
def __init__(self, msr):
|
def __init__(self, msr):
|
||||||
super().__init__()
|
|
||||||
self.msr = msr
|
self.msr = msr
|
||||||
self.options = (
|
self.options = (
|
||||||
("cpu_6t_enabled", self.get_t6, self.set_t6),
|
("cpu_6t_enabled", self.get_t6, self.set_t6),
|
||||||
@ -81,7 +69,7 @@ class Stc89Option(BaseOption):
|
|||||||
return not bool(self.msr & 1)
|
return not bool(self.msr & 1)
|
||||||
|
|
||||||
def set_t6(self, val):
|
def set_t6(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr &= 0xfe
|
self.msr &= 0xfe
|
||||||
self.msr |= 0x01 if not bool(val) else 0x00
|
self.msr |= 0x01 if not bool(val) else 0x00
|
||||||
|
|
||||||
@ -89,7 +77,7 @@ class Stc89Option(BaseOption):
|
|||||||
return not bool(self.msr & 4)
|
return not bool(self.msr & 4)
|
||||||
|
|
||||||
def set_pindetect(self, val):
|
def set_pindetect(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr &= 0xfb
|
self.msr &= 0xfb
|
||||||
self.msr |= 0x04 if not bool(val) else 0x00
|
self.msr |= 0x04 if not bool(val) else 0x00
|
||||||
|
|
||||||
@ -97,7 +85,7 @@ class Stc89Option(BaseOption):
|
|||||||
return not bool(self.msr & 8)
|
return not bool(self.msr & 8)
|
||||||
|
|
||||||
def set_ee_erase(self, val):
|
def set_ee_erase(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr &= 0xf7
|
self.msr &= 0xf7
|
||||||
self.msr |= 0x08 if not bool(val) else 0x00
|
self.msr |= 0x08 if not bool(val) else 0x00
|
||||||
|
|
||||||
@ -116,7 +104,7 @@ class Stc89Option(BaseOption):
|
|||||||
return bool(self.msr & 32)
|
return bool(self.msr & 32)
|
||||||
|
|
||||||
def set_ale(self, val):
|
def set_ale(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr &= 0xdf
|
self.msr &= 0xdf
|
||||||
self.msr |= 0x20 if bool(val) else 0x00
|
self.msr |= 0x20 if bool(val) else 0x00
|
||||||
|
|
||||||
@ -124,7 +112,7 @@ class Stc89Option(BaseOption):
|
|||||||
return bool(self.msr & 64)
|
return bool(self.msr & 64)
|
||||||
|
|
||||||
def set_xram(self, val):
|
def set_xram(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr &= 0xbf
|
self.msr &= 0xbf
|
||||||
self.msr |= 0x40 if bool(val) else 0x00
|
self.msr |= 0x40 if bool(val) else 0x00
|
||||||
|
|
||||||
@ -132,7 +120,7 @@ class Stc89Option(BaseOption):
|
|||||||
return not bool(self.msr & 128)
|
return not bool(self.msr & 128)
|
||||||
|
|
||||||
def set_watchdog(self, val):
|
def set_watchdog(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr &= 0x7f
|
self.msr &= 0x7f
|
||||||
self.msr |= 0x80 if not bool(val) else 0x00
|
self.msr |= 0x80 if not bool(val) else 0x00
|
||||||
|
|
||||||
@ -141,7 +129,6 @@ class Stc12AOption(BaseOption):
|
|||||||
"""Manipulate STC12A series option bytes"""
|
"""Manipulate STC12A series option bytes"""
|
||||||
|
|
||||||
def __init__(self, msr):
|
def __init__(self, msr):
|
||||||
super().__init__()
|
|
||||||
assert len(msr) == 4
|
assert len(msr) == 4
|
||||||
self.msr = bytearray(msr)
|
self.msr = bytearray(msr)
|
||||||
|
|
||||||
@ -163,7 +150,7 @@ class Stc12AOption(BaseOption):
|
|||||||
def set_low_voltage_detect(self, val):
|
def set_low_voltage_detect(self, val):
|
||||||
lvds = {"low": 1, "high": 0}
|
lvds = {"low": 1, "high": 0}
|
||||||
if val not in lvds.keys():
|
if val not in lvds.keys():
|
||||||
raise ValueError("must be one of %s" % list(lvds.keys()))
|
raise ValueError("must be one of %s" % list(sources.keys()))
|
||||||
self.msr[3] &= 0xbf
|
self.msr[3] &= 0xbf
|
||||||
self.msr[3] |= lvds[val] << 6
|
self.msr[3] |= lvds[val] << 6
|
||||||
|
|
||||||
@ -182,7 +169,7 @@ class Stc12AOption(BaseOption):
|
|||||||
return not bool(self.msr[1] & 32)
|
return not bool(self.msr[1] & 32)
|
||||||
|
|
||||||
def set_watchdog(self, val):
|
def set_watchdog(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[1] &= 0xdf
|
self.msr[1] &= 0xdf
|
||||||
self.msr[1] |= 0x20 if not val else 0x00
|
self.msr[1] |= 0x20 if not val else 0x00
|
||||||
|
|
||||||
@ -190,7 +177,7 @@ class Stc12AOption(BaseOption):
|
|||||||
return not bool(self.msr[1] & 8)
|
return not bool(self.msr[1] & 8)
|
||||||
|
|
||||||
def set_watchdog_idle(self, val):
|
def set_watchdog_idle(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[1] &= 0xf7
|
self.msr[1] &= 0xf7
|
||||||
self.msr[1] |= 0x08 if not val else 0x00
|
self.msr[1] |= 0x08 if not val else 0x00
|
||||||
|
|
||||||
@ -209,7 +196,7 @@ class Stc12AOption(BaseOption):
|
|||||||
return not bool(self.msr[2] & 2)
|
return not bool(self.msr[2] & 2)
|
||||||
|
|
||||||
def set_ee_erase(self, val):
|
def set_ee_erase(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[2] &= 0xfd
|
self.msr[2] &= 0xfd
|
||||||
self.msr[2] |= 0x02 if not val else 0x00
|
self.msr[2] |= 0x02 if not val else 0x00
|
||||||
|
|
||||||
@ -217,7 +204,7 @@ class Stc12AOption(BaseOption):
|
|||||||
return not bool(self.msr[2] & 1)
|
return not bool(self.msr[2] & 1)
|
||||||
|
|
||||||
def set_pindetect(self, val):
|
def set_pindetect(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[2] &= 0xfe
|
self.msr[2] &= 0xfe
|
||||||
self.msr[2] |= 0x01 if not val else 0x00
|
self.msr[2] |= 0x01 if not val else 0x00
|
||||||
|
|
||||||
@ -226,7 +213,6 @@ class Stc12Option(BaseOption):
|
|||||||
"""Manipulate STC10/11/12 series option bytes"""
|
"""Manipulate STC10/11/12 series option bytes"""
|
||||||
|
|
||||||
def __init__(self, msr):
|
def __init__(self, msr):
|
||||||
super().__init__()
|
|
||||||
assert len(msr) == 4
|
assert len(msr) == 4
|
||||||
self.msr = bytearray(msr)
|
self.msr = bytearray(msr)
|
||||||
|
|
||||||
@ -249,7 +235,7 @@ class Stc12Option(BaseOption):
|
|||||||
return bool(self.msr[0] & 1)
|
return bool(self.msr[0] & 1)
|
||||||
|
|
||||||
def set_reset_pin_enabled(self, val):
|
def set_reset_pin_enabled(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[0] &= 0xfe
|
self.msr[0] &= 0xfe
|
||||||
self.msr[0] |= 0x01 if bool(val) else 0x00
|
self.msr[0] |= 0x01 if bool(val) else 0x00
|
||||||
|
|
||||||
@ -257,7 +243,7 @@ class Stc12Option(BaseOption):
|
|||||||
return not bool(self.msr[0] & 64)
|
return not bool(self.msr[0] & 64)
|
||||||
|
|
||||||
def set_low_voltage_detect(self, val):
|
def set_low_voltage_detect(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[0] &= 0xbf
|
self.msr[0] &= 0xbf
|
||||||
self.msr[0] |= 0x40 if not val else 0x00
|
self.msr[0] |= 0x40 if not val else 0x00
|
||||||
|
|
||||||
@ -309,7 +295,7 @@ class Stc12Option(BaseOption):
|
|||||||
return not bool(self.msr[2] & 32)
|
return not bool(self.msr[2] & 32)
|
||||||
|
|
||||||
def set_watchdog(self, val):
|
def set_watchdog(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[2] &= 0xdf
|
self.msr[2] &= 0xdf
|
||||||
self.msr[2] |= 0x20 if not val else 0x00
|
self.msr[2] |= 0x20 if not val else 0x00
|
||||||
|
|
||||||
@ -317,7 +303,7 @@ class Stc12Option(BaseOption):
|
|||||||
return not bool(self.msr[2] & 8)
|
return not bool(self.msr[2] & 8)
|
||||||
|
|
||||||
def set_watchdog_idle(self, val):
|
def set_watchdog_idle(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[2] &= 0xf7
|
self.msr[2] &= 0xf7
|
||||||
self.msr[2] |= 0x08 if not val else 0x00
|
self.msr[2] |= 0x08 if not val else 0x00
|
||||||
|
|
||||||
@ -336,7 +322,7 @@ class Stc12Option(BaseOption):
|
|||||||
return not bool(self.msr[3] & 2)
|
return not bool(self.msr[3] & 2)
|
||||||
|
|
||||||
def set_ee_erase(self, val):
|
def set_ee_erase(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[3] &= 0xfd
|
self.msr[3] &= 0xfd
|
||||||
self.msr[3] |= 0x02 if not val else 0x00
|
self.msr[3] |= 0x02 if not val else 0x00
|
||||||
|
|
||||||
@ -344,14 +330,13 @@ class Stc12Option(BaseOption):
|
|||||||
return not bool(self.msr[3] & 1)
|
return not bool(self.msr[3] & 1)
|
||||||
|
|
||||||
def set_pindetect(self, val):
|
def set_pindetect(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[3] &= 0xfe
|
self.msr[3] &= 0xfe
|
||||||
self.msr[3] |= 0x01 if not val else 0x00
|
self.msr[3] |= 0x01 if not val else 0x00
|
||||||
|
|
||||||
|
|
||||||
class Stc15AOption(BaseOption):
|
class Stc15AOption(BaseOption):
|
||||||
def __init__(self, msr):
|
def __init__(self, msr):
|
||||||
super().__init__()
|
|
||||||
assert len(msr) == 13
|
assert len(msr) == 13
|
||||||
self.msr = bytearray(msr)
|
self.msr = bytearray(msr)
|
||||||
|
|
||||||
@ -374,7 +359,7 @@ class Stc15AOption(BaseOption):
|
|||||||
return bool(self.msr[0] & 16)
|
return bool(self.msr[0] & 16)
|
||||||
|
|
||||||
def set_reset_pin_enabled(self, val):
|
def set_reset_pin_enabled(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[0] &= 0xef
|
self.msr[0] &= 0xef
|
||||||
self.msr[0] |= 0x10 if bool(val) else 0x00
|
self.msr[0] |= 0x10 if bool(val) else 0x00
|
||||||
|
|
||||||
@ -382,7 +367,7 @@ class Stc15AOption(BaseOption):
|
|||||||
return not bool(self.msr[2] & 32)
|
return not bool(self.msr[2] & 32)
|
||||||
|
|
||||||
def set_watchdog(self, val):
|
def set_watchdog(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[2] &= 0xdf
|
self.msr[2] &= 0xdf
|
||||||
self.msr[2] |= 0x20 if not val else 0x00
|
self.msr[2] |= 0x20 if not val else 0x00
|
||||||
|
|
||||||
@ -390,7 +375,7 @@ class Stc15AOption(BaseOption):
|
|||||||
return not bool(self.msr[2] & 8)
|
return not bool(self.msr[2] & 8)
|
||||||
|
|
||||||
def set_watchdog_idle(self, val):
|
def set_watchdog_idle(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[2] &= 0xf7
|
self.msr[2] &= 0xf7
|
||||||
self.msr[2] |= 0x08 if not val else 0x00
|
self.msr[2] |= 0x08 if not val else 0x00
|
||||||
|
|
||||||
@ -409,7 +394,7 @@ class Stc15AOption(BaseOption):
|
|||||||
return bool(self.msr[1] & 64)
|
return bool(self.msr[1] & 64)
|
||||||
|
|
||||||
def set_lvrs(self, val):
|
def set_lvrs(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[1] &= 0xbf
|
self.msr[1] &= 0xbf
|
||||||
self.msr[1] |= 0x40 if val else 0x00
|
self.msr[1] |= 0x40 if val else 0x00
|
||||||
|
|
||||||
@ -417,7 +402,7 @@ class Stc15AOption(BaseOption):
|
|||||||
return bool(self.msr[1] & 128)
|
return bool(self.msr[1] & 128)
|
||||||
|
|
||||||
def set_eeprom_lvd(self, val):
|
def set_eeprom_lvd(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[1] &= 0x7f
|
self.msr[1] &= 0x7f
|
||||||
self.msr[1] |= 0x80 if val else 0x00
|
self.msr[1] |= 0x80 if val else 0x00
|
||||||
|
|
||||||
@ -435,7 +420,7 @@ class Stc15AOption(BaseOption):
|
|||||||
return not bool(self.msr[12] & 2)
|
return not bool(self.msr[12] & 2)
|
||||||
|
|
||||||
def set_ee_erase(self, val):
|
def set_ee_erase(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[12] &= 0xfd
|
self.msr[12] &= 0xfd
|
||||||
self.msr[12] |= 0x02 if not val else 0x00
|
self.msr[12] |= 0x02 if not val else 0x00
|
||||||
|
|
||||||
@ -443,14 +428,13 @@ class Stc15AOption(BaseOption):
|
|||||||
return not bool(self.msr[12] & 1)
|
return not bool(self.msr[12] & 1)
|
||||||
|
|
||||||
def set_pindetect(self, val):
|
def set_pindetect(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[12] &= 0xfe
|
self.msr[12] &= 0xfe
|
||||||
self.msr[12] |= 0x01 if not val else 0x00
|
self.msr[12] |= 0x01 if not val else 0x00
|
||||||
|
|
||||||
|
|
||||||
class Stc15Option(BaseOption):
|
class Stc15Option(BaseOption):
|
||||||
def __init__(self, msr):
|
def __init__(self, msr):
|
||||||
super().__init__()
|
|
||||||
assert len(msr) >= 4
|
assert len(msr) >= 4
|
||||||
self.msr = bytearray(msr)
|
self.msr = bytearray(msr)
|
||||||
|
|
||||||
@ -473,13 +457,13 @@ class Stc15Option(BaseOption):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if len(msr) > 4:
|
if len(msr) > 4:
|
||||||
self.options += (("cpu_core_voltage", self.get_core_voltage, self.set_core_voltage),)
|
self.options += ("cpu_core_voltage", self.get_core_voltage, self.set_core_voltage),
|
||||||
|
|
||||||
def get_reset_pin_enabled(self):
|
def get_reset_pin_enabled(self):
|
||||||
return not bool(self.msr[2] & 16)
|
return not bool(self.msr[2] & 16)
|
||||||
|
|
||||||
def set_reset_pin_enabled(self, val):
|
def set_reset_pin_enabled(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[2] &= 0xef
|
self.msr[2] &= 0xef
|
||||||
self.msr[2] |= 0x10 if not bool(val) else 0x00
|
self.msr[2] |= 0x10 if not bool(val) else 0x00
|
||||||
|
|
||||||
@ -509,7 +493,7 @@ class Stc15Option(BaseOption):
|
|||||||
return not bool(self.msr[0] & 32)
|
return not bool(self.msr[0] & 32)
|
||||||
|
|
||||||
def set_watchdog(self, val):
|
def set_watchdog(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[0] &= 0xdf
|
self.msr[0] &= 0xdf
|
||||||
self.msr[0] |= 0x20 if not val else 0x00
|
self.msr[0] |= 0x20 if not val else 0x00
|
||||||
|
|
||||||
@ -517,7 +501,7 @@ class Stc15Option(BaseOption):
|
|||||||
return not bool(self.msr[0] & 8)
|
return not bool(self.msr[0] & 8)
|
||||||
|
|
||||||
def set_watchdog_idle(self, val):
|
def set_watchdog_idle(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[0] &= 0xf7
|
self.msr[0] &= 0xf7
|
||||||
self.msr[0] |= 0x08 if not val else 0x00
|
self.msr[0] |= 0x08 if not val else 0x00
|
||||||
|
|
||||||
@ -536,7 +520,7 @@ class Stc15Option(BaseOption):
|
|||||||
return not bool(self.msr[1] & 64)
|
return not bool(self.msr[1] & 64)
|
||||||
|
|
||||||
def set_lvrs(self, val):
|
def set_lvrs(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[1] &= 0xbf
|
self.msr[1] &= 0xbf
|
||||||
self.msr[1] |= 0x40 if not val else 0x00
|
self.msr[1] |= 0x40 if not val else 0x00
|
||||||
|
|
||||||
@ -544,7 +528,7 @@ class Stc15Option(BaseOption):
|
|||||||
return bool(self.msr[1] & 128)
|
return bool(self.msr[1] & 128)
|
||||||
|
|
||||||
def set_eeprom_lvd(self, val):
|
def set_eeprom_lvd(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[1] &= 0x7f
|
self.msr[1] &= 0x7f
|
||||||
self.msr[1] |= 0x80 if val else 0x00
|
self.msr[1] |= 0x80 if val else 0x00
|
||||||
|
|
||||||
@ -562,7 +546,7 @@ class Stc15Option(BaseOption):
|
|||||||
return bool(self.msr[3] & 2)
|
return bool(self.msr[3] & 2)
|
||||||
|
|
||||||
def set_ee_erase(self, val):
|
def set_ee_erase(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[3] &= 0xfd
|
self.msr[3] &= 0xfd
|
||||||
self.msr[3] |= 0x02 if val else 0x00
|
self.msr[3] |= 0x02 if val else 0x00
|
||||||
|
|
||||||
@ -570,7 +554,7 @@ class Stc15Option(BaseOption):
|
|||||||
return not bool(self.msr[3] & 1)
|
return not bool(self.msr[3] & 1)
|
||||||
|
|
||||||
def set_pindetect(self, val):
|
def set_pindetect(self, val):
|
||||||
val = Utils.to_bool(val)
|
val = Utils.to_bool(val);
|
||||||
self.msr[3] &= 0xfe
|
self.msr[3] &= 0xfe
|
||||||
self.msr[3] |= 0x01 if not val else 0x00
|
self.msr[3] |= 0x01 if not val else 0x00
|
||||||
|
|
||||||
@ -615,177 +599,10 @@ class Stc15Option(BaseOption):
|
|||||||
if self.msr[4] == 0xea: return "low"
|
if self.msr[4] == 0xea: return "low"
|
||||||
elif self.msr[4] == 0xf7: return "mid"
|
elif self.msr[4] == 0xf7: return "mid"
|
||||||
elif self.msr[4] == 0xfd: return "high"
|
elif self.msr[4] == 0xfd: return "high"
|
||||||
return "unknown"
|
else: return "unknown"
|
||||||
|
|
||||||
def set_core_voltage(self, val):
|
def set_core_voltage(self, val):
|
||||||
volt_vals = {"low": 0xea, "mid": 0xf7, "high": 0xfd}
|
volt_vals = {"low": 0xea, "mid": 0xf7, "high": 0xfd}
|
||||||
if val not in volt_vals.keys():
|
if val not in volt_vals.keys():
|
||||||
raise ValueError("must be one of %s" % list(volt_vals.keys()))
|
raise ValueError("must be one of %s" % list(volt_vals.keys()))
|
||||||
self.msr[4] = volt_vals[val]
|
self.msr[4] = volt_vals[val]
|
||||||
|
|
||||||
class Stc8Option(BaseOption):
|
|
||||||
def __init__(self, msr):
|
|
||||||
super().__init__()
|
|
||||||
assert len(msr) >= 5
|
|
||||||
self.msr = bytearray(msr)
|
|
||||||
|
|
||||||
self.options = (
|
|
||||||
("reset_pin_enabled", self.get_reset_pin_enabled, self.set_reset_pin_enabled),
|
|
||||||
("clock_gain", self.get_clock_gain, self.set_clock_gain),
|
|
||||||
("watchdog_por_enabled", self.get_watchdog, self.set_watchdog),
|
|
||||||
("watchdog_stop_idle", self.get_watchdog_idle, self.set_watchdog_idle),
|
|
||||||
("watchdog_prescale", self.get_watchdog_prescale, self.set_watchdog_prescale),
|
|
||||||
("low_voltage_reset", self.get_lvrs, self.set_lvrs),
|
|
||||||
("low_voltage_threshold", self.get_low_voltage, self.set_low_voltage),
|
|
||||||
("eeprom_erase_enabled", self.get_ee_erase, self.set_ee_erase),
|
|
||||||
("bsl_pindetect_enabled", self.get_pindetect, self.set_pindetect),
|
|
||||||
("por_reset_delay", self.get_por_delay, self.set_por_delay),
|
|
||||||
("rstout_por_state", self.get_p20_state, self.set_p20_state),
|
|
||||||
("uart1_remap", self.get_uart1_remap, self.set_uart1_remap),
|
|
||||||
("uart2_passthrough", self.get_uart_passthrough, self.set_uart_passthrough),
|
|
||||||
("uart2_pin_mode", self.get_uart_pin_mode, self.set_uart_pin_mode),
|
|
||||||
("epwm_open_drain", self.get_epwm_pp, self.set_epwm_pp),
|
|
||||||
("program_eeprom_split", self.get_flash_split, self.set_flash_split),
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_reset_pin_enabled(self):
|
|
||||||
return not bool(self.msr[2] & 16)
|
|
||||||
|
|
||||||
def set_reset_pin_enabled(self, val):
|
|
||||||
val = Utils.to_bool(val)
|
|
||||||
self.msr[2] &= 0xef
|
|
||||||
self.msr[2] |= 0x10 if not bool(val) else 0x00
|
|
||||||
|
|
||||||
def get_clock_gain(self):
|
|
||||||
gain = bool(self.msr[1] & 0x02)
|
|
||||||
return "high" if gain else "low"
|
|
||||||
|
|
||||||
def set_clock_gain(self, val):
|
|
||||||
gains = {"low": 0, "high": 1}
|
|
||||||
if val not in gains.keys():
|
|
||||||
raise ValueError("must be one of %s" % list(gains.keys()))
|
|
||||||
self.msr[1] &= 0xfd
|
|
||||||
self.msr[1] |= gains[val] << 1
|
|
||||||
|
|
||||||
def get_watchdog(self):
|
|
||||||
return not bool(self.msr[3] & 32)
|
|
||||||
|
|
||||||
def set_watchdog(self, val):
|
|
||||||
val = Utils.to_bool(val)
|
|
||||||
self.msr[3] &= 0xdf
|
|
||||||
self.msr[3] |= 0x20 if not val else 0x00
|
|
||||||
|
|
||||||
def get_watchdog_idle(self):
|
|
||||||
return not bool(self.msr[3] & 8)
|
|
||||||
|
|
||||||
def set_watchdog_idle(self, val):
|
|
||||||
val = Utils.to_bool(val)
|
|
||||||
self.msr[3] &= 0xf7
|
|
||||||
self.msr[3] |= 0x08 if not val else 0x00
|
|
||||||
|
|
||||||
def get_watchdog_prescale(self):
|
|
||||||
return 2 ** (((self.msr[3]) & 0x07) + 1)
|
|
||||||
|
|
||||||
def set_watchdog_prescale(self, val):
|
|
||||||
val = Utils.to_int(val)
|
|
||||||
wd_vals = {2: 0, 4: 1, 8: 2, 16: 3, 32: 4, 64: 5, 128: 6, 256: 7}
|
|
||||||
if val not in wd_vals.keys():
|
|
||||||
raise ValueError("must be one of %s" % list(wd_vals.keys()))
|
|
||||||
self.msr[3] &= 0xf8
|
|
||||||
self.msr[3] |= wd_vals[val]
|
|
||||||
|
|
||||||
def get_lvrs(self):
|
|
||||||
return not bool(self.msr[2] & 64)
|
|
||||||
|
|
||||||
def set_lvrs(self, val):
|
|
||||||
val = Utils.to_bool(val)
|
|
||||||
self.msr[2] &= 0xbf
|
|
||||||
self.msr[2] |= 0x40 if not val else 0x00
|
|
||||||
|
|
||||||
def get_low_voltage(self):
|
|
||||||
return 3 - self.msr[2] & 0x03
|
|
||||||
|
|
||||||
def set_low_voltage(self, val):
|
|
||||||
val = Utils.to_int(val)
|
|
||||||
if val not in range(0, 4):
|
|
||||||
raise ValueError("must be one of %s" % list(range(0, 4)))
|
|
||||||
self.msr[2] &= 0xfc
|
|
||||||
self.msr[2] |= 3 - val
|
|
||||||
|
|
||||||
def get_ee_erase(self):
|
|
||||||
return bool(self.msr[0] & 2)
|
|
||||||
|
|
||||||
def set_ee_erase(self, val):
|
|
||||||
val = Utils.to_bool(val)
|
|
||||||
self.msr[0] &= 0xfd
|
|
||||||
self.msr[0] |= 0x02 if val else 0x00
|
|
||||||
|
|
||||||
def get_pindetect(self):
|
|
||||||
return not bool(self.msr[0] & 1)
|
|
||||||
|
|
||||||
def set_pindetect(self, val):
|
|
||||||
val = Utils.to_bool(val)
|
|
||||||
self.msr[0] &= 0xfe
|
|
||||||
self.msr[0] |= 0x01 if not val else 0x00
|
|
||||||
|
|
||||||
def get_por_delay(self):
|
|
||||||
delay = bool(self.msr[1] & 128)
|
|
||||||
return "long" if delay else "short"
|
|
||||||
|
|
||||||
def set_por_delay(self, val):
|
|
||||||
delays = {"short": 0, "long": 1}
|
|
||||||
if val not in delays.keys():
|
|
||||||
raise ValueError("must be one of %s" % list(delays.keys()))
|
|
||||||
self.msr[1] &= 0x7f
|
|
||||||
self.msr[1] |= delays[val] << 7
|
|
||||||
|
|
||||||
def get_p20_state(self):
|
|
||||||
return "high" if self.msr[1] & 0x08 else "low"
|
|
||||||
|
|
||||||
def set_p20_state(self, val):
|
|
||||||
val = Utils.to_bool(val)
|
|
||||||
self.msr[1] &= 0xf7
|
|
||||||
self.msr[1] |= 0x08 if val else 0x00
|
|
||||||
|
|
||||||
def get_uart_passthrough(self):
|
|
||||||
return bool(self.msr[1] & 0x10)
|
|
||||||
|
|
||||||
def set_uart_passthrough(self, val):
|
|
||||||
val = Utils.to_bool(val)
|
|
||||||
self.msr[1] &= 0xef
|
|
||||||
self.msr[1] |= 0x10 if val else 0x00
|
|
||||||
|
|
||||||
def get_uart_pin_mode(self):
|
|
||||||
return "push-pull" if bool(self.msr[1] & 0x20) else "normal"
|
|
||||||
|
|
||||||
def set_uart_pin_mode(self, val):
|
|
||||||
modes = {"normal": 0, "push-pull": 1}
|
|
||||||
if val not in modes.keys():
|
|
||||||
raise ValueError("must be one of %s" % list(modes.keys()))
|
|
||||||
self.msr[1] &= 0xdf
|
|
||||||
self.msr[1] |= 0x20 if modes[val] else 0x00
|
|
||||||
|
|
||||||
def get_epwm_pp(self):
|
|
||||||
return bool(self.msr[1] & 0x04)
|
|
||||||
|
|
||||||
def set_epwm_pp(self, val):
|
|
||||||
val = Utils.to_bool(val)
|
|
||||||
self.msr[1] &= 0xfb
|
|
||||||
self.msr[1] |= 0x04 if val else 0x00
|
|
||||||
|
|
||||||
def get_uart1_remap(self):
|
|
||||||
return bool(self.msr[1] & 0x40)
|
|
||||||
|
|
||||||
def set_uart1_remap(self, val):
|
|
||||||
val = Utils.to_bool(val)
|
|
||||||
self.msr[1] &= 0xbf
|
|
||||||
self.msr[1] |= 0x40 if val else 0x00
|
|
||||||
|
|
||||||
def get_flash_split(self):
|
|
||||||
return self.msr[4] * 256
|
|
||||||
|
|
||||||
def set_flash_split(self, val):
|
|
||||||
num_val = Utils.to_int(val)
|
|
||||||
if num_val < 512 or num_val > 65024 or (num_val % 512) != 0:
|
|
||||||
raise ValueError("must be between 512 and 65024 bytes and a multiple of 512 bytes")
|
|
||||||
self.msr[4] = num_val // 256
|
|
@ -21,28 +21,16 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import serial
|
import serial
|
||||||
import sys
|
import sys, os, time, struct, re, errno
|
||||||
import os
|
import argparse
|
||||||
import time
|
import collections
|
||||||
import struct
|
|
||||||
import re
|
|
||||||
import errno
|
|
||||||
from stcgal.models import MCUModelDatabase
|
from stcgal.models import MCUModelDatabase
|
||||||
from stcgal.utils import Utils
|
from stcgal.utils import Utils
|
||||||
from stcgal.options import Stc89Option
|
from stcgal.options import *
|
||||||
from stcgal.options import Stc12Option
|
|
||||||
from stcgal.options import Stc12AOption
|
|
||||||
from stcgal.options import Stc15Option
|
|
||||||
from stcgal.options import Stc15AOption
|
|
||||||
from stcgal.options import Stc8Option
|
|
||||||
from abc import ABC
|
|
||||||
from abc import abstractmethod
|
|
||||||
import functools
|
import functools
|
||||||
import tqdm
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import usb.core
|
import usb.core, usb.util
|
||||||
import usb.util
|
|
||||||
_usb_available = True
|
_usb_available = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
_usb_available = False
|
_usb_available = False
|
||||||
@ -58,23 +46,22 @@ class StcProtocolException(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class StcBaseProtocol(ABC):
|
class StcBaseProtocol:
|
||||||
"""Basic functionality for STC BSL protocols"""
|
"""Basic functionality for STC BSL protocols"""
|
||||||
|
|
||||||
PACKET_START = bytes([0x46, 0xb9])
|
|
||||||
"""magic word that starts a packet"""
|
"""magic word that starts a packet"""
|
||||||
|
PACKET_START = bytes([0x46, 0xb9])
|
||||||
|
|
||||||
PACKET_END = bytes([0x16])
|
|
||||||
"""magic byte that ends a packet"""
|
"""magic byte that ends a packet"""
|
||||||
|
PACKET_END = bytes([0x16])
|
||||||
|
|
||||||
PACKET_MCU = bytes([0x68])
|
|
||||||
"""magic byte for packets received from MCU"""
|
"""magic byte for packets received from MCU"""
|
||||||
|
PACKET_MCU = bytes([0x68])
|
||||||
|
|
||||||
PACKET_HOST = bytes([0x6a])
|
|
||||||
"""magic byte for packets sent by host"""
|
"""magic byte for packets sent by host"""
|
||||||
|
PACKET_HOST = bytes([0x6a])
|
||||||
|
|
||||||
PARITY = serial.PARITY_NONE
|
PARITY = serial.PARITY_NONE
|
||||||
"""parity configuration for serial communication"""
|
|
||||||
|
|
||||||
def __init__(self, port, baud_handshake, baud_transfer):
|
def __init__(self, port, baud_handshake, baud_transfer):
|
||||||
self.port = port
|
self.port = port
|
||||||
@ -90,22 +77,6 @@ class StcBaseProtocol(ABC):
|
|||||||
self.debug = False
|
self.debug = False
|
||||||
self.status_packet = None
|
self.status_packet = None
|
||||||
self.protocol_name = None
|
self.protocol_name = None
|
||||||
self.progress = None
|
|
||||||
self.progress_cb = self.progress_bar_cb
|
|
||||||
|
|
||||||
def progress_text_cb(self, current, written, maximum):
|
|
||||||
print(current, written, maximum)
|
|
||||||
|
|
||||||
def progress_bar_cb(self, current, written, maximum):
|
|
||||||
if not self.progress:
|
|
||||||
self.progress = tqdm.tqdm(
|
|
||||||
total = maximum,
|
|
||||||
unit = " Bytes",
|
|
||||||
desc = "Writing flash"
|
|
||||||
)
|
|
||||||
self.progress.update(written)
|
|
||||||
if current == maximum:
|
|
||||||
self.progress.close()
|
|
||||||
|
|
||||||
def dump_packet(self, data, receive=True):
|
def dump_packet(self, data, receive=True):
|
||||||
if self.debug:
|
if self.debug:
|
||||||
@ -132,10 +103,6 @@ class StcBaseProtocol(ABC):
|
|||||||
|
|
||||||
return packet[5:-1]
|
return packet[5:-1]
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def write_packet(self, packet_data):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def read_packet(self):
|
def read_packet(self):
|
||||||
"""Read and check packet from MCU.
|
"""Read and check packet from MCU.
|
||||||
|
|
||||||
@ -175,7 +142,7 @@ class StcBaseProtocol(ABC):
|
|||||||
packet += self.read_bytes_safe(packet_len - 3)
|
packet += self.read_bytes_safe(packet_len - 3)
|
||||||
|
|
||||||
# verify checksum and extract payload
|
# verify checksum and extract payload
|
||||||
payload = self.extract_payload(packet)
|
payload = self.extract_payload(packet);
|
||||||
|
|
||||||
self.dump_packet(packet, receive=True)
|
self.dump_packet(packet, receive=True)
|
||||||
|
|
||||||
@ -225,6 +192,20 @@ class StcBaseProtocol(ABC):
|
|||||||
mcu_name += "E" if self.status_packet[17] < 0x70 else "W"
|
mcu_name += "E" if self.status_packet[17] < 0x70 else "W"
|
||||||
self.model = self.model._replace(name = mcu_name)
|
self.model = self.model._replace(name = mcu_name)
|
||||||
|
|
||||||
|
protocol_database = [("stc89", "STC(89|90)(C|LE)\d"),
|
||||||
|
("stc12a", "STC12(C|LE)\d052"),
|
||||||
|
("stc12b", "STC12(C|LE)(52|56)"),
|
||||||
|
("stc12", "(STC|IAP)(10|11|12)\D"),
|
||||||
|
("stc15a", "(STC|IAP)15[FL][01]0\d(E|EA|)$"),
|
||||||
|
("stc15", "(STC|IAP|IRC)15\D")]
|
||||||
|
|
||||||
|
for protocol_name, pattern in protocol_database:
|
||||||
|
if re.match(pattern, self.model.name):
|
||||||
|
self.protocol_name = protocol_name
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.protocol_name = None
|
||||||
|
|
||||||
def get_status_packet(self):
|
def get_status_packet(self):
|
||||||
"""Read and decode status packet"""
|
"""Read and decode status packet"""
|
||||||
|
|
||||||
@ -260,22 +241,7 @@ class StcBaseProtocol(ABC):
|
|||||||
def set_option(self, name, value):
|
def set_option(self, name, value):
|
||||||
self.options.set_option(name, value)
|
self.options.set_option(name, value)
|
||||||
|
|
||||||
def reset_device(self, resetcmd=False):
|
def connect(self, autoreset=False):
|
||||||
if not resetcmd:
|
|
||||||
print("Cycling power: ", end="")
|
|
||||||
sys.stdout.flush()
|
|
||||||
self.ser.setDTR(True)
|
|
||||||
time.sleep(0.5)
|
|
||||||
self.ser.setDTR(False)
|
|
||||||
print("done")
|
|
||||||
else:
|
|
||||||
print("Cycling power via shell cmd: " + resetcmd)
|
|
||||||
os.system(resetcmd)
|
|
||||||
|
|
||||||
print("Waiting for MCU: ", end="")
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
def connect(self, autoreset=False, resetcmd=False):
|
|
||||||
"""Connect to MCU and initialize communication.
|
"""Connect to MCU and initialize communication.
|
||||||
|
|
||||||
Set up serial port, send sync sequence and get part info.
|
Set up serial port, send sync sequence and get part info.
|
||||||
@ -294,7 +260,14 @@ class StcBaseProtocol(ABC):
|
|||||||
self.ser.flushInput()
|
self.ser.flushInput()
|
||||||
|
|
||||||
if autoreset:
|
if autoreset:
|
||||||
self.reset_device(resetcmd)
|
print("Cycling power: ", end="")
|
||||||
|
sys.stdout.flush()
|
||||||
|
self.ser.setDTR(True)
|
||||||
|
time.sleep(0.5)
|
||||||
|
self.ser.setDTR(False)
|
||||||
|
print("done")
|
||||||
|
print("Waiting for MCU: ", end="")
|
||||||
|
sys.stdout.flush()
|
||||||
else:
|
else:
|
||||||
print("Waiting for MCU, please cycle power: ", end="")
|
print("Waiting for MCU, please cycle power: ", end="")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
@ -306,8 +279,6 @@ class StcBaseProtocol(ABC):
|
|||||||
try:
|
try:
|
||||||
self.pulse()
|
self.pulse()
|
||||||
self.status_packet = self.get_status_packet()
|
self.status_packet = self.get_status_packet()
|
||||||
if len(self.status_packet) < 23:
|
|
||||||
raise StcProtocolException("status packet too short")
|
|
||||||
except (StcFramingException, serial.SerialTimeoutException): pass
|
except (StcFramingException, serial.SerialTimeoutException): pass
|
||||||
print("done")
|
print("done")
|
||||||
|
|
||||||
@ -317,21 +288,7 @@ class StcBaseProtocol(ABC):
|
|||||||
|
|
||||||
self.initialize_model()
|
self.initialize_model()
|
||||||
|
|
||||||
@abstractmethod
|
def initialize(self, base_protocol = None):
|
||||||
def initialize_status(self, status_packet):
|
|
||||||
"""Initialize internal state from status packet"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def initialize_options(self, status_packet):
|
|
||||||
"""Initialize options from status packet"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def initialize(self, base_protocol=None):
|
|
||||||
"""
|
|
||||||
Initialize from another instance. This is an alternative for calling
|
|
||||||
connect() and is used by protocol autodetection.
|
|
||||||
"""
|
|
||||||
if base_protocol:
|
if base_protocol:
|
||||||
self.ser = base_protocol.ser
|
self.ser = base_protocol.ser
|
||||||
self.ser.parity = self.PARITY
|
self.ser.parity = self.PARITY
|
||||||
@ -359,48 +316,14 @@ class StcBaseProtocol(ABC):
|
|||||||
print("Disconnected!")
|
print("Disconnected!")
|
||||||
|
|
||||||
|
|
||||||
class StcAutoProtocol(StcBaseProtocol):
|
|
||||||
"""
|
|
||||||
Protocol handler for autodetection of protocols. Does not implement full
|
|
||||||
functionality for any device class.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def initialize_model(self):
|
|
||||||
super().initialize_model()
|
|
||||||
|
|
||||||
protocol_database = [("stc89", r"STC(89|90)(C|LE)\d"),
|
|
||||||
("stc12a", r"STC12(C|LE)\d052"),
|
|
||||||
("stc12b", r"STC12(C|LE)(52|56)"),
|
|
||||||
("stc12", r"(STC|IAP)(10|11|12)\D"),
|
|
||||||
("stc15a", r"(STC|IAP)15[FL][012]0\d(E|EA|)$"),
|
|
||||||
("stc15", r"(STC|IAP|IRC)15\D"),
|
|
||||||
("stc8", r"(STC|IAP|IRC)8")]
|
|
||||||
|
|
||||||
for protocol_name, pattern in protocol_database:
|
|
||||||
if re.match(pattern, self.model.name):
|
|
||||||
self.protocol_name = protocol_name
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
self.protocol_name = None
|
|
||||||
|
|
||||||
def initialize_options(self, status_packet):
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def initialize_status(self, status_packet):
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def write_packet(self, packet_data):
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
|
|
||||||
class Stc89Protocol(StcBaseProtocol):
|
class Stc89Protocol(StcBaseProtocol):
|
||||||
"""Protocol handler for STC 89/90 series"""
|
"""Protocol handler for STC 89/90 series"""
|
||||||
|
|
||||||
|
"""These don't use any parity"""
|
||||||
PARITY = serial.PARITY_NONE
|
PARITY = serial.PARITY_NONE
|
||||||
"""Parity configuration - these don't use any parity"""
|
|
||||||
|
|
||||||
PROGRAM_BLOCKSIZE = 128
|
|
||||||
"""block size for programming flash"""
|
"""block size for programming flash"""
|
||||||
|
PROGRAM_BLOCKSIZE = 128
|
||||||
|
|
||||||
def __init__(self, port, baud_handshake, baud_transfer):
|
def __init__(self, port, baud_handshake, baud_transfer):
|
||||||
StcBaseProtocol.__init__(self, port, baud_handshake, baud_transfer)
|
StcBaseProtocol.__init__(self, port, baud_handshake, baud_transfer)
|
||||||
@ -419,7 +342,7 @@ class Stc89Protocol(StcBaseProtocol):
|
|||||||
payload = StcBaseProtocol.extract_payload(self, packet)
|
payload = StcBaseProtocol.extract_payload(self, packet)
|
||||||
return payload[:-1]
|
return payload[:-1]
|
||||||
|
|
||||||
def write_packet(self, packet_data):
|
def write_packet(self, data):
|
||||||
"""Send packet to MCU.
|
"""Send packet to MCU.
|
||||||
|
|
||||||
Constructs a packet with supplied payload and sends it to the MCU.
|
Constructs a packet with supplied payload and sends it to the MCU.
|
||||||
@ -431,8 +354,8 @@ class Stc89Protocol(StcBaseProtocol):
|
|||||||
packet += self.PACKET_HOST
|
packet += self.PACKET_HOST
|
||||||
|
|
||||||
# packet length and payload
|
# packet length and payload
|
||||||
packet += struct.pack(">H", len(packet_data) + 5)
|
packet += struct.pack(">H", len(data) + 5)
|
||||||
packet += packet_data
|
packet += data
|
||||||
|
|
||||||
# checksum and end code
|
# checksum and end code
|
||||||
packet += bytes([sum(packet[2:]) & 0xff])
|
packet += bytes([sum(packet[2:]) & 0xff])
|
||||||
@ -453,9 +376,6 @@ class Stc89Protocol(StcBaseProtocol):
|
|||||||
def initialize_options(self, status_packet):
|
def initialize_options(self, status_packet):
|
||||||
"""Initialize options"""
|
"""Initialize options"""
|
||||||
|
|
||||||
if len(status_packet) < 20:
|
|
||||||
raise StcProtocolException("invalid options in status packet")
|
|
||||||
|
|
||||||
self.options = Stc89Option(status_packet[19])
|
self.options = Stc89Option(status_packet[19])
|
||||||
self.options.print()
|
self.options.print()
|
||||||
|
|
||||||
@ -488,21 +408,21 @@ class Stc89Protocol(StcBaseProtocol):
|
|||||||
|
|
||||||
return brt, brt_csum, iap_wait, delay
|
return brt, brt_csum, iap_wait, delay
|
||||||
|
|
||||||
def initialize_status(self, status_packet):
|
def initialize_status(self, packet):
|
||||||
"""Decode status packet and store basic MCU info"""
|
"""Decode status packet and store basic MCU info"""
|
||||||
|
|
||||||
self.cpu_6t = not bool(status_packet[19] & 1)
|
self.cpu_6t = not bool(packet[19] & 1)
|
||||||
|
|
||||||
cpu_t = 6.0 if self.cpu_6t else 12.0
|
cpu_t = 6.0 if self.cpu_6t else 12.0
|
||||||
freq_counter = 0
|
freq_counter = 0
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
freq_counter += struct.unpack(">H", status_packet[1+2*i:3+2*i])[0]
|
freq_counter += struct.unpack(">H", packet[1+2*i:3+2*i])[0]
|
||||||
freq_counter /= 8.0
|
freq_counter /= 8.0
|
||||||
self.mcu_clock_hz = (self.baud_handshake * freq_counter * cpu_t) / 7.0
|
self.mcu_clock_hz = (self.baud_handshake * freq_counter * cpu_t) / 7.0
|
||||||
|
|
||||||
bl_version, bl_stepping = struct.unpack("BB", status_packet[17:19])
|
bl_version, bl_stepping = struct.unpack("BB", packet[17:19])
|
||||||
self.mcu_bsl_version = "%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
|
self.mcu_bsl_version = "%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
|
||||||
chr(bl_stepping))
|
chr(bl_stepping))
|
||||||
|
|
||||||
def handshake(self):
|
def handshake(self):
|
||||||
"""Switch to transfer baudrate
|
"""Switch to transfer baudrate
|
||||||
@ -545,7 +465,7 @@ class Stc89Protocol(StcBaseProtocol):
|
|||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
packet = bytes([0x80, 0x00, 0x00, 0x36, 0x01])
|
packet = bytes([0x80, 0x00, 0x00, 0x36, 0x01])
|
||||||
packet += struct.pack(">H", self.mcu_magic)
|
packet += struct.pack(">H", self.mcu_magic)
|
||||||
for _ in range(4):
|
for i in range(4):
|
||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if response[0] != 0x80:
|
if response[0] != 0x80:
|
||||||
@ -553,7 +473,7 @@ class Stc89Protocol(StcBaseProtocol):
|
|||||||
|
|
||||||
print("done")
|
print("done")
|
||||||
|
|
||||||
def erase_flash(self, erase_size, _):
|
def erase_flash(self, erase_size, flash_size):
|
||||||
"""Erase the MCU's flash memory.
|
"""Erase the MCU's flash memory.
|
||||||
|
|
||||||
Erase the flash memory with a block-erase command.
|
Erase the flash memory with a block-erase command.
|
||||||
@ -577,6 +497,8 @@ class Stc89Protocol(StcBaseProtocol):
|
|||||||
as the block size (depends on MCU's RAM size).
|
as the block size (depends on MCU's RAM size).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
print("Writing %d bytes: " % len(data), end="")
|
||||||
|
sys.stdout.flush()
|
||||||
for i in range(0, len(data), self.PROGRAM_BLOCKSIZE):
|
for i in range(0, len(data), self.PROGRAM_BLOCKSIZE):
|
||||||
packet = bytes(3)
|
packet = bytes(3)
|
||||||
packet += struct.pack(">H", i)
|
packet += struct.pack(">H", i)
|
||||||
@ -586,12 +508,13 @@ class Stc89Protocol(StcBaseProtocol):
|
|||||||
csum = sum(packet[7:]) & 0xff
|
csum = sum(packet[7:]) & 0xff
|
||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if len(response) < 1 or response[0] != 0x80:
|
if response[0] != 0x80:
|
||||||
raise StcProtocolException("incorrect magic in write packet")
|
raise StcProtocolException("incorrect magic in write packet")
|
||||||
elif len(response) < 2 or response[1] != csum:
|
elif response[1] != csum:
|
||||||
raise StcProtocolException("verification checksum mismatch")
|
raise StcProtocolException("verification checksum mismatch")
|
||||||
self.progress_cb(i, self.PROGRAM_BLOCKSIZE, len(data))
|
print(".", end="")
|
||||||
self.progress_cb(len(data), self.PROGRAM_BLOCKSIZE, len(data))
|
sys.stdout.flush()
|
||||||
|
print(" done")
|
||||||
|
|
||||||
def program_options(self):
|
def program_options(self):
|
||||||
"""Program option byte into flash"""
|
"""Program option byte into flash"""
|
||||||
@ -645,18 +568,18 @@ class Stc12AProtocol(Stc12AOptionsMixIn, Stc89Protocol):
|
|||||||
def __init__(self, port, baud_handshake, baud_transfer):
|
def __init__(self, port, baud_handshake, baud_transfer):
|
||||||
Stc89Protocol.__init__(self, port, baud_handshake, baud_transfer)
|
Stc89Protocol.__init__(self, port, baud_handshake, baud_transfer)
|
||||||
|
|
||||||
def initialize_status(self, status_packet):
|
def initialize_status(self, packet):
|
||||||
"""Decode status packet and store basic MCU info"""
|
"""Decode status packet and store basic MCU info"""
|
||||||
|
|
||||||
freq_counter = 0
|
freq_counter = 0
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
freq_counter += struct.unpack(">H", status_packet[1+2*i:3+2*i])[0]
|
freq_counter += struct.unpack(">H", packet[1+2*i:3+2*i])[0]
|
||||||
freq_counter /= 8.0
|
freq_counter /= 8.0
|
||||||
self.mcu_clock_hz = (self.baud_handshake * freq_counter * 12.0) / 7.0
|
self.mcu_clock_hz = (self.baud_handshake * freq_counter * 12.0) / 7.0
|
||||||
|
|
||||||
bl_version, bl_stepping = struct.unpack("BB", status_packet[17:19])
|
bl_version, bl_stepping = struct.unpack("BB", packet[17:19])
|
||||||
self.mcu_bsl_version = "%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
|
self.mcu_bsl_version = "%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
|
||||||
chr(bl_stepping))
|
chr(bl_stepping))
|
||||||
|
|
||||||
self.bsl_version = bl_version
|
self.bsl_version = bl_version
|
||||||
|
|
||||||
@ -689,9 +612,6 @@ class Stc12AProtocol(Stc12AOptionsMixIn, Stc89Protocol):
|
|||||||
def initialize_options(self, status_packet):
|
def initialize_options(self, status_packet):
|
||||||
"""Initialize options"""
|
"""Initialize options"""
|
||||||
|
|
||||||
if len(status_packet) < 31:
|
|
||||||
raise StcProtocolException("invalid options in status packet")
|
|
||||||
|
|
||||||
# create option state
|
# create option state
|
||||||
self.options = Stc12AOption(status_packet[23:26] + status_packet[29:30])
|
self.options = Stc12AOption(status_packet[23:26] + status_packet[29:30])
|
||||||
self.options.print()
|
self.options.print()
|
||||||
@ -733,7 +653,7 @@ class Stc12AProtocol(Stc12AOptionsMixIn, Stc89Protocol):
|
|||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
packet = bytes([0x80, 0x00, 0x00, 0x36, 0x01])
|
packet = bytes([0x80, 0x00, 0x00, 0x36, 0x01])
|
||||||
packet += struct.pack(">H", self.mcu_magic)
|
packet += struct.pack(">H", self.mcu_magic)
|
||||||
for _ in range(4):
|
for i in range(4):
|
||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if response[0] != 0x80:
|
if response[0] != 0x80:
|
||||||
@ -790,14 +710,14 @@ class Stc12OptionsMixIn:
|
|||||||
class Stc12BaseProtocol(StcBaseProtocol):
|
class Stc12BaseProtocol(StcBaseProtocol):
|
||||||
"""Base class for STC 10/11/12 series protocol handlers"""
|
"""Base class for STC 10/11/12 series protocol handlers"""
|
||||||
|
|
||||||
PROGRAM_BLOCKSIZE = 128
|
|
||||||
"""block size for programming flash"""
|
"""block size for programming flash"""
|
||||||
|
PROGRAM_BLOCKSIZE = 128
|
||||||
|
|
||||||
ERASE_COUNTDOWN = 0x0d
|
|
||||||
"""countdown value for flash erase"""
|
"""countdown value for flash erase"""
|
||||||
|
ERASE_COUNTDOWN = 0x0d
|
||||||
|
|
||||||
PARITY = serial.PARITY_EVEN
|
|
||||||
"""Parity for error correction was introduced with STC12"""
|
"""Parity for error correction was introduced with STC12"""
|
||||||
|
PARITY = serial.PARITY_EVEN
|
||||||
|
|
||||||
def __init__(self, port, baud_handshake, baud_transfer):
|
def __init__(self, port, baud_handshake, baud_transfer):
|
||||||
StcBaseProtocol.__init__(self, port, baud_handshake, baud_transfer)
|
StcBaseProtocol.__init__(self, port, baud_handshake, baud_transfer)
|
||||||
@ -814,7 +734,7 @@ class Stc12BaseProtocol(StcBaseProtocol):
|
|||||||
payload = StcBaseProtocol.extract_payload(self, packet)
|
payload = StcBaseProtocol.extract_payload(self, packet)
|
||||||
return payload[:-2]
|
return payload[:-2]
|
||||||
|
|
||||||
def write_packet(self, packet_data):
|
def write_packet(self, data):
|
||||||
"""Send packet to MCU.
|
"""Send packet to MCU.
|
||||||
|
|
||||||
Constructs a packet with supplied payload and sends it to the MCU.
|
Constructs a packet with supplied payload and sends it to the MCU.
|
||||||
@ -826,8 +746,8 @@ class Stc12BaseProtocol(StcBaseProtocol):
|
|||||||
packet += self.PACKET_HOST
|
packet += self.PACKET_HOST
|
||||||
|
|
||||||
# packet length and payload
|
# packet length and payload
|
||||||
packet += struct.pack(">H", len(packet_data) + 6)
|
packet += struct.pack(">H", len(data) + 6)
|
||||||
packet += packet_data
|
packet += data
|
||||||
|
|
||||||
# checksum and end code
|
# checksum and end code
|
||||||
packet += struct.pack(">H", sum(packet[2:]) & 0xffff)
|
packet += struct.pack(">H", sum(packet[2:]) & 0xffff)
|
||||||
@ -837,18 +757,18 @@ class Stc12BaseProtocol(StcBaseProtocol):
|
|||||||
self.ser.write(packet)
|
self.ser.write(packet)
|
||||||
self.ser.flush()
|
self.ser.flush()
|
||||||
|
|
||||||
def initialize_status(self, status_packet):
|
def initialize_status(self, packet):
|
||||||
"""Decode status packet and store basic MCU info"""
|
"""Decode status packet and store basic MCU info"""
|
||||||
|
|
||||||
freq_counter = 0
|
freq_counter = 0
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
freq_counter += struct.unpack(">H", status_packet[1+2*i:3+2*i])[0]
|
freq_counter += struct.unpack(">H", packet[1+2*i:3+2*i])[0]
|
||||||
freq_counter /= 8.0
|
freq_counter /= 8.0
|
||||||
self.mcu_clock_hz = (self.baud_handshake * freq_counter * 12.0) / 7.0
|
self.mcu_clock_hz = (self.baud_handshake * freq_counter * 12.0) / 7.0
|
||||||
|
|
||||||
bl_version, bl_stepping = struct.unpack("BB", status_packet[17:19])
|
bl_version, bl_stepping = struct.unpack("BB", packet[17:19])
|
||||||
self.mcu_bsl_version = "%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
|
self.mcu_bsl_version = "%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
|
||||||
chr(bl_stepping))
|
chr(bl_stepping))
|
||||||
|
|
||||||
self.bsl_version = bl_version
|
self.bsl_version = bl_version
|
||||||
|
|
||||||
@ -881,9 +801,6 @@ class Stc12BaseProtocol(StcBaseProtocol):
|
|||||||
def initialize_options(self, status_packet):
|
def initialize_options(self, status_packet):
|
||||||
"""Initialize options"""
|
"""Initialize options"""
|
||||||
|
|
||||||
if len(status_packet) < 29:
|
|
||||||
raise StcProtocolException("invalid options in status packet")
|
|
||||||
|
|
||||||
# create option state
|
# create option state
|
||||||
self.options = Stc12Option(status_packet[23:26] + status_packet[27:28])
|
self.options = Stc12Option(status_packet[23:26] + status_packet[27:28])
|
||||||
self.options.print()
|
self.options.print()
|
||||||
@ -961,18 +878,22 @@ class Stc12BaseProtocol(StcBaseProtocol):
|
|||||||
as the block size (depends on MCU's RAM size).
|
as the block size (depends on MCU's RAM size).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
print("Writing %d bytes: " % len(data), end="")
|
||||||
|
sys.stdout.flush()
|
||||||
for i in range(0, len(data), self.PROGRAM_BLOCKSIZE):
|
for i in range(0, len(data), self.PROGRAM_BLOCKSIZE):
|
||||||
packet = bytes(3)
|
packet = bytes(3)
|
||||||
packet += struct.pack(">H", i)
|
packet += struct.pack(">H", i)
|
||||||
packet += struct.pack(">H", self.PROGRAM_BLOCKSIZE)
|
packet += struct.pack(">H", self.PROGRAM_BLOCKSIZE)
|
||||||
packet += data[i:i+self.PROGRAM_BLOCKSIZE]
|
packet += data[i:i+self.PROGRAM_BLOCKSIZE]
|
||||||
while len(packet) < self.PROGRAM_BLOCKSIZE + 7: packet += b"\x00"
|
while len(packet) < self.PROGRAM_BLOCKSIZE + 7: packet += b"\x00"
|
||||||
|
csum = sum(packet[7:]) & 0xff
|
||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if response[0] != 0x00:
|
if response[0] != 0x00:
|
||||||
raise StcProtocolException("incorrect magic in write packet")
|
raise StcProtocolException("incorrect magic in write packet")
|
||||||
self.progress_cb(i, self.PROGRAM_BLOCKSIZE, len(data))
|
print(".", end="")
|
||||||
self.progress_cb(len(data), self.PROGRAM_BLOCKSIZE, len(data))
|
sys.stdout.flush()
|
||||||
|
print(" done")
|
||||||
|
|
||||||
print("Finishing write: ", end="")
|
print("Finishing write: ", end="")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
@ -1015,9 +936,6 @@ class Stc15AProtocol(Stc12Protocol):
|
|||||||
def initialize_options(self, status_packet):
|
def initialize_options(self, status_packet):
|
||||||
"""Initialize options"""
|
"""Initialize options"""
|
||||||
|
|
||||||
if len(status_packet) < 37:
|
|
||||||
raise StcProtocolException("invalid options in status packet")
|
|
||||||
|
|
||||||
# create option state
|
# create option state
|
||||||
self.options = Stc15AOption(status_packet[23:36])
|
self.options = Stc15AOption(status_packet[23:36])
|
||||||
self.options.print()
|
self.options.print()
|
||||||
@ -1036,20 +954,20 @@ class Stc15AProtocol(Stc12Protocol):
|
|||||||
raise StcProtocolException("incorrect magic in status packet")
|
raise StcProtocolException("incorrect magic in status packet")
|
||||||
return status_packet
|
return status_packet
|
||||||
|
|
||||||
def initialize_status(self, status_packet):
|
def initialize_status(self, packet):
|
||||||
"""Decode status packet and store basic MCU info"""
|
"""Decode status packet and store basic MCU info"""
|
||||||
|
|
||||||
freq_counter = 0
|
freq_counter = 0
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
freq_counter += struct.unpack(">H", status_packet[1+2*i:3+2*i])[0]
|
freq_counter += struct.unpack(">H", packet[1+2*i:3+2*i])[0]
|
||||||
freq_counter /= 4.0
|
freq_counter /= 4.0
|
||||||
self.mcu_clock_hz = (self.baud_handshake * freq_counter * 12.0) / 7.0
|
self.mcu_clock_hz = (self.baud_handshake * freq_counter * 12.0) / 7.0
|
||||||
|
|
||||||
bl_version, bl_stepping = struct.unpack("BB", status_packet[17:19])
|
bl_version, bl_stepping = struct.unpack("BB", packet[17:19])
|
||||||
self.mcu_bsl_version = "%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
|
self.mcu_bsl_version = "%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
|
||||||
chr(bl_stepping))
|
chr(bl_stepping))
|
||||||
|
|
||||||
self.trim_data = status_packet[51:58]
|
self.trim_data = packet[51:58]
|
||||||
self.freq_counter = freq_counter
|
self.freq_counter = freq_counter
|
||||||
|
|
||||||
def get_trim_sequence(self, frequency):
|
def get_trim_sequence(self, frequency):
|
||||||
@ -1101,8 +1019,7 @@ class Stc15AProtocol(Stc12Protocol):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
user_speed = self.trim_frequency
|
user_speed = self.trim_frequency
|
||||||
if user_speed <= 0:
|
if user_speed <= 0: user_speed = self.mcu_clock_hz
|
||||||
user_speed = self.mcu_clock_hz
|
|
||||||
program_speed = 22118400
|
program_speed = 22118400
|
||||||
|
|
||||||
user_count = int(self.freq_counter * (user_speed / self.mcu_clock_hz))
|
user_count = int(self.freq_counter * (user_speed / self.mcu_clock_hz))
|
||||||
@ -1130,19 +1047,15 @@ class Stc15AProtocol(Stc12Protocol):
|
|||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
self.pulse(timeout=1.0)
|
self.pulse(timeout=1.0)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if len(response) < 36 or response[0] != 0x65:
|
if response[0] != 0x65:
|
||||||
raise StcProtocolException("incorrect magic in handshake packet")
|
raise StcProtocolException("incorrect magic in handshake packet")
|
||||||
|
|
||||||
# determine programming speed trim value
|
# determine programming speed trim value
|
||||||
target_trim_a, target_count_a = struct.unpack(">HH", response[28:32])
|
target_trim_a, target_count_a = struct.unpack(">HH", response[28:32])
|
||||||
target_trim_b, target_count_b = struct.unpack(">HH", response[32:36])
|
target_trim_b, target_count_b = struct.unpack(">HH", response[32:36])
|
||||||
if target_count_a == target_count_b:
|
|
||||||
raise StcProtocolException("frequency trimming failed")
|
|
||||||
m = (target_trim_b - target_trim_a) / (target_count_b - target_count_a)
|
m = (target_trim_b - target_trim_a) / (target_count_b - target_count_a)
|
||||||
n = target_trim_a - m * target_count_a
|
n = target_trim_a - m * target_count_a
|
||||||
program_trim = round(m * program_count + n)
|
program_trim = round(m * program_count + n)
|
||||||
if program_trim > 65535 or program_trim < 0:
|
|
||||||
raise StcProtocolException("frequency trimming failed")
|
|
||||||
|
|
||||||
# determine trim trials for second round
|
# determine trim trials for second round
|
||||||
trim_a, count_a = struct.unpack(">HH", response[12:16])
|
trim_a, count_a = struct.unpack(">HH", response[12:16])
|
||||||
@ -1161,14 +1074,10 @@ class Stc15AProtocol(Stc12Protocol):
|
|||||||
target_count_a = count_a
|
target_count_a = count_a
|
||||||
target_count_b = count_b
|
target_count_b = count_b
|
||||||
# linear interpolate to find range to try next
|
# linear interpolate to find range to try next
|
||||||
if target_count_a == target_count_b:
|
|
||||||
raise StcProtocolException("frequency trimming failed")
|
|
||||||
m = (target_trim_b - target_trim_a) / (target_count_b - target_count_a)
|
m = (target_trim_b - target_trim_a) / (target_count_b - target_count_a)
|
||||||
n = target_trim_a - m * target_count_a
|
n = target_trim_a - m * target_count_a
|
||||||
target_trim = round(m * user_count + n)
|
target_trim = round(m * user_count + n)
|
||||||
target_trim_start = min(max(target_trim - 5, target_trim_a), target_trim_b)
|
target_trim_start = min(max(target_trim - 5, target_trim_a), target_trim_b)
|
||||||
if target_trim_start + 11 > 65535 or target_trim_start < 0:
|
|
||||||
raise StcProtocolException("frequency trimming failed")
|
|
||||||
|
|
||||||
# trim challenge-response, second round
|
# trim challenge-response, second round
|
||||||
packet = bytes([0x65])
|
packet = bytes([0x65])
|
||||||
@ -1180,7 +1089,7 @@ class Stc15AProtocol(Stc12Protocol):
|
|||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
self.pulse(timeout=1.0)
|
self.pulse(timeout=1.0)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if len(response) < 56 or response[0] != 0x65:
|
if response[0] != 0x65:
|
||||||
raise StcProtocolException("incorrect magic in handshake packet")
|
raise StcProtocolException("incorrect magic in handshake packet")
|
||||||
|
|
||||||
# determine best trim value
|
# determine best trim value
|
||||||
@ -1239,40 +1148,37 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
def initialize_options(self, status_packet):
|
def initialize_options(self, status_packet):
|
||||||
"""Initialize options"""
|
"""Initialize options"""
|
||||||
|
|
||||||
if len(status_packet) < 14:
|
|
||||||
raise StcProtocolException("invalid options in status packet")
|
|
||||||
|
|
||||||
# create option state
|
# create option state
|
||||||
# XXX: check how option bytes are concatenated here
|
|
||||||
self.options = Stc15Option(status_packet[5:8] + status_packet[12:13] + status_packet[37:38])
|
self.options = Stc15Option(status_packet[5:8] + status_packet[12:13] + status_packet[37:38])
|
||||||
self.options.print()
|
self.options.print()
|
||||||
|
|
||||||
def initialize_status(self, status_packet):
|
def initialize_status(self, packet):
|
||||||
"""Decode status packet and store basic MCU info"""
|
"""Decode status packet and store basic MCU info"""
|
||||||
|
|
||||||
# check bit that control internal vs. external clock source
|
# check bit that control internal vs. external clock source
|
||||||
# get frequency either stored from calibration or from
|
# get frequency either stored from calibration or from
|
||||||
# frequency counter
|
# frequency counter
|
||||||
self.external_clock = (status_packet[7] & 0x01) == 0
|
self.external_clock = (packet[7] & 0x01) == 0
|
||||||
if self.external_clock:
|
if self.external_clock:
|
||||||
count, = struct.unpack(">H", status_packet[13:15])
|
count, = struct.unpack(">H", packet[13:15])
|
||||||
self.mcu_clock_hz = self.baud_handshake * count
|
self.mcu_clock_hz = self.baud_handshake * count
|
||||||
else:
|
else:
|
||||||
self.mcu_clock_hz, = struct.unpack(">I", status_packet[8:12])
|
self.mcu_clock_hz, = struct.unpack(">I", packet[8:12])
|
||||||
# all ones means no calibration
|
# all ones means no calibration
|
||||||
# new chips are shipped without any calibration
|
# new chips are shipped without any calibration
|
||||||
if self.mcu_clock_hz == 0xffffffff: self.mcu_clock_hz = 0
|
if self.mcu_clock_hz == 0xffffffff: self.mcu_clock_hz = 0
|
||||||
|
|
||||||
# pre-calibrated trim adjust for 24 MHz, range 0x40
|
# pre-calibrated trim adjust for 24 MHz, range 0x40
|
||||||
self.freq_count_24 = status_packet[4]
|
self.freq_count_24 = packet[4]
|
||||||
|
|
||||||
# wakeup timer factory value
|
# wakeup timer factory value
|
||||||
self.wakeup_freq, = struct.unpack(">H", status_packet[1:3])
|
self.wakeup_freq, = struct.unpack(">H", packet[1:3])
|
||||||
|
|
||||||
bl_version, bl_stepping = struct.unpack("BB", status_packet[17:19])
|
bl_version, bl_stepping = struct.unpack("BB", packet[17:19])
|
||||||
bl_minor = status_packet[22] & 0x0f
|
bl_minor = packet[22] & 0x0f
|
||||||
self.mcu_bsl_version = "%d.%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
|
self.mcu_bsl_version = "%d.%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
|
||||||
bl_minor, chr(bl_stepping))
|
bl_minor,
|
||||||
|
chr(bl_stepping))
|
||||||
self.bsl_version = bl_version
|
self.bsl_version = bl_version
|
||||||
|
|
||||||
def print_mcu_info(self):
|
def print_mcu_info(self):
|
||||||
@ -1288,8 +1194,6 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
calib_data = response[2:]
|
calib_data = response[2:]
|
||||||
challenge_data = packet[2:]
|
challenge_data = packet[2:]
|
||||||
calib_len = response[1]
|
calib_len = response[1]
|
||||||
if len(calib_data) < 2 * calib_len:
|
|
||||||
raise StcProtocolException("range calibration data missing")
|
|
||||||
|
|
||||||
for i in range(calib_len - 1):
|
for i in range(calib_len - 1):
|
||||||
count_a, count_b = struct.unpack(">HH", calib_data[2*i:2*i+4])
|
count_a, count_b = struct.unpack(">HH", calib_data[2*i:2*i+4])
|
||||||
@ -1299,8 +1203,6 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
m = (trim_b - trim_a) / (count_b - count_a)
|
m = (trim_b - trim_a) / (count_b - count_a)
|
||||||
n = trim_a - m * count_a
|
n = trim_a - m * count_a
|
||||||
target_trim = round(m * target_count + n)
|
target_trim = round(m * target_count + n)
|
||||||
if target_trim > 65536 or target_trim < 0:
|
|
||||||
raise StcProtocolException("frequency trimming failed")
|
|
||||||
return (target_trim, trim_range)
|
return (target_trim, trim_range)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
@ -1312,8 +1214,6 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
calib_data = response[2:]
|
calib_data = response[2:]
|
||||||
challenge_data = packet[2:]
|
challenge_data = packet[2:]
|
||||||
calib_len = response[1]
|
calib_len = response[1]
|
||||||
if len(calib_data) < 2 * calib_len:
|
|
||||||
raise StcProtocolException("trim calibration data missing")
|
|
||||||
|
|
||||||
best = None
|
best = None
|
||||||
best_count = sys.maxsize
|
best_count = sys.maxsize
|
||||||
@ -1324,9 +1224,6 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
best_count = abs(count - target_count)
|
best_count = abs(count - target_count)
|
||||||
best = (trim_adj, trim_range), count
|
best = (trim_adj, trim_range), count
|
||||||
|
|
||||||
if not best:
|
|
||||||
raise StcProtocolException("frequency trimming failed")
|
|
||||||
|
|
||||||
return best
|
return best
|
||||||
|
|
||||||
def calibrate(self):
|
def calibrate(self):
|
||||||
@ -1356,13 +1253,13 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
self.pulse(b"\xfe", timeout=1.0)
|
self.pulse(b"\xfe", timeout=1.0)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if len(response) < 2 or response[0] != 0x00:
|
if response[0] != 0x00:
|
||||||
raise StcProtocolException("incorrect magic in handshake packet")
|
raise StcProtocolException("incorrect magic in handshake packet")
|
||||||
|
|
||||||
# select ranges and trim values
|
# select ranges and trim values
|
||||||
user_trim = self.choose_range(packet, response, target_user_count)
|
user_trim = self.choose_range(packet, response, target_user_count)
|
||||||
prog_trim = self.choose_range(packet, response, target_prog_count)
|
prog_trim = self.choose_range(packet, response, target_prog_count)
|
||||||
if user_trim is None or prog_trim is None:
|
if user_trim == None or prog_trim == None:
|
||||||
raise StcProtocolException("frequency trimming unsuccessful")
|
raise StcProtocolException("frequency trimming unsuccessful")
|
||||||
|
|
||||||
# calibration, round 2
|
# calibration, round 2
|
||||||
@ -1375,12 +1272,12 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
self.pulse(b"\xfe", timeout=1.0)
|
self.pulse(b"\xfe", timeout=1.0)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if len(response) < 2 or response[0] != 0x00:
|
if response[0] != 0x00:
|
||||||
raise StcProtocolException("incorrect magic in handshake packet")
|
raise StcProtocolException("incorrect magic in handshake packet")
|
||||||
|
|
||||||
# select final values
|
# select final values
|
||||||
user_trim, user_count = self.choose_trim(packet, response, target_user_count)
|
user_trim, user_count = self.choose_trim(packet, response, target_user_count)
|
||||||
prog_trim, _ = self.choose_trim(packet, response, target_prog_count)
|
prog_trim, prog_count = self.choose_trim(packet, response, target_prog_count)
|
||||||
self.trim_value = user_trim
|
self.trim_value = user_trim
|
||||||
self.trim_frequency = round(user_count * (self.baud_handshake / 2))
|
self.trim_frequency = round(user_count * (self.baud_handshake / 2))
|
||||||
print("%.03f MHz" % (self.trim_frequency / 1E6))
|
print("%.03f MHz" % (self.trim_frequency / 1E6))
|
||||||
@ -1396,12 +1293,12 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
# This is a bit of a hack, but it works.
|
# This is a bit of a hack, but it works.
|
||||||
bauds = self.baud_transfer if (self.mcu_magic >> 8) == 0xf2 else self.baud_transfer * 4
|
bauds = self.baud_transfer if (self.mcu_magic >> 8) == 0xf2 else self.baud_transfer * 4
|
||||||
packet += struct.pack(">H", int(65535 - program_speed / bauds))
|
packet += struct.pack(">H", int(65535 - program_speed / bauds))
|
||||||
packet += bytes(user_trim)
|
packet += struct.pack(">H", int(65535 - (program_speed / bauds) * 1.5))
|
||||||
iap_wait = self.get_iap_delay(program_speed)
|
iap_wait = self.get_iap_delay(program_speed)
|
||||||
packet += bytes([iap_wait])
|
packet += bytes([iap_wait])
|
||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if len(response) < 1 or response[0] != 0x01:
|
if response[0] != 0x01:
|
||||||
raise StcProtocolException("incorrect magic in handshake packet")
|
raise StcProtocolException("incorrect magic in handshake packet")
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
self.ser.baudrate = self.baud_transfer
|
self.ser.baudrate = self.baud_transfer
|
||||||
@ -1418,7 +1315,7 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
packet += bytes([0x00, 0x00, iap_wait])
|
packet += bytes([0x00, 0x00, iap_wait])
|
||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if len(response) < 1 or response[0] != 0x01:
|
if response[0] != 0x01:
|
||||||
raise StcProtocolException("incorrect magic in handshake packet")
|
raise StcProtocolException("incorrect magic in handshake packet")
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
self.ser.baudrate = self.baud_transfer
|
self.ser.baudrate = self.baud_transfer
|
||||||
@ -1444,9 +1341,9 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
packet += bytes([0x00, 0x00, 0x5a, 0xa5])
|
packet += bytes([0x00, 0x00, 0x5a, 0xa5])
|
||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if len(response) == 1 and response[0] == 0x0f:
|
if response[0] == 0x0f:
|
||||||
raise StcProtocolException("MCU is locked")
|
raise StcProtocolException("MCU is locked")
|
||||||
if len(response) < 1 or response[0] != 0x05:
|
if response[0] != 0x05:
|
||||||
raise StcProtocolException("incorrect magic in handshake packet")
|
raise StcProtocolException("incorrect magic in handshake packet")
|
||||||
|
|
||||||
print("done")
|
print("done")
|
||||||
@ -1467,20 +1364,18 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
packet += bytes([0x00, 0x5a, 0xa5])
|
packet += bytes([0x00, 0x5a, 0xa5])
|
||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if len(response) < 1 or response[0] != 0x03:
|
if response[0] != 0x03:
|
||||||
raise StcProtocolException("incorrect magic in handshake packet")
|
raise StcProtocolException("incorrect magic in handshake packet")
|
||||||
print("done")
|
print("done")
|
||||||
|
|
||||||
if len(response) >= 8:
|
if len(response) >= 8:
|
||||||
self.uid = response[1:8]
|
self.uid = response[1:8]
|
||||||
|
|
||||||
# we should have a UID at this point
|
|
||||||
if not self.uid:
|
|
||||||
raise StcProtocolException("UID is missing")
|
|
||||||
|
|
||||||
def program_flash(self, data):
|
def program_flash(self, data):
|
||||||
"""Program the MCU's flash memory."""
|
"""Program the MCU's flash memory."""
|
||||||
|
|
||||||
|
print("Writing %d bytes: " % len(data), end="")
|
||||||
|
sys.stdout.flush()
|
||||||
for i in range(0, len(data), self.PROGRAM_BLOCKSIZE):
|
for i in range(0, len(data), self.PROGRAM_BLOCKSIZE):
|
||||||
packet = bytes([0x22]) if i == 0 else bytes([0x02])
|
packet = bytes([0x22]) if i == 0 else bytes([0x02])
|
||||||
packet += struct.pack(">H", i)
|
packet += struct.pack(">H", i)
|
||||||
@ -1490,10 +1385,11 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
while len(packet) < self.PROGRAM_BLOCKSIZE + 3: packet += b"\x00"
|
while len(packet) < self.PROGRAM_BLOCKSIZE + 3: packet += b"\x00"
|
||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if len(response) < 2 or response[0] != 0x02 or response[1] != 0x54:
|
if response[0] != 0x02 or response[1] != 0x54:
|
||||||
raise StcProtocolException("incorrect magic in write packet")
|
raise StcProtocolException("incorrect magic in write packet")
|
||||||
self.progress_cb(i, self.PROGRAM_BLOCKSIZE, len(data))
|
print(".", end="")
|
||||||
self.progress_cb(len(data), self.PROGRAM_BLOCKSIZE, len(data))
|
sys.stdout.flush()
|
||||||
|
print(" done")
|
||||||
|
|
||||||
# BSL 7.2+ needs a write finish packet according to dumps
|
# BSL 7.2+ needs a write finish packet according to dumps
|
||||||
if self.bsl_version >= 0x72:
|
if self.bsl_version >= 0x72:
|
||||||
@ -1502,7 +1398,7 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
packet = bytes([0x07, 0x00, 0x00, 0x5a, 0xa5])
|
packet = bytes([0x07, 0x00, 0x00, 0x5a, 0xa5])
|
||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if len(response) < 2 or response[0] != 0x07 or response[1] != 0x54:
|
if response[0] != 0x07 or response[1] != 0x54:
|
||||||
raise StcProtocolException("incorrect magic in finish packet")
|
raise StcProtocolException("incorrect magic in finish packet")
|
||||||
print("done")
|
print("done")
|
||||||
|
|
||||||
@ -1511,7 +1407,7 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
configuration."""
|
configuration."""
|
||||||
|
|
||||||
msr = self.options.get_msr()
|
msr = self.options.get_msr()
|
||||||
packet = bytes([0xff] * 23)
|
packet = bytes([0xff] * 23)
|
||||||
packet += bytes([(self.trim_frequency >> 24) & 0xff,
|
packet += bytes([(self.trim_frequency >> 24) & 0xff,
|
||||||
0xff,
|
0xff,
|
||||||
(self.trim_frequency >> 16) & 0xff,
|
(self.trim_frequency >> 16) & 0xff,
|
||||||
@ -1541,152 +1437,13 @@ class Stc15Protocol(Stc15AProtocol):
|
|||||||
packet += self.build_options()
|
packet += self.build_options()
|
||||||
self.write_packet(packet)
|
self.write_packet(packet)
|
||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if len(response) < 2 or response[0] != 0x04 or response[1] != 0x54:
|
if response[0] != 0x04 or response[1] != 0x54:
|
||||||
raise StcProtocolException("incorrect magic in option packet")
|
raise StcProtocolException("incorrect magic in option packet")
|
||||||
print("done")
|
print("done")
|
||||||
|
|
||||||
print("Target UID: %s" % Utils.hexstr(self.uid))
|
print("Target UID: %s" % Utils.hexstr(self.uid))
|
||||||
|
|
||||||
|
|
||||||
class Stc8Protocol(Stc15Protocol):
|
|
||||||
"""Protocol handler for STC8 series"""
|
|
||||||
|
|
||||||
def __init__(self, port, handshake, baud, trim):
|
|
||||||
Stc15Protocol.__init__(self, port, handshake, baud, trim)
|
|
||||||
self.trim_divider = None
|
|
||||||
|
|
||||||
def initialize_options(self, status_packet):
|
|
||||||
"""Initialize options"""
|
|
||||||
if len(status_packet) < 17:
|
|
||||||
raise StcProtocolException("invalid options in status packet")
|
|
||||||
|
|
||||||
# create option state
|
|
||||||
self.options = Stc8Option(status_packet[9:12] + status_packet[15:17])
|
|
||||||
self.options.print()
|
|
||||||
|
|
||||||
def initialize_status(self, packet):
|
|
||||||
"""Decode status packet and store basic MCU info"""
|
|
||||||
|
|
||||||
self.mcu_clock_hz, = struct.unpack(">I", packet[1:5])
|
|
||||||
# XXX: external clock not supported nor tested
|
|
||||||
self.external_clock = False
|
|
||||||
# all ones means no calibration
|
|
||||||
# new chips are shipped without any calibration
|
|
||||||
# XXX: somehow check if that still holds
|
|
||||||
if self.mcu_clock_hz == 0xffffffff: self.mcu_clock_hz = 0
|
|
||||||
|
|
||||||
# pre-calibrated trim adjust for 24 MHz, range 0x40
|
|
||||||
self.freq_count_24 = packet[4]
|
|
||||||
|
|
||||||
# wakeup timer factory value
|
|
||||||
self.wakeup_freq, = struct.unpack(">H", packet[23:25])
|
|
||||||
|
|
||||||
bl_version, bl_stepping = struct.unpack("BB", packet[17:19])
|
|
||||||
bl_minor = packet[22] & 0x0f
|
|
||||||
self.mcu_bsl_version = "%d.%d.%d%s" % (bl_version >> 4, bl_version & 0x0f,
|
|
||||||
bl_minor, chr(bl_stepping))
|
|
||||||
self.bsl_version = bl_version
|
|
||||||
|
|
||||||
def calibrate(self):
|
|
||||||
"""Calibrate selected user frequency frequency and switch to selected baudrate."""
|
|
||||||
|
|
||||||
# handle uncalibrated chips
|
|
||||||
if self.mcu_clock_hz == 0 and self.trim_frequency <= 0:
|
|
||||||
raise StcProtocolException("uncalibrated, please provide a trim value")
|
|
||||||
|
|
||||||
# determine target counter
|
|
||||||
user_speed = self.trim_frequency
|
|
||||||
if user_speed <= 0: user_speed = self.mcu_clock_hz
|
|
||||||
target_user_count = round(user_speed / (self.baud_handshake/2))
|
|
||||||
|
|
||||||
# calibration, round 1
|
|
||||||
# XXX: challenges need work. the ranges and how they related to clock frequency
|
|
||||||
# is different. A clock divider is used for lower frequencies.
|
|
||||||
print("Trimming frequency: ", end="")
|
|
||||||
sys.stdout.flush()
|
|
||||||
packet = bytes([0x00])
|
|
||||||
packet += struct.pack(">B", 12)
|
|
||||||
packet += bytes([0x00, 0x00, 23*1, 0x00, 23*2, 0x00])
|
|
||||||
packet += bytes([23*3, 0x00, 23*4, 0x00, 23*5, 0x00])
|
|
||||||
packet += bytes([23*6, 0x00, 23*7, 0x00, 23*8, 0x00])
|
|
||||||
packet += bytes([23*9, 0x00, 23*10, 0x00, 255, 0x00])
|
|
||||||
self.write_packet(packet)
|
|
||||||
self.pulse(b"\xfe", timeout=1.0)
|
|
||||||
response = self.read_packet()
|
|
||||||
if len(response) < 2 or response[0] != 0x00:
|
|
||||||
raise StcProtocolException("incorrect magic in handshake packet")
|
|
||||||
|
|
||||||
# select ranges and trim values
|
|
||||||
for divider in (1, 2, 3, 4, 5):
|
|
||||||
user_trim = self.choose_range(packet, response, target_user_count * divider)
|
|
||||||
if user_trim is not None:
|
|
||||||
self.trim_divider = divider
|
|
||||||
break
|
|
||||||
if user_trim is None:
|
|
||||||
raise StcProtocolException("frequency trimming unsuccessful")
|
|
||||||
|
|
||||||
# calibration, round 2
|
|
||||||
packet = bytes([0x00])
|
|
||||||
packet += struct.pack(">B", 12)
|
|
||||||
for i in range(user_trim[0] - 1, user_trim[0] + 2):
|
|
||||||
packet += bytes([i & 0xff, 0x00])
|
|
||||||
for i in range(user_trim[0] - 1, user_trim[0] + 2):
|
|
||||||
packet += bytes([i & 0xff, 0x01])
|
|
||||||
for i in range(user_trim[0] - 1, user_trim[0] + 2):
|
|
||||||
packet += bytes([i & 0xff, 0x02])
|
|
||||||
for i in range(user_trim[0] - 1, user_trim[0] + 2):
|
|
||||||
packet += bytes([i & 0xff, 0x03])
|
|
||||||
self.write_packet(packet)
|
|
||||||
self.pulse(b"\xfe", timeout=1.0)
|
|
||||||
response = self.read_packet()
|
|
||||||
if len(response) < 2 or response[0] != 0x00:
|
|
||||||
raise StcProtocolException("incorrect magic in handshake packet")
|
|
||||||
|
|
||||||
# select final values
|
|
||||||
user_trim, user_count = self.choose_trim(packet, response, target_user_count)
|
|
||||||
self.trim_value = user_trim
|
|
||||||
self.trim_frequency = round(user_count * (self.baud_handshake / 2) / self.trim_divider)
|
|
||||||
print("%.03f MHz" % (self.trim_frequency / 1E6))
|
|
||||||
|
|
||||||
# switch to programming frequency
|
|
||||||
print("Switching to %d baud: " % self.baud_transfer, end="")
|
|
||||||
sys.stdout.flush()
|
|
||||||
packet = bytes([0x01, 0x00, 0x00])
|
|
||||||
bauds = self.baud_transfer * 4
|
|
||||||
packet += struct.pack(">H", int(65535 - 24E6 / bauds))
|
|
||||||
packet += bytes([user_trim[1], user_trim[0]])
|
|
||||||
iap_wait = self.get_iap_delay(24E6)
|
|
||||||
packet += bytes([iap_wait])
|
|
||||||
self.write_packet(packet)
|
|
||||||
response = self.read_packet()
|
|
||||||
if len(response) < 1 or response[0] != 0x01:
|
|
||||||
raise StcProtocolException("incorrect magic in handshake packet")
|
|
||||||
self.ser.baudrate = self.baud_transfer
|
|
||||||
|
|
||||||
def build_options(self):
|
|
||||||
"""Build a packet of option data from the current configuration."""
|
|
||||||
|
|
||||||
msr = self.options.get_msr()
|
|
||||||
packet = 40 * bytearray([0xff])
|
|
||||||
packet[3] = 0
|
|
||||||
packet[6] = 0
|
|
||||||
packet[22] = 0
|
|
||||||
packet[24:28] = struct.pack(">I", self.trim_frequency)
|
|
||||||
packet[28:30] = self.trim_value
|
|
||||||
packet[30] = self.trim_divider
|
|
||||||
packet[32] = msr[0]
|
|
||||||
packet[36:40] = msr[1:5]
|
|
||||||
return bytes(packet)
|
|
||||||
|
|
||||||
def disconnect(self):
|
|
||||||
"""Disconnect from MCU"""
|
|
||||||
|
|
||||||
# reset mcu
|
|
||||||
packet = bytes([0xff])
|
|
||||||
self.write_packet(packet)
|
|
||||||
self.ser.close()
|
|
||||||
print("Disconnected!")
|
|
||||||
|
|
||||||
class StcUsb15Protocol(Stc15Protocol):
|
class StcUsb15Protocol(Stc15Protocol):
|
||||||
"""USB should use large blocks"""
|
"""USB should use large blocks"""
|
||||||
PROGRAM_BLOCKSIZE = 128
|
PROGRAM_BLOCKSIZE = 128
|
||||||
@ -1704,9 +1461,8 @@ class StcUsb15Protocol(Stc15Protocol):
|
|||||||
|
|
||||||
def dump_packet(self, data, request=0, value=0, index=0, receive=True):
|
def dump_packet(self, data, request=0, value=0, index=0, receive=True):
|
||||||
if self.debug:
|
if self.debug:
|
||||||
print("%s bRequest=%02X wValue=%04X wIndex=%04X data: %s" %
|
print("%s bRequest=%02X wValue=%04X wIndex=%04X data: %s" % (("<-" if receive else "->"),
|
||||||
(("<-" if receive else "->"), request, value, index,
|
request, value, index, Utils.hexstr(data, " ")), file=sys.stderr)
|
||||||
Utils.hexstr(data, " ")), file=sys.stderr)
|
|
||||||
|
|
||||||
def read_packet(self):
|
def read_packet(self):
|
||||||
"""Read a packet from the MCU"""
|
"""Read a packet from the MCU"""
|
||||||
@ -1746,16 +1502,15 @@ class StcUsb15Protocol(Stc15Protocol):
|
|||||||
|
|
||||||
self.dump_packet(chunks, request, value, index, receive=False)
|
self.dump_packet(chunks, request, value, index, receive=False)
|
||||||
host2dev = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_RECIPIENT_DEVICE | usb.util.CTRL_OUT
|
host2dev = usb.util.CTRL_TYPE_VENDOR | usb.util.CTRL_RECIPIENT_DEVICE | usb.util.CTRL_OUT
|
||||||
self.dev.ctrl_transfer(host2dev, request, value, index, chunks)
|
self.dev.ctrl_transfer(host2dev, request, value, index, chunks);
|
||||||
|
|
||||||
def connect(self, autoreset=False, resetcmd=False):
|
def connect(self, autoreset=False):
|
||||||
"""Connect to USB device and read info packet"""
|
"""Connect to USB device and read info packet"""
|
||||||
|
|
||||||
# USB support is optional. Provide an error if pyusb is not available.
|
# USB support is optional. Provide an error if pyusb is not available.
|
||||||
if not _usb_available:
|
if _usb_available == False:
|
||||||
raise StcProtocolException(
|
raise StcProtocolException("USB support not available. "
|
||||||
"USB support not available. " +
|
+ "pyusb is not installed or not working correctly.")
|
||||||
"pyusb is not installed or not working correctly.")
|
|
||||||
|
|
||||||
print("Waiting for MCU, please cycle power: ", end="")
|
print("Waiting for MCU, please cycle power: ", end="")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
@ -1815,6 +1570,8 @@ class StcUsb15Protocol(Stc15Protocol):
|
|||||||
def program_flash(self, data):
|
def program_flash(self, data):
|
||||||
"""Program the MCU's flash memory."""
|
"""Program the MCU's flash memory."""
|
||||||
|
|
||||||
|
print("Writing %d bytes: " % len(data), end="")
|
||||||
|
sys.stdout.flush()
|
||||||
for i in range(0, len(data), self.PROGRAM_BLOCKSIZE):
|
for i in range(0, len(data), self.PROGRAM_BLOCKSIZE):
|
||||||
packet = data[i:i+self.PROGRAM_BLOCKSIZE]
|
packet = data[i:i+self.PROGRAM_BLOCKSIZE]
|
||||||
while len(packet) < self.PROGRAM_BLOCKSIZE: packet += b"\x00"
|
while len(packet) < self.PROGRAM_BLOCKSIZE: packet += b"\x00"
|
||||||
@ -1824,8 +1581,9 @@ class StcUsb15Protocol(Stc15Protocol):
|
|||||||
response = self.read_packet()
|
response = self.read_packet()
|
||||||
if response[0] != 0x02 or response[1] != 0x54:
|
if response[0] != 0x02 or response[1] != 0x54:
|
||||||
raise StcProtocolException("incorrect magic in write packet")
|
raise StcProtocolException("incorrect magic in write packet")
|
||||||
self.progress_cb(i, self.PROGRAM_BLOCKSIZE, len(data))
|
print(".", end="")
|
||||||
self.progress_cb(len(data), self.PROGRAM_BLOCKSIZE, len(data))
|
sys.stdout.flush()
|
||||||
|
print(" done")
|
||||||
|
|
||||||
def program_options(self):
|
def program_options(self):
|
||||||
print("Setting options: ", end="")
|
print("Setting options: ", end="")
|
||||||
|
@ -19,38 +19,31 @@
|
|||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
import argparse
|
|
||||||
import serial
|
import serial
|
||||||
|
import argparse
|
||||||
|
|
||||||
class Utils:
|
class Utils:
|
||||||
"""Common utility functions"""
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def to_bool(cls, val):
|
def to_bool(self, val):
|
||||||
"""make sensible boolean from string or other type value"""
|
"""make sensible boolean from string or other type value"""
|
||||||
|
|
||||||
if not val:
|
if isinstance(val, bool): return val
|
||||||
return False
|
if isinstance(val, int): return bool(val)
|
||||||
if isinstance(val, bool):
|
if len(val) == 0: return False
|
||||||
return val
|
|
||||||
elif isinstance(val, int):
|
|
||||||
return bool(val)
|
|
||||||
return True if val[0].lower() == "t" or val[0] == "1" else False
|
return True if val[0].lower() == "t" or val[0] == "1" else False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def to_int(cls, val):
|
def to_int(self, val):
|
||||||
"""make int from any value, nice error message if not possible"""
|
"""make int from any value, nice error message if not possible"""
|
||||||
|
|
||||||
try:
|
try: return int(val, 0)
|
||||||
return int(val, 0)
|
except: raise ValueError("invalid integer")
|
||||||
except (TypeError, ValueError):
|
|
||||||
raise ValueError("invalid integer")
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def hexstr(cls, bytestr, sep=""):
|
def hexstr(self, bytestr, sep=""):
|
||||||
"""make formatted hex string output from byte sequence"""
|
"""make formatted hex string output from byte sequence"""
|
||||||
|
|
||||||
return sep.join(["%02X" % x for x in bytes(bytestr)])
|
return sep.join(["%02X" % x for x in bytestr])
|
||||||
|
|
||||||
|
|
||||||
class BaudType:
|
class BaudType:
|
||||||
@ -62,5 +55,5 @@ class BaudType:
|
|||||||
raise argparse.ArgumentTypeError("illegal baudrate")
|
raise argparse.ArgumentTypeError("illegal baudrate")
|
||||||
return baud
|
return baud
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self): return "baudrate"
|
||||||
return "baudrate"
|
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
name: IAP15F2K61S2 programming test
|
|
||||||
protocol: stc15
|
|
||||||
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
|
|
||||||
responses:
|
|
||||||
- [0x50, 0x87, 0xD3, 0x75, 0x9C, 0xF5, 0x3B, 0x17, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x09, 0x81, 0x00, 0x00, 0x71, 0x53, 0x00, 0xF4, 0x49, 0x04, 0x06, 0x58, 0x9C, 0x02, 0x0E, 0x14, 0x17, 0x19, 0x19, 0x00, 0xF4, 0xF4, 0x04, 0xD2]
|
|
||||||
- [0x00, 0x0B, 0x03, 0x37, 0x04, 0x9A, 0x06, 0x02, 0x06, 0x6B, 0x09, 0x27, 0x0B, 0xE8, 0x0D, 0x0A, 0x12, 0x5A, 0x17, 0x9B, 0x14, 0x8F, 0x1C, 0x96, 0x00, 0x00]
|
|
||||||
- [0x00, 0x0C, 0x09, 0x04, 0x09, 0x09, 0x09, 0x0E, 0x09, 0x0E, 0x09, 0x18, 0x09, 0x1D, 0x12, 0x00, 0x12, 0x0F, 0x12, 0x19, 0x12, 0x23, 0x12, 0x2D, 0x12, 0x37]
|
|
||||||
- [0x01]
|
|
||||||
- [0x05]
|
|
||||||
- [0x03, 0x0D, 0x00, 0x00, 0x21, 0x02, 0x26, 0x32]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x04, 0x54]
|
|
@ -1,19 +0,0 @@
|
|||||||
name: STC12C2052AD programming test
|
|
||||||
protocol: stc12a
|
|
||||||
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
|
|
||||||
responses:
|
|
||||||
- [0x00, 0x04, 0xEC, 0x04, 0xEC, 0x04, 0xEC, 0x04, 0xEC, 0x04, 0xEC, 0x04, 0xEC, 0x04, 0xEB, 0x04, 0xEB, 0x58, 0x44, 0x00, 0xF2, 0x12, 0x83, 0xFD, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFD, 0xF7, 0xF7, 0xFF]
|
|
||||||
- [0x8F, 0xC0, 0x79, 0x3F, 0xFE, 0x28, 0x85]
|
|
||||||
- [0x8E, 0xC0, 0x79, 0x3F, 0xFE, 0x28]
|
|
||||||
- [0x80]
|
|
||||||
- [0x80]
|
|
||||||
- [0x80]
|
|
||||||
- [0x80]
|
|
||||||
- [0x80]
|
|
||||||
- [0x80, 0x66]
|
|
||||||
- [0x80, 0x80]
|
|
||||||
- [0x80, 0x80]
|
|
||||||
- [0x80, 0x80]
|
|
||||||
- [0x80, 0xEE]
|
|
||||||
- [0x10, 0xC0, 0x16, 0xF7, 0xFF, 0xBF, 0x03, 0xFF, 0x58, 0x44, 0xFD, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFD, 0xF7, 0xF7, 0xFF]
|
|
||||||
- [0x80]
|
|
@ -1,15 +0,0 @@
|
|||||||
name: STC12C5A60S2 programming test
|
|
||||||
protocol: stc12
|
|
||||||
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
|
|
||||||
responses:
|
|
||||||
- [0x50, 0x04, 0xBD, 0x04, 0xBC, 0x04, 0xBC, 0x04, 0xBD, 0x04, 0xBC, 0x04, 0xBC, 0x04, 0xBC, 0x04, 0xBC, 0x62, 0x49, 0x00, 0xD1, 0x7E, 0x8C, 0xFF, 0x7F, 0xF7, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x00, 0xB0, 0x02, 0x2E, 0x6B, 0x00, 0xCD, 0x80, 0x00, 0x00]
|
|
||||||
- [0x8F]
|
|
||||||
- [0x8F, 0xC0, 0x7E, 0x3F, 0xFE, 0xA0, 0x83, 0x04]
|
|
||||||
- [0x84, 0xC0, 0x7E, 0x3F, 0xFE, 0xA0, 0x04]
|
|
||||||
- [0x00]
|
|
||||||
- [0x00, 0x03]
|
|
||||||
- [0x00, 0x00]
|
|
||||||
- [0x00, 0x00]
|
|
||||||
- [0x00, 0x00]
|
|
||||||
- [0x8D]
|
|
||||||
- [0x50, 0xFF, 0x7F, 0xF7, 0xFF, 0xFF, 0x03, 0xFF, 0x62, 0x49, 0xFF, 0x7F, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x03, 0x00, 0xB0, 0x02, 0x2E, 0x6B, 0x00, 0xCD, 0x80, 0x00, 0x00]
|
|
@ -1,20 +0,0 @@
|
|||||||
name: STC15F104E programming test
|
|
||||||
protocol: stc15a
|
|
||||||
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
|
|
||||||
responses:
|
|
||||||
- [0x50, 0x02, 0xB0, 0x02, 0xB0, 0x02, 0xAF, 0x02, 0xB0, 0x02, 0xE6, 0x02, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x67, 0x51, 0xFF, 0xF2, 0x94, 0x8C, 0xEF, 0x3B, 0xF5, 0x58, 0x34, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x58, 0x50, 0x0C, 0x94, 0x21, 0xFF, 0x29]
|
|
||||||
- [0x8f]
|
|
||||||
- [0x65, 0x58, 0x50, 0x0C, 0x95, 0x21, 0xFF, 0x2B, 0xFF, 0xFF, 0x06, 0x06, 0x58, 0x00, 0x02, 0x00, 0x58, 0x80, 0x02, 0x00, 0x58, 0x80, 0x02, 0x00, 0x58, 0xFF, 0x02, 0x00, 0x58, 0x00, 0x02, 0x00, 0x58, 0x80, 0x02, 0x00]
|
|
||||||
- [0x65, 0x58, 0x50, 0x0C, 0x95, 0x21, 0xFF, 0x2B, 0xFF, 0xFF, 0x06, 0x0B, 0x58, 0x24, 0x02, 0x00, 0x58, 0x25, 0x02, 0x00, 0x58, 0x26, 0x02, 0x00, 0x58, 0x27, 0x02, 0x00, 0x58, 0x28, 0x02, 0x00, 0x58, 0x29, 0x02, 0x00, 0x58, 0x2A, 0x02, 0x00, 0x58, 0x2B, 0x02, 0x00, 0x58, 0x2C, 0x02, 0x00, 0x58, 0x2D, 0x02, 0x00, 0x58, 0x2E, 0x02, 0x00]
|
|
||||||
- [0x01]
|
|
||||||
- [0x05]
|
|
||||||
- [0x03, 0x0C, 0x00, 0x00, 0x17, 0x01, 0xA0, 0xE0]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x04, 0x54]
|
|
@ -1,19 +0,0 @@
|
|||||||
name: STC15L104W programming test
|
|
||||||
protocol: stc15
|
|
||||||
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
|
|
||||||
responses:
|
|
||||||
- [0x50, 0x66, 0x3C, 0x93, 0xBA, 0xF7, 0xBB, 0x9F, 0x00, 0x5B, 0x68, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x71, 0x51, 0x03, 0xF2, 0xD4, 0x04, 0x06, 0x58, 0xBA, 0x02, 0x2A, 0x31, 0x32, 0x38, 0x30, 0x80, 0x14, 0x10, 0x04, 0xD9]
|
|
||||||
- [0x00, 0x0B, 0x03, 0x0A, 0x04, 0x4F, 0x05, 0x9E, 0x06, 0x20, 0x08, 0xB9, 0x0B, 0x5C, 0x0C, 0x6A, 0x11, 0x7E, 0x16, 0x79, 0x13, 0x77, 0x1A, 0xB1, 0x00, 0x00]
|
|
||||||
- [0x00, 0x0C, 0x04, 0xD6, 0x04, 0xDB, 0x04, 0xE0, 0x04, 0xE0, 0x04, 0xE0, 0x04, 0xE5, 0x11, 0xE2, 0x11, 0xF1, 0x11, 0xFB, 0x12, 0x05, 0x12, 0x0A, 0x12, 0x19]
|
|
||||||
- [0x01]
|
|
||||||
- [0x05]
|
|
||||||
- [0x03, 0x0C, 0x00, 0x00, 0x17, 0x01, 0xA0, 0xE0]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x04, 0x54]
|
|
@ -1,20 +0,0 @@
|
|||||||
name: STC15W4K56S4 programming test
|
|
||||||
protocol: stc15
|
|
||||||
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
|
|
||||||
responses:
|
|
||||||
- [0x50, 0x8D, 0xFF, 0x73, 0x96, 0xF5, 0x7B, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x27, 0xED, 0x00, 0x00, 0x73, 0x54, 0x00, 0xF5, 0x28, 0x04, 0x06, 0x70, 0x96, 0x02, 0x15, 0x19, 0x1C, 0x1E, 0x23, 0x00, 0xEC, 0xE0, 0x04, 0xD7, 0xF8, 0x73, 0xBF, 0xFF, 0xFF, 0x15, 0x09, 0x25, 0x60]
|
|
||||||
- [0x00, 0x0B, 0x0D, 0x21, 0x12, 0xBC, 0x18, 0x3E, 0x1A, 0x05, 0x24, 0xFA, 0x2F, 0xB3, 0x34, 0xD1, 0x4A, 0x52, 0x5E, 0xC0, 0x52, 0xDB, 0x73, 0x1A, 0x00, 0x00]
|
|
||||||
- [0x00, 0x0C, 0x23, 0xBF, 0x23, 0xD3, 0x23, 0xE7, 0x23, 0xF6, 0x24, 0x0F, 0x24, 0x23, 0x47, 0x73, 0x47, 0xB9, 0x47, 0xE1, 0x48, 0x09, 0x48, 0x36, 0x48, 0x59]
|
|
||||||
- [0x01]
|
|
||||||
- [0x05]
|
|
||||||
- [0x03, 0xF5, 0x28, 0x00, 0xA5, 0x03, 0x27, 0x49]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x02, 0x54]
|
|
||||||
- [0x07, 0x54]
|
|
||||||
- [0x04, 0x54]
|
|
@ -1,19 +0,0 @@
|
|||||||
name: STC89C52RC programming test
|
|
||||||
protocol: stc89
|
|
||||||
code_data: [49, 50, 51, 52, 53, 54, 55, 56, 57]
|
|
||||||
responses:
|
|
||||||
- [0x00, 0x25, 0xE6, 0x25, 0xE6, 0x25, 0xE6, 0x25, 0xE6, 0x25, 0xE6, 0x25, 0xE6, 0x25, 0xE2, 0x25, 0xE6, 0x43, 0x43, 0xFC, 0xF0, 0x02, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
|
|
||||||
- [0x8F, 0xFD, 0xF8, 0x02, 0x10, 0x28, 0x81]
|
|
||||||
- [0x8E, 0xFD, 0xF8, 0x02, 0x10, 0x28]
|
|
||||||
- [0x80]
|
|
||||||
- [0x80]
|
|
||||||
- [0x80]
|
|
||||||
- [0x80]
|
|
||||||
- [0x80]
|
|
||||||
- [0x80, 0x66]
|
|
||||||
- [0x80, 0x80]
|
|
||||||
- [0x80, 0x80]
|
|
||||||
- [0x80, 0x80]
|
|
||||||
- [0x8D, 0xFC, 0xFF, 0xF6, 0xFF]
|
|
||||||
- [0x10, 0xC0, 0x16, 0xF6, 0xFF, 0xF1, 0x03, 0xFF, 0x43, 0x43, 0xFC]
|
|
||||||
- [0x80]
|
|
@ -1,119 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2017 Grigori Goronzy <greg@chown.ath.cx>
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
|
||||||
# in the Software without restriction, including without limitation the rights
|
|
||||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
# copies of the Software, and to permit persons to whom the Software is
|
|
||||||
# furnished to do so, subject to the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be included in all
|
|
||||||
# copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
# SOFTWARE.
|
|
||||||
#
|
|
||||||
|
|
||||||
"""Tests with fuzzing of input data"""
|
|
||||||
|
|
||||||
import random
|
|
||||||
import sys
|
|
||||||
import unittest
|
|
||||||
from unittest.mock import patch
|
|
||||||
import yaml
|
|
||||||
import stcgal.frontend
|
|
||||||
import stcgal.protocols
|
|
||||||
from tests.test_program import get_default_opts, convert_to_bytes
|
|
||||||
|
|
||||||
class ByteArrayFuzzer:
|
|
||||||
"""Fuzzer for byte arrays"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.rng = random.Random()
|
|
||||||
self.cut_propability = 0.01 # probability for cutting off an array early
|
|
||||||
self.cut_min = 0 # minimum cut amount
|
|
||||||
self.cut_max = sys.maxsize # maximum cut amount
|
|
||||||
self.bitflip_probability = 0.0001 # probability for flipping a bit
|
|
||||||
self.randomize_probability = 0.001 # probability for randomizing a char
|
|
||||||
|
|
||||||
def fuzz(self, inp):
|
|
||||||
"""Fuzz an array of bytes according to predefined settings"""
|
|
||||||
arr = bytearray(inp)
|
|
||||||
arr = self.cut_off(arr)
|
|
||||||
self.randomize(arr)
|
|
||||||
return bytes(arr)
|
|
||||||
|
|
||||||
def randomize(self, arr):
|
|
||||||
"""Randomize array contents with bitflips and random bytes"""
|
|
||||||
for i, _ in enumerate(arr):
|
|
||||||
for j in range(8):
|
|
||||||
if self.rng.random() < self.bitflip_probability:
|
|
||||||
arr[i] ^= (1 << j)
|
|
||||||
if self.rng.random() < self.randomize_probability:
|
|
||||||
arr[i] = self.rng.getrandbits(8)
|
|
||||||
|
|
||||||
def cut_off(self, arr):
|
|
||||||
"""Cut off data from end of array"""
|
|
||||||
if self.rng.random() < self.cut_propability:
|
|
||||||
cut_limit = min(len(arr), self.cut_max)
|
|
||||||
cut_len = self.rng.randrange(self.cut_min, cut_limit)
|
|
||||||
arr = arr[0:len(arr) - cut_len]
|
|
||||||
return arr
|
|
||||||
|
|
||||||
class TestProgramFuzzed(unittest.TestCase):
|
|
||||||
"""Special programming cycle tests that use a fuzzing approach"""
|
|
||||||
|
|
||||||
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
|
|
||||||
@patch("stcgal.protocols.Stc89Protocol.write_packet")
|
|
||||||
@patch("stcgal.protocols.serial.Serial", autospec=True)
|
|
||||||
@patch("stcgal.protocols.time.sleep")
|
|
||||||
@patch("sys.stdout")
|
|
||||||
@patch("sys.stderr")
|
|
||||||
def test_program_fuzz(self, err, out, sleep_mock, serial_mock, write_mock, read_mock):
|
|
||||||
"""Test programming cycles with fuzzing enabled"""
|
|
||||||
yml = [
|
|
||||||
"./tests/iap15f2k61s2.yml",
|
|
||||||
"./tests/stc12c2052ad.yml",
|
|
||||||
"./tests/stc15w4k56s4.yml",
|
|
||||||
"./tests/stc12c5a60s2.yml",
|
|
||||||
"./tests/stc89c52rc.yml",
|
|
||||||
"./tests/stc15l104w.yml",
|
|
||||||
"./tests/stc15f104e.yml",
|
|
||||||
]
|
|
||||||
fuzzer = ByteArrayFuzzer()
|
|
||||||
fuzzer.cut_propability = 0.01
|
|
||||||
fuzzer.bitflip_probability = 0.005
|
|
||||||
fuzzer.rng = random.Random(1)
|
|
||||||
for y in yml:
|
|
||||||
with self.subTest(msg="trace {}".format(y)):
|
|
||||||
self.single_fuzz(y, serial_mock, fuzzer, read_mock, err, out,
|
|
||||||
sleep_mock, write_mock)
|
|
||||||
|
|
||||||
def single_fuzz(self, yml, serial_mock, fuzzer, read_mock, err, out, sleep_mock, write_mock):
|
|
||||||
"""Test a single programming cycle with fuzzing"""
|
|
||||||
with open(yml) as test_file:
|
|
||||||
test_data = yaml.load(test_file.read())
|
|
||||||
for _ in range(1000):
|
|
||||||
with self.subTest():
|
|
||||||
opts = get_default_opts()
|
|
||||||
opts.protocol = test_data["protocol"]
|
|
||||||
opts.code_image.read.return_value = bytes(test_data["code_data"])
|
|
||||||
serial_mock.return_value.inWaiting.return_value = 1
|
|
||||||
fuzzed_responses = []
|
|
||||||
for arr in convert_to_bytes(test_data["responses"]):
|
|
||||||
fuzzed_responses.append(fuzzer.fuzz(arr))
|
|
||||||
read_mock.side_effect = fuzzed_responses
|
|
||||||
gal = stcgal.frontend.StcGal(opts)
|
|
||||||
self.assertGreaterEqual(gal.run(), 0)
|
|
||||||
err.reset_mock()
|
|
||||||
out.reset_mock()
|
|
||||||
sleep_mock.reset_mock()
|
|
||||||
serial_mock.reset_mock()
|
|
||||||
write_mock.reset_mock()
|
|
||||||
read_mock.reset_mock()
|
|
@ -1,135 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2017 Grigori Goronzy <greg@chown.ath.cx>
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
|
||||||
# in the Software without restriction, including without limitation the rights
|
|
||||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
# copies of the Software, and to permit persons to whom the Software is
|
|
||||||
# furnished to do so, subject to the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be included in all
|
|
||||||
# copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
# SOFTWARE.
|
|
||||||
#
|
|
||||||
|
|
||||||
"""Tests that simulate a whole programming cycle"""
|
|
||||||
|
|
||||||
import unittest
|
|
||||||
from unittest.mock import patch
|
|
||||||
import yaml
|
|
||||||
import stcgal.frontend
|
|
||||||
import stcgal.protocols
|
|
||||||
|
|
||||||
def convert_to_bytes(list_of_lists):
|
|
||||||
"""Convert lists of integer lists to list of byte lists"""
|
|
||||||
return [bytes(x) for x in list_of_lists]
|
|
||||||
|
|
||||||
def get_default_opts():
|
|
||||||
"""Get a default preconfigured option object"""
|
|
||||||
opts = unittest.mock.MagicMock()
|
|
||||||
opts.protocol = "stc89"
|
|
||||||
opts.autoreset = False
|
|
||||||
opts.port = ""
|
|
||||||
opts.baud = 19200
|
|
||||||
opts.handshake = 9600
|
|
||||||
opts.trim = 22118
|
|
||||||
opts.eeprom_image = None
|
|
||||||
opts.debug = False
|
|
||||||
opts.code_image.name = "test.bin"
|
|
||||||
opts.code_image.read.return_value = b"123456789"
|
|
||||||
return opts
|
|
||||||
|
|
||||||
class ProgramTests(unittest.TestCase):
|
|
||||||
"""Test MCU programming cycles for different families, based on traces"""
|
|
||||||
|
|
||||||
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
|
|
||||||
@patch("stcgal.protocols.Stc89Protocol.write_packet")
|
|
||||||
@patch("stcgal.protocols.serial.Serial", autospec=True)
|
|
||||||
@patch("stcgal.protocols.time.sleep")
|
|
||||||
@patch("sys.stdout")
|
|
||||||
def test_program_stc89(self, out, sleep_mock, serial_mock, write_mock, read_mock):
|
|
||||||
"""Test a programming cycle with STC89 protocol"""
|
|
||||||
self._program_yml("./tests/stc89c52rc.yml", serial_mock, read_mock)
|
|
||||||
|
|
||||||
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
|
|
||||||
@patch("stcgal.protocols.Stc89Protocol.write_packet")
|
|
||||||
@patch("stcgal.protocols.serial.Serial", autospec=True)
|
|
||||||
@patch("stcgal.protocols.time.sleep")
|
|
||||||
@patch("sys.stdout")
|
|
||||||
def test_program_stc12(self, out, sleep_mock, serial_mock, write_mock, read_mock):
|
|
||||||
"""Test a programming cycle with STC12 protocol"""
|
|
||||||
self._program_yml("./tests/stc12c5a60s2.yml", serial_mock, read_mock)
|
|
||||||
|
|
||||||
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
|
|
||||||
@patch("stcgal.protocols.Stc89Protocol.write_packet")
|
|
||||||
@patch("stcgal.protocols.serial.Serial", autospec=True)
|
|
||||||
@patch("stcgal.protocols.time.sleep")
|
|
||||||
@patch("sys.stdout")
|
|
||||||
def test_program_stc12a(self, out, sleep_mock, serial_mock, write_mock, read_mock):
|
|
||||||
"""Test a programming cycle with STC12A protocol"""
|
|
||||||
self._program_yml("./tests/stc12c2052ad.yml", serial_mock, read_mock)
|
|
||||||
|
|
||||||
def test_program_stc12b(self):
|
|
||||||
"""Test a programming cycle with STC12B protocol"""
|
|
||||||
self.skipTest("trace missing")
|
|
||||||
|
|
||||||
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
|
|
||||||
@patch("stcgal.protocols.Stc89Protocol.write_packet")
|
|
||||||
@patch("stcgal.protocols.serial.Serial", autospec=True)
|
|
||||||
@patch("stcgal.protocols.time.sleep")
|
|
||||||
@patch("sys.stdout")
|
|
||||||
def test_program_stc15f2(self, out, sleep_mock, serial_mock, write_mock, read_mock):
|
|
||||||
"""Test a programming cycle with STC15 protocol, F2 series"""
|
|
||||||
self._program_yml("./tests/iap15f2k61s2.yml", serial_mock, read_mock)
|
|
||||||
|
|
||||||
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
|
|
||||||
@patch("stcgal.protocols.Stc89Protocol.write_packet")
|
|
||||||
@patch("stcgal.protocols.serial.Serial", autospec=True)
|
|
||||||
@patch("stcgal.protocols.time.sleep")
|
|
||||||
@patch("sys.stdout")
|
|
||||||
def test_program_stc15w4(self, out, sleep_mock, serial_mock, write_mock, read_mock):
|
|
||||||
"""Test a programming cycle with STC15 protocol, W4 series"""
|
|
||||||
self._program_yml("./tests/stc15w4k56s4.yml", serial_mock, read_mock)
|
|
||||||
|
|
||||||
@unittest.skip("trace is broken")
|
|
||||||
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
|
|
||||||
@patch("stcgal.protocols.Stc89Protocol.write_packet")
|
|
||||||
@patch("stcgal.protocols.serial.Serial", autospec=True)
|
|
||||||
@patch("stcgal.protocols.time.sleep")
|
|
||||||
@patch("sys.stdout")
|
|
||||||
def test_program_stc15a(self, out, sleep_mock, serial_mock, write_mock, read_mock):
|
|
||||||
"""Test a programming cycle with STC15A protocol"""
|
|
||||||
self._program_yml("./tests/stc15f104e.yml", serial_mock, read_mock)
|
|
||||||
|
|
||||||
@patch("stcgal.protocols.StcBaseProtocol.read_packet")
|
|
||||||
@patch("stcgal.protocols.Stc89Protocol.write_packet")
|
|
||||||
@patch("stcgal.protocols.serial.Serial", autospec=True)
|
|
||||||
@patch("stcgal.protocols.time.sleep")
|
|
||||||
@patch("sys.stdout")
|
|
||||||
def test_program_stc15l1(self, out, sleep_mock, serial_mock, write_mock, read_mock):
|
|
||||||
"""Test a programming cycle with STC15 protocol, L1 series"""
|
|
||||||
self._program_yml("./tests/stc15l104w.yml", serial_mock, read_mock)
|
|
||||||
|
|
||||||
def test_program_stc15w4_usb(self):
|
|
||||||
"""Test a programming cycle with STC15W4 USB protocol"""
|
|
||||||
self.skipTest("USB not supported yet, trace missing")
|
|
||||||
|
|
||||||
def _program_yml(self, yml, serial_mock, read_mock):
|
|
||||||
"""Program MCU with data from YAML file"""
|
|
||||||
with open(yml) as test_file:
|
|
||||||
test_data = yaml.load(test_file.read())
|
|
||||||
opts = get_default_opts()
|
|
||||||
opts.protocol = test_data["protocol"]
|
|
||||||
opts.code_image.read.return_value = bytes(test_data["code_data"])
|
|
||||||
serial_mock.return_value.inWaiting.return_value = 1
|
|
||||||
read_mock.side_effect = convert_to_bytes(test_data["responses"])
|
|
||||||
gal = stcgal.frontend.StcGal(opts)
|
|
||||||
self.assertEqual(gal.run(), 0)
|
|
@ -1,76 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright (c) 2017 Grigori Goronzy <greg@chown.ath.cx>
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
|
||||||
# in the Software without restriction, including without limitation the rights
|
|
||||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
# copies of the Software, and to permit persons to whom the Software is
|
|
||||||
# furnished to do so, subject to the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be included in all
|
|
||||||
# copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
# SOFTWARE.
|
|
||||||
#
|
|
||||||
|
|
||||||
"""Tests for utility functions and other misc parts"""
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import unittest
|
|
||||||
from stcgal.utils import Utils, BaudType
|
|
||||||
|
|
||||||
class TestUtils(unittest.TestCase):
|
|
||||||
"""Test for utility functions in the Utils class"""
|
|
||||||
|
|
||||||
def test_to_bool(self):
|
|
||||||
"""Test special utility function for bool conversion"""
|
|
||||||
self.assertTrue(Utils.to_bool(True))
|
|
||||||
self.assertTrue(Utils.to_bool("true"))
|
|
||||||
self.assertTrue(Utils.to_bool("True"))
|
|
||||||
self.assertTrue(Utils.to_bool("t"))
|
|
||||||
self.assertTrue(Utils.to_bool("T"))
|
|
||||||
self.assertTrue(Utils.to_bool(1))
|
|
||||||
self.assertTrue(Utils.to_bool(-1))
|
|
||||||
self.assertFalse(Utils.to_bool(0))
|
|
||||||
self.assertFalse(Utils.to_bool(None))
|
|
||||||
self.assertFalse(Utils.to_bool("false"))
|
|
||||||
self.assertFalse(Utils.to_bool("False"))
|
|
||||||
self.assertFalse(Utils.to_bool("f"))
|
|
||||||
self.assertFalse(Utils.to_bool("F"))
|
|
||||||
self.assertFalse(Utils.to_bool(""))
|
|
||||||
|
|
||||||
def test_to_int(self):
|
|
||||||
"""Test wrapped integer conversion"""
|
|
||||||
self.assertEqual(Utils.to_int("2"), 2)
|
|
||||||
self.assertEqual(Utils.to_int("0x10"), 16)
|
|
||||||
with self.assertRaises(ValueError):
|
|
||||||
Utils.to_int("a")
|
|
||||||
with self.assertRaises(ValueError):
|
|
||||||
Utils.to_int("")
|
|
||||||
with self.assertRaises(ValueError):
|
|
||||||
Utils.to_int(None)
|
|
||||||
|
|
||||||
def test_hexstr(self):
|
|
||||||
"""Test byte array formatter"""
|
|
||||||
self.assertEqual(Utils.hexstr([10]), "0A")
|
|
||||||
self.assertEqual(Utils.hexstr([1, 2, 3]), "010203")
|
|
||||||
with self.assertRaises(Exception):
|
|
||||||
Utils.hexstr([400, 500])
|
|
||||||
|
|
||||||
class TestBaudType(unittest.TestCase):
|
|
||||||
"""Test BaudType class"""
|
|
||||||
|
|
||||||
def test_create_baud_type(self):
|
|
||||||
"""Test creation of BaudType instances"""
|
|
||||||
baud_type = BaudType()
|
|
||||||
self.assertEqual(baud_type("2400"), 2400)
|
|
||||||
self.assertEqual(baud_type("115200"), 115200)
|
|
||||||
with self.assertRaises(argparse.ArgumentTypeError):
|
|
||||||
baud_type("2374882")
|
|
Reference in New Issue
Block a user