78 Commits

Author SHA1 Message Date
a414bfb864 protocols.py: Increase clock_safety_factor to 2.5
This fixes cp2102 and ch341a baudswitch on mac sierra

Signed-off-by: Andrew 'ncrmnt' Andrianov <andrew@ncrmnt.org>
2017-10-14 21:08:26 +03:00
68d19f7b88 Use calculated delays
Some serial drivers don't handle draining the transmit buffer
correctly. This has been handled with a long delay so far, which might
be problematic. There's a race condition with some protocol versions.

Until STC15, the baud rate switch is initiated with a command sent by
stcgal, which is replied to by the MCU with the new baud rate. So the
switch of the baud rate has to be done after the command has finished
transmission, but before the MCU has started to transmit the response.

This change calculates the minimum delay needed (with some tolerance
added) so that it's unlikely that the baud rate switch will happen
too late.
2017-10-10 22:11:07 +02:00
ebcfeb467c Merge pull request #27 from nekromant/fixes
Implement power-cycling via a custom shell cmd, update models.py
2017-10-09 00:05:55 +02:00
d7e226df6b README.md: Document -r option properly
Signed-off-by: Andrew Andrianov <andrew@ncrmnt.org>
2017-10-08 23:58:31 +03:00
191a580469 protocols: Move device reset logic to a separate method
Signed-off-by: Andrew Andrianov <andrew@ncrmnt.org>
2017-10-08 23:20:17 +03:00
c131a9d901 frontend: Use command instead of cmd in description
Signed-off-by: Andrew Andrianov <andrew@ncrmnt.org>
2017-10-08 23:19:55 +03:00
3f4263e8fe models.py: Add some STC15xxx definitions from stcdude's mcudb
Signed-off-by: Andrew Andrianov <andrew@ncrmnt.org>
2017-10-07 23:30:03 +03:00
ba4faf9c43 Implement power-cycling via custom shell command
Sometimes instead of DTR line some custom way (e.g SoC gpio line)
may be used to reset the device. This commit implements
automated power-cycling using a a custom shell command that can
be specified via -r option

Signed-off-by: Andrew Andrianov <andrew@ncrmnt.org>
2017-10-07 22:41:49 +03:00
f1bafb1e0d Update version to 1.4 2017-09-19 18:00:02 +02:00
fdd6707d2d Add Travis CI for CI and CD
Run tests for each commit and deploy packages (deb/rpm) for each
release tag.
2017-09-19 17:54:26 +02:00
532363d97b Exclude test directory from build 2017-09-18 15:42:08 +02:00
5865b06f7f Add STC15W4K56S4 programming test 2017-09-02 10:23:06 +02:00
1b69257cd3 Add missing STC15F104E trace
Currently broken, needs retracing.
2017-09-02 10:12:14 +02:00
38ac5f0788 Add STC15L104W programming test 2017-09-02 08:05:13 +02:00
6dccf13fb6 Add missing test dependency
PyYAML is needed to parse the programming simulation data.
2017-09-02 00:08:28 +02:00
0ca8b2ea2d Ensure hexstr helper actually received a list of bytes
Otherwise, the formatted output is rather bogus. Found with a test case.
2017-09-02 00:00:27 +02:00
53184b549e Handle None in to_bool utility
None is commonly used, so we want to be able to handle it with this helper.
Found with a test case.
2017-09-01 23:59:05 +02:00
cf68e3c6dc Add initial tests
This adds various tests, integrated into setuptools. These use "monkey
patching" where needed to mock the pyserial and packet reader/writer
functionality to allow for testing with no changes.

The code should be refactored to simplify testing, but this is good enough
to stop regressions for now.
2017-09-01 23:55:46 +02:00
5d10c06f1e Add Visual Studio Code to gitignore 2017-08-31 21:08:57 +02:00
7e84b8e0fb Fix some additional code smells
No functional change intended.
2017-08-31 21:07:56 +02:00
f34ba6644f Fix option error handling for STC12A LVD 2017-06-16 10:22:24 +02:00
f15b64f4f7 Fix some minor code smells reported by pylint
No functional change intended.
2017-06-16 10:21:43 +02:00
2e822375e0 Update Debian packaging scripts for 1.3 2017-06-10 10:02:53 +02:00
7d6e8e9bfd Update version to 1.3 2017-06-10 09:55:38 +02:00
506289b8ee Add __main__ module
This allows stcgal to be started with "python3 -m stcgal" or similar.
Addresses stcgal#24.
2017-06-09 21:03:07 +02:00
f417b6eed5 Add new compatibility report
Closes #20.
2016-11-22 10:23:47 +01:00
86e289b65c usb15: add basic protocol information
These are just my notes from reverse engineering.
2016-06-10 21:12:17 +02:00
53f9544281 stc15: fix RC oscillator baudrate switch packet
It looks like it wasn't correct. The last value sent is probably
supposed to be the trim value for the chosen trim frequency.

Found while investigating grigorig/stcgal#16.
2016-06-10 12:45:58 +02:00
65a7759647 stc12+: drop checksum verification for flashing
It's not needed on STC12 and up. All transfers are error checked with
parity and a 16-bit modular sum already. STC15 dropped the verification
checksum on the protocol level, it's not sent with the write status
packet, which is a testament to this not being needed.

Some parts store the UID in the last bytes of flash memory and this
verification actually caused incorrect verification failures because
of the verification, which apparently read the UID on verification
readback.

Fixes grigorig/stcgal#15.
2016-05-28 11:25:44 +02:00
8ad77586d4 Update version to 1.2 2016-05-20 03:22:24 +02:00
276c696fa4 frontend: enable protocol autodetection by default
It seems to work rather well after some extended testing. Also clean
up and update the protocol documentation while at it.
2016-05-20 02:59:35 +02:00
26ef34991b usb15: abort if permission denied
Don't ignore permission denied when looking for a suitable USB device.
Otherwise users don't notice what the problem is, stcgal will just
keep waiting on the prompt.
2016-05-20 02:55:23 +02:00
f90fe4152b Add STC12B protocol variant
This is just like STC12, but with the STC12A option packet. Used by
STC12xx52 series, STC12xx56 series and possibly others.

Fixes grigorig/stcgal#14.
2016-05-20 02:54:57 +02:00
d6ef028dc7 Extract mix-ins for STC12 and STC12A options
This simplifies code down the line. No functional change intended.
2016-05-20 02:44:50 +02:00
979d7f513f Get rid of USB bmRequestType constants
These constants were calculated on class loading, which didn't work
without pyusb. USB support is going to remain optional.
2016-05-18 16:40:09 +02:00
fce2f01232 Extract option classes into separate file 2016-05-18 02:38:13 +02:00
854f36100b stc12: fix option handling
MCS3 index was wrong. Also, write MCS3 to two possible indices in
the option set packet.

Addresses grigorig/stcgal#14.
2016-05-18 02:14:02 +02:00
92f4def11a stc12a: revamp option handling
Completely revamp option handling. This fixes a wrong index of MCS4,
which is now renamed to MCS3. Now programming should be exactly
similar to STC-ISP 6.85M.

This also renames the values of the low_voltage_reset option for
clarity.

Also update the documentation and clarity the meaning of the option
according to protocol family.

Addresses grigorig/stcgal#14.
2016-05-18 01:40:08 +02:00
6c0af88551 frontend: always pad to 512 bytes, fill with 0xff
This seems to be the default of STC-ISP, so let's use it for possibly
improved compatibility.
2016-05-18 00:56:16 +02:00
366a3a5bd3 Fix EEPROM size of STC12x54 series in MCU database 2016-05-15 02:39:51 +02:00
c046e886e3 usb15: add protocol notes 2016-05-15 02:31:36 +02:00
7ba95eab68 stc15/usb15: add password feature notes
I'm not going to implement this right now as it is rather dangerous.
2016-05-15 02:30:25 +02:00
61a4fa0e4f stc89: add missing output flush 2016-05-14 21:37:27 +02:00
da5f6678c5 usb15: sanity check on status packet reads
If a previous stcgal invocation is aborted, we can be in a bad state
upon connect. Add a simple sanity check based on packet length to
detect this and drop unsuitable packets.
2016-05-14 21:03:07 +02:00
a8f141584d Merge branch 'usbisp'
It is still experimental, but the changes are not very invasive, so why
not include it right now. Closes grigorig/stcgal#10.
2016-05-14 13:26:57 +02:00
adcb8d8ced README: add details of usb15 protocol mode 2016-05-14 13:21:43 +02:00
81c890337e usb15: make USB support optional 2016-05-14 13:03:03 +02:00
9af984a191 Add USB-ISP support for STC15W4 series
The STC15W4 series have an additional USB BSL mode which kind of wraps
the serial protocol. It just uses basic USB control transfers. This
adds support for this mode, based on the existing STC15 code. pyusb is
required as an additional dependency. The new protocol mode is called
"usb15". There are some shortcomings, for instance timing of erase
and programming operations is problematic and right now only delays
are used. Also, only a single USB-ISP device is supported and the
first one found is always used.

Flash programming and setting options has been mildly tested on an
STC15W4K56S4 MCU.
2016-05-14 12:50:14 +02:00
2738118e8f stc15: extract build_options method
This will allow use to reuse code for upcoming USB-ISP support.
2016-05-14 12:43:15 +02:00
eedf9169a7 stc15: add error reporting for locked MCUs
It is possible to lock devices with a password against flashing. This
feature is not currently supported by stcgal, so at least output a
sensible message.
2016-05-13 02:54:43 +02:00
cb739e6f94 Add exit status to documentation 2016-05-12 01:48:02 +02:00
2a770bb37f Add missing license header 2016-05-12 01:25:22 +02:00
8fe94e001f Update list of compatible MCUs 2016-05-12 01:19:31 +02:00
b1ed017137 Add protocol detection to documentation 2016-05-12 01:07:27 +02:00
678d001ec5 Print informational message after protocol detection 2016-05-12 01:04:34 +02:00
f8e8d66baa Merge pull request #13 from laborer/master
Add automatic protocol detection
2016-05-12 00:11:10 +02:00
afba6c6805 Add automatic protocol detection
The model of the target MCU and its protocol is detected using model ID provided in the first packet (status packet) from the MCU.

Tested working models include,
IAP15F2K61S2 (BSL version: 7.1.4S, protocol: stc15)
STC15F104W (BSL version: 7.1.4Q, protocol: stc15)
TC11F02E (BSL version: 6.5K, protocol: stc12)
STC10F04XE (BSL version: 6.5J, protocol: stc12)
STC12C5A16S2 (BSL version: 6.2I, protocol: stc12)
STC12C5608AD (BSL version: 6.0G, protocol: stc12)
STC12C2052 (BSL version: 5.8D, protocol: stc12a)
STC90C52RC (BSL version: 4.3C, protocol: stc89)
STC89C52RC (BSL version: 4.3C, protocol: stc89)
STC89C54RD+ (BSL version: 4.3C, protocol: stc89)
STC15F104E (BSL version: 6.7Q, protocol: stc15a)

STC15F104E uses a different status packet protocol than other MCUs; it waits for an ACK packet before sending out the status packet.  Another problem is that STC15F104E shares the same model magic with STC15F104W.  Fortunately, these two models can be differentiated by their BSL version numbers.
2016-05-11 15:14:13 -04:00
d1f464c387 Raise default handshake baudrate to 2400
See grigorig/stcgal#12 for more information.
2016-04-15 11:13:54 +02:00
e268b282cb Update dump-mcu.py for stc-isp 6.85K
v2: squash "Update model DB"
2016-04-14 18:53:45 +02:00
f9a19c927c Update README.md 2016-04-02 23:13:51 +02:00
372f854c77 Add autoreset feature via DTR control line
This is inspired by Arduino.  Directly before connect, DTR is asserted
for 0.5 seconds and then deasserted again.  With a small external
circuit, the MCU can be power-cycled with this control signal.
In case the MCU draws very little power, it may even be possible to
supply power directly from the DTR pin.
2016-04-02 23:00:07 +02:00
41cabb587b frontend: also catch I/O errors in pulse phase 2016-01-17 15:16:43 +01:00
6a38127c0d Fix regression with some STC15 parts
The cpu core voltage setting is only available on newer parts, so do not
try to support it on older ones. The option packet is too short on some
parts, which resulted in an assertion hit.

There may be a nicer solution, but this works for now.

Fixes grigorig/stcgal#6.
2016-01-05 07:03:59 +01:00
d3911870c3 Fix initialization with CH340 UARTs
Initialization is messed up on older Linux kernels and that results
in 9600 baud being used unconditionally in some cases. Setting the
baud rate separately seems to work around this successfully.

Fixes grigorig/stcgal#5.
2015-12-15 20:22:25 +01:00
293ce2c749 Add STC15W408AS to compatibility list
Tested and works fine.
2015-12-12 01:03:14 +01:00
f13650a352 stc15: remove extra space in output 2015-12-11 01:50:55 +01:00
f5574f30e3 frontend: rename code_binary/eeprom_binary
We don't accept binary only anymore.
2015-12-11 01:49:45 +01:00
bc6f9da03e frontend: nicer description 2015-12-11 01:38:46 +01:00
6f0ee0387d serial: flush input on connect
Sometimes there's some garbage in the input buffer and we aren't
interested in that.
2015-12-11 01:21:06 +01:00
cc20c85ad0 Add STC15W4K56S4 dump 2015-12-11 01:14:51 +01:00
b71b6535c4 Add STC15W4K56S4 to compatibility list
Seems to work just fine for me now.
2015-12-11 01:13:35 +01:00
76b3418f0a stc15: add core voltage option (STC15W)
This is used on STC15W4 series and has no function on earlier MCUs.
There is no good way to filter options, unfortunately.
2015-12-11 01:11:53 +01:00
11b165c02c stc15a: set pulse timeout for handshake 2015-12-11 00:40:22 +01:00
9f42ef29f3 stc15: use generic/new sync sequence for handshake
Use the newer sync sequence. Refactor the pulse() function to make
it somewhat generic, so we can use it without worrying about writing
the exactly right number of bytes.

This seems to get STC15W4 series chips working.
2015-12-11 00:39:59 +01:00
432fed8af1 Add STC11F02E to compatibility list 2015-12-06 19:45:29 +01:00
7336673655 Add STC15L2K61S2 to README
See https://github.com/grigorig/stcgal/issues/3
2015-11-30 00:51:51 +01:00
0548582dd4 Add initial debian packaging info
v2 (Grigori Goronzy): Simplify with pybuild, fix some smaller issues,
license as MIT.

Signed-off-by: Andrew Andrianov <andrew@ncrmnt.org>
2015-11-25 23:03:25 +01:00
e0afd851ae Let MCU detection recover faster
Use small timeouts to recover faster if there is a misdetection for
whatever reason (truncated packet, user program toggles port, etc.).
2015-11-25 22:19:54 +01:00
35 changed files with 2240 additions and 941 deletions

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ __pycache__
/build /build
/dist /dist
/deb_dist /deb_dist
/.vscode

33
.travis.yml Normal file
View File

@ -0,0 +1,33 @@
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
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"

116
README.md
View File

@ -1,18 +1,21 @@
[![Build Status](https://travis-ci.org/grigorig/stcgal.svg)](https://travis-ci.org/grigorig/stcgal)
stcgal - STC MCU ISP flash tool stcgal - STC MCU ISP flash tool
=============================== ===============================
stcgal is a command line flash programming tool for STC MCU Ltd. [1] stcgal is a command line flash programming tool for STC MCU Ltd. [1]
8051 compatible microcontrollers. The name was inspired by avrdude [2]. 8051 compatible microcontrollers. The name was inspired by avrdude [2].
STC microcontrollers have a UART based boot strap loader (BSL). It STC microcontrollers have an UART/USB based boot strap loader (BSL). It
utilizes a packet-based protocol to flash the code memory and IAP utilizes a packet-based protocol to flash the code memory and IAP
memory over a serial link. This is referred to as in-system programming (ISP). memory over a serial link. This is referred to as in-system programming
The BSL is also used to configure various (fuse-like) device (ISP). The BSL is also used to configure various (fuse-like) device
options. Unfortunately, this protocol is not publicly documented and options. Unfortunately, this protocol is not publicly documented and
STC only provide a (crude) Windows GUI application for programming. STC only provide a (crude) Windows GUI application for programming.
stcgal is a full-featured Open Source replacement for STC's Windows software; stcgal is a full-featured Open Source replacement for STC's Windows
it supports a wide range of MCUs, it is very portable and suitable for automation. software; it supports a wide range of MCUs, it is very portable and
suitable for automation.
[1] http://stcmcu.com/ [1] http://stcmcu.com/
[2] http://www.nongnu.org/avrdude/ [2] http://www.nongnu.org/avrdude/
@ -24,20 +27,33 @@ 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) * STC89C52RC (BSL version: 4.3C/6.6C)
* STC90C52RC (BSL version: 4.3C)
* STC89C54RD+ (BSL version: 4.3C)
* STC12C2052 (BSL version: 5.8D)
* STC12C2052AD (BSL version: 5.8D) * STC12C2052AD (BSL version: 5.8D)
* STC12C5A60S2 (BSL version: 6.2I) * STC12C5608AD (BSL version: 6.0G)
* STC12C5A16S2 (BSL version: 6.2I)
* STC12C5A60S2 (BSL version: 6.2I/7.1I)
* STC11F02E (BSL version: 6.5K)
* STC10F04XE (BSL version: 6.5J)
* STC11F08XE (BSL version: 6.5M) * STC11F08XE (BSL version: 6.5M)
* STC12C5204AD (BSL version: 6.6H)
* STC15F104E (BSL version: 6.7Q) * STC15F104E (BSL version: 6.7Q)
* STC15F204EA (BSL version: 6.7R) * STC15F204EA (BSL version: 6.7R)
* STC15L104W (BSL version: 7.1Q) * STC15L104W (BSL version: 7.1.4Q)
* IAP15F2K61S2 (BSL version: 7.1S) * STC15F104W (BSL version: 7.1.4Q)
* IAP15F2K61S2 (BSL version: 7.1.4S)
* STC15L2K16S2 (BSL version: 7.2.4S)
* STC15W408AS (BSL version: 7.2.4T)
* STC15W4K56S4 (BSL version: 7.3.4T, UART and USB mode)
More compatibility testing is going to happen soon. Compatibility reports, both negative and positive, are welcome.
Features Features
-------- --------
* UART and USB BSL support
* Display part info * Display part info
* Determine operating frequency * Determine operating frequency
* Program flash memory * Program flash memory
@ -45,11 +61,14 @@ Features
* Set device options * Set device options
* Read unique device ID (STC 10/11/12/15) * Read unique device ID (STC 10/11/12/15)
* Trim RC oscillator frequency (STC 15) * Trim RC oscillator frequency (STC 15)
* Automatic power-cycling with DTR toggle or a custom shell command
* Automatic UART protocol detection
Installation Installation
------------ ------------
stcgal requires Python 3.2 (or later) and pySerial. You can run stcgal stcgal requires Python 3.2 (or later) and pySerial. USB support is
optional and requires pyusb 1.0.0b2 or later. You can run stcgal
directly with the included ```stcgal.py``` script. The recommended directly with the included ```stcgal.py``` script. The recommended
method for permanent installation is to use Python's setuptools. Run method for permanent installation is to use Python's setuptools. Run
```./setup.py build``` to build and ```sudo ./setup.py install``` ```./setup.py build``` to build and ```sudo ./setup.py install```
@ -62,24 +81,30 @@ Usage
Call stcgal with ```-h``` for usage information. Call stcgal with ```-h``` for usage information.
``` ```
usage: stcgal.py [-h] [-P {stc89,stc12a,stc12,stc15a,stc15}] [-p PORT] usage: stcgal.py [-h] [-a] [-P {stc89,stc12a,stc12,stc15a,stc15,auto}]
[-b BAUD] [-l HANDSHAKE] [-o OPTION] [-t TRIM] [-D] [-p PORT] [-b BAUD] [-l HANDSHAKE] [-o OPTION] [-t TRIM] [-D]
[code_binary] [eeprom_binary] [code_image] [eeprom_image]
stcgal 1.0 - an STC MCU ISP flash tool stcgal 1.0 - an STC MCU ISP flash tool
(C) 2014-2015 Grigori Goronzy
https://github.com/grigorig/stcgal
positional arguments: positional arguments:
code_binary code segment binary file to flash code_image code segment file to flash (BIN/HEX)
eeprom_binary eeprom segment binary file to flash eeprom_image eeprom segment file to flash (BIN/HEX)
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
-P {stc89,stc12a,stc12,stc15a,stc15}, --protocol {stc89,stc12a,stc12,stc15a,stc15} -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}
protocol version protocol version
-p PORT, --port PORT serial port device -p PORT, --port PORT serial port device
-b BAUD, --baud BAUD transfer baud rate (default: 19200) -b BAUD, --baud BAUD transfer baud rate (default: 19200)
-l HANDSHAKE, --handshake HANDSHAKE -l HANDSHAKE, --handshake HANDSHAKE
handshake baud rate (default: 1200) handshake baud rate (default: 2400)
-o OPTION, --option OPTION -o OPTION, --option OPTION
set option (can be used multiple times) set option (can be used multiple times)
-t TRIM, --trim TRIM RC oscillator frequency in kHz (STC15 series only) -t TRIM, --trim TRIM RC oscillator frequency in kHz (STC15 series only)
@ -91,14 +116,18 @@ Most importantly, ```-p``` sets the serial port to be used for programming.
### Protocols ### Protocols
STC MCUs use a variety of related but incompatible protocols for the STC MCUs use a variety of related but incompatible protocols for the
BSL. The protocol must be specified with the ```-P``` flag. Here's BSL. The protocol can be specified with the ```-P``` flag. By default
the general mapping between protocols and MCU series: UART protocol autodetection is used. The mapping between protocols
and MCU series is as follows:
* ```stc89``` STC89/90 series * ```stc89``` STC89/90 series
* ```stc12a``` STC12Cx052AD and possibly others * ```stc12a``` STC12x052 series and possibly others
* ```stc12b``` STC12x52 series, STC12x56 series and possibly others
* ```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
* ```usb15``` USB support on STC15W4 series
* ```auto``` Automatic detection of UART based protocols (default)
The text files in the doc/ subdirectory provide an overview over The text files in the doc/ subdirectory provide an overview over
the reverse engineered protocols used by the BSLs. For more details, the reverse engineered protocols used by the BSLs. For more details,
@ -217,7 +246,9 @@ Option key | Possible values | Protocols/Models | Descri
```ale_enabled``` | true/false | STC89 only | ALE pin enabled if true, normal GPIO if false ```ale_enabled``` | true/false | STC89 only | ALE pin enabled if true, normal GPIO if false
```xram_enabled``` | true/false | STC89 only | Use internal XRAM (STC89 only) ```xram_enabled``` | true/false | STC89 only | Use internal XRAM (STC89 only)
```watchdog_por_enabled``` | true/false | All | Watchdog state after power-on reset (POR) ```watchdog_por_enabled``` | true/false | All | Watchdog state after power-on reset (POR)
```low_voltage_reset ``` | true/false | STC12A+ | Low-voltage reset (brownout) ```low_voltage_reset``` | low/high | STC12A/STC12 | Low-voltage reset level (low: ~3.3V, high: ~3.7V)
```low_voltage_reset``` | true/false | STC12 | Enable RESET2 pin low voltage detect
```low_voltage_reset``` | true/false | STC15A | Enable low-voltage reset (brownout)
```clock_source``` | internal/external | STC12A+ with XTAL | Use internal (RC) or external (crystal) clock ```clock_source``` | internal/external | STC12A+ with XTAL | Use internal (RC) or external (crystal) clock
```watchdog_stop_idle``` | true/false | STC12A+ | Stop watchdog in IDLE mode ```watchdog_stop_idle``` | true/false | STC12A+ | Stop watchdog in IDLE mode
```watchdog_prescale``` | 2,4,8,...,256 | STC12A+ | Watchdog timer prescaler, must be a power of two. ```watchdog_prescale``` | 2,4,8,...,256 | STC12A+ | Watchdog timer prescaler, must be a power of two.
@ -229,6 +260,7 @@ Option key | Possible values | Protocols/Models | Descri
```rstout_por_state``` | low/high | STC15+ | RSTOUT pin state after power-on reset ```rstout_por_state``` | low/high | STC15+ | RSTOUT pin state after power-on reset
```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)
### Frequency trimming ### Frequency trimming
@ -239,6 +271,46 @@ 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.
### Automatic power-cycling
STC's microcontrollers require a power-on reset to invoke the bootloader,
which can be inconvenient. stcgal can use the DTR control signal of a
serial interface to automate this. The DTR signal is asserted for
approximately 500 ms when the autoreset feature is enabled with the
```-a``` flag. This requires external circuitry to actually switch the
power. In some cases, when the microcontroller draws only little power,
it is possible to directly supply power from the DTR signal.
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
The exit status is 0 if no error occured while executing stcgal. Any
error, such as a protocol error or I/O error, results in an exit
status of 1. If the the user aborted stcgal by pressing CTRL-C,
that results in an exit status of 2.
### USB support
STC15W4 series have an USB-based BSL that can be optionally
used. USB support in stcgal is experimental and might change in the
future. USB mode is enabled by using the ```usb15``` protocol. The
port (```-p```) flag as well as the baudrate options are ignored for
the USB protocol. RC frequency trimming is not supported.
License License
------- -------

24
debian/changelog vendored Normal file
View File

@ -0,0 +1,24 @@
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
* Update to 1.2
* Add optional python3-usb dependency
-- Grigori Goronzy <greg@chown.ath.cx> Fri, 20 May 2016 03:21:25 +0200
stcgal (1.0git) unstable; urgency=low
* Initial Debianized Release
-- Andrew 'Necromant' Andrianov <andrew@ncrmnt.org> Wed, 25 Nov 2015 13:07:03 +0300

1
debian/compat vendored Normal file
View File

@ -0,0 +1 @@
9

27
debian/control vendored Normal file
View File

@ -0,0 +1,27 @@
Source: stcgal
Section: electronics
Priority: optional
Maintainer: Andrew Andrianov <andrew@ncrmnt.org>
Build-Depends: debhelper (>= 9), python3, python3-setuptools, dh-python
Standards-Version: 3.9.5
Homepage: https://github.com/grigorig/stcgal
X-Python3-Version: >= 3.2
Package: stcgal
Architecture: all
Depends: ${misc:Depends}, python3, python3-serial
Recommends: python3-usb (>= 1.0.0~b2)
Description: STC MCU ISP flash tool
stcgal is a command line flash programming tool for STC MCU Ltd.
8051 compatible microcontrollers. The name was inspired by avrdude.
.
STC microcontrollers have an UART/USB based boot strap loader (BSL). It
utilizes a packet-based protocol to flash the code memory and IAP
memory over a serial link. This is referred to as in-system programming
(ISP). The BSL is also used to configure various (fuse-like) device
options. Unfortunately, this protocol is not publicly documented and
STC only provide a (crude) Windows GUI application for programming.
.
stcgal is a full-featured Open Source replacement for STC's Windows
software; it supports a wide range of MCUs, it is very portable and
suitable for automation.

32
debian/copyright vendored Normal file
View File

@ -0,0 +1,32 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: stcgal
Upstream-Contact: Grigori Goronzy <greg@kinoho.net>
Source: https://github.com/grigorig/stcgal
Files: *
Copyright: 2013-2015 Grigori Goronzy <greg@kinoho.net>
License: MIT
Files: debian/*
Copyright: 2015 Andrew 'Necromant' Andrianov <andrew@ncrmnt.org>
2015 Grigori Goronzy <greg@kinoho.net>
License: MIT
License: MIT
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.

2
debian/docs vendored Normal file
View File

@ -0,0 +1,2 @@
README.md
TODO.md

7
debian/rules vendored Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/make -f
export PYBUILD_NAME=stcgal
%:
dh $@ --with python3 --buildsystem=pybuild

1
debian/source/format vendored Normal file
View File

@ -0,0 +1 @@
3.0 (native)

View File

@ -1,13 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# This curious script dumps all model info from STC-ISP. # This curious script dumps all model info from STC-ISP.
# Data is directly read from the binary. # Data is directly read from the binary.
# Offsets are for STC-ISP 6.85I, sha1sum a1a625d6c491fe98d0286ebac0a8d78b94dca81d # Offsets are for stc-isp-15xx-v6.85K.exe, sha1sum aa66e4c1ab49de27369b83c954a7c202acce0950
MCU_TABLE_OFFSET = 0x00063550 MCU_TABLE_OFFSET = 0x00064550
MCU_TABLE_SIZE = 914 MCU_TABLE_SIZE = 941
MCU_RECORD_SIZE = 32 MCU_RECORD_SIZE = 32
MCU_NAMES_OFFSET = 0x0007d708 MCU_NAMES_OFFSET = 0x0007e80c
MCU_NAMES_PTR_OFFSET = 0x0047d708 MCU_NAMES_PTR_OFFSET = 0x0047e80c
import struct import struct
import sys import sys
@ -25,12 +25,12 @@ for i in range(MCU_TABLE_SIZE):
inp.seek(mcu_name_offset) inp.seek(mcu_name_offset)
name_str = inp.read(16).split(b'\00')[0].decode("ascii") name_str = inp.read(16).split(b'\00')[0].decode("ascii")
# XXX: 1 KB are reserved one *some* MCUs for some reason # TODO: With some MCUs, the amount of available EEPROM depends on the BSL version.
#if ee_size > 0 and not name_str.startswith("IAP"): # Generally, newer BSLs free up a KB of additional EEPROM. Currently, always the
# ee_size -= 1024 # maximum amount (with newer BSL) is reported.
# STC12C54xx always have 12 KB eeprom # STC12x54xx always have 12 KB eeprom
if name_str.startswith("STC12C54"): if name_str.startswith("STC12C54") or name_str.startswith("STC12LE54"):
ee_size = 12 * 1024 ee_size = 12 * 1024
print("MCUModel(name='%s', magic=0x%02x%02x, total=%d, code=%d, eeprom=%d)," % print("MCUModel(name='%s', magic=0x%02x%02x, total=%d, code=%d, eeprom=%d)," %

View File

@ -4,7 +4,7 @@ Placement of configuration values
"~" means the bit is a negated boolean. Sometimes values overlap, "~" means the bit is a negated boolean. Sometimes values overlap,
depending on MCU model. depending on MCU model.
In STC12A series, the first 4 MCS bytes have active In STC12A series, the first 7 MCS bytes have active
values. Generally, unused bits should be set to 1. values. Generally, unused bits should be set to 1.
MCS0 MCS0
@ -47,14 +47,9 @@ MSB 7 6 5 4 3 2 1 0 LSB
(or others, depends on MCU model) are held low on POR. (or others, depends on MCU model) are held low on POR.
MCS3
----
Unused. MCS3 (at index 6!)
------------------
MCS4
----
MSB 7 6 5 4 3 2 1 0 LSB MSB 7 6 5 4 3 2 1 0 LSB
LVD LVD

View File

@ -5,6 +5,7 @@ MCS3 is like early STC15 MCS1.
MCS2 is like early STC15 MCS2. MCS2 is like early STC15 MCS2.
MCS4 is like early STC15 MCS0 but with additions. MCS4 is like early STC15 MCS0 but with additions.
MCSX is like early STC15 MCS12. MCSX is like early STC15 MCS12.
MCSY is new in STC15W4 series
baseline baseline
B5 FF F7 BB 9F B5 FF F7 BB 9F
@ -80,3 +81,61 @@ external oscillator enabled (IAP15F2K61S2)
external oscillator enabled + clock gain low (IAP15F2K61S2) external oscillator enabled + clock gain low (IAP15F2K61S2)
9C 7F F7 BB 9C 9C 7F F7 BB 9C
--> MCS 4 bit controls clock gain. high => high clock gain, low => low clock gain. --> MCS 4 bit controls clock gain. high => high clock gain, low => low clock gain.
cpu core supply level (MCSY)
in status packet:
2.68v
46 B9 68 00 34 50 8D FF 73 96 F7 BC 9F 00 5B 7A C0 FD 27 ED 00 00 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 EC E0 04 D7 EA 92 FF FF FF 15 09 25 60 14 BD 16
3.33v
46 B9 68 00 34 50 8D FF 73 96 F7 BC 9F 00 5B 92 30 FD 25 EA 00 FC 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 EC E0 04 D7 F7 92 FF FF FF 15 09 25 60 15 49 16
3.63v
46 B9 68 00 34 50 8D FF 73 96 F7 BC 9F 00 5B 7A C0 FD 25 EF 00 00 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 EC E0 04 D7 FD 92 FF FF FF 15 09 25 60 14 D0 16
3.73v
46 B9 68 00 34 50 8D FF 73 96 F7 BC 9F 00 5B 92 30 FD 25 EA 00 00 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 EC E0 04 D7 FF 92 FF FF FF 15 09 25 60 14 55 16
^^
MCSY
voltage: ff -> 3.73v
fd -> 3.63v
f7 -> 3.33v
ea -> 2.68v
in set options packet:
46 B9 6A 00 4B 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 00 FF A8 FF EE FF E0 FF FD 03 FF FF FF FF FF
^^
MCSP
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FD FF FF FF 75 BF F7 BC 9F 3A 80 16
^^
MCSY
password setting
the password is sent with packet type 0x07 and checked before erase with packet type 0x05. setting the password uses two fields.
index 22 of the option block encodes the password length in bytes (MCSP, see above). bit 3 in MCS3 decides whether the password
will be checked. if the bit is set, no password check occurs. if it is reset, a password check occurs.
quick dump from USB-ISP packets:
set: foobar
0000 ff ff ff 00 ff ff 00 05 ff ff ff ff ff ff ff 07 ................
0010 ff ff ff ff ff ff ff 07 ff 06 01 ff 6e ff 36 58 ............n.6X
0020 ff 00 ff f5 03 ff ff 0c ff ff ff ff ff ff ff 07 ................
0030 ff ff ff ff ff ff ff 07 ff ff ff ff ff ff ec 1a ................
0040 ff ff ff 99 7f f7 bc 38 9f 61 .......8.a
reset:
0000 ff ff ff 00 ff ff 00 05 ff ff ff ff ff ff ff 07 ................
0010 ff ff ff ff ff ff ff 07 ff 00 01 ff 6e ff 36 5e ............n.6^
0020 ff 00 ff fd 03 ff ff 04 ff ff ff ff ff ff ff 07 ................
0030 ff ff ff ff ff ff ff 07 ff ff ff ff ff ff ec 1a ................
0040 ff ff ff 99 7f f7 bc 38 9f 61 .......8.a

View File

@ -59,6 +59,11 @@ info packet
^^ ^^
factory calibration adjust for 24 MHz (range 0x40)? factory calibration adjust for 24 MHz (range 0x40)?
STC15W4K56S4:
46 B9 68 00 34 50 8D FF 73 96 F7 BC 9F 00 5B 7A C0 FD 27 ED 00 00 73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00 EC E0 04 D7 EA 92 FF FF FF 15 09 25 60 14 BD 16
^^
core voltage (MCSY)
IAP15F2K61S2: IAP15F2K61S2:
external osc: external osc:
46 B9 68 00 2B 50 87 D3 75 9C F7 BB 9E 01 77 70 80 FD 06 57 00 00 71 53 00 F4 49 04 06 58 9C 02 0E 14 17 19 19 00 F4 F4 04 D2 0E 8A 16 46 B9 68 00 2B 50 87 D3 75 9C F7 BB 9E 01 77 70 80 FD 06 57 00 00 71 53 00 F4 49 04 06 58 9C 02 0E 14 17 19 19 00 F4 F4 04 D2 0E 8A 16
@ -140,8 +145,9 @@ option packet
FF FD FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF B5 FF F7 BB 9F 3A 48 16 FF FD FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF B5 FF F7 BB 9F 3A 48 16
^ ^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^
MCSX MCS0-4 MCSX ^^ MCS0-4
MCSY
(STC15W4)
MCS bytes MCS bytes
--------- ---------
@ -154,7 +160,7 @@ RC calibration adjust
0x3f + RC calibration range (0x00, 0x40, 0x80, 0xc0) 0x3f + RC calibration range (0x00, 0x40, 0x80, 0xc0)
### MCS2 - MCS4 and MCSX ### MCS2 - MCS4, MCSX and MCSY
See stc15-options.txt See stc15-options.txt

View File

@ -0,0 +1,46 @@
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

128
doc/stc15w4k56s4.txt Normal file
View File

@ -0,0 +1,128 @@
2015-12-10 23:47:44.198341: PC
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F 7F
2015-12-10 23:47:48.400692: MCU
46 B9 68
2015-12-10 23:47:48.411946: PC
7F
2015-12-10 23:47:48.414811: MCU
00 34 50
2015-12-10 23:47:48.427644: PC
7F
2015-12-10 23:47:48.428894: MCU
8D FF 73 96 F5 7B 9F FF FF FF FF FF 27 ED 00 00
73 54 00 F5 28 04 06 70 96 02 15 19 1C 1E 23 00
EC E0 04 D7 F8 73 BF FF FF 15 09 25 60 16 92 16
2015-12-10 23:47:48.725370: PC
46 B9 6A 00 20 00 0B 00 C0 80 C0 FF C0 00 80 80
80 FF 80 00 40 80 40 FF 40 00 00 80 00 00 00 0A
12 16 FE FE FE FE FE FE FE FE FE FE FE FE FE
2015-12-10 23:47:49.088353: MCU
46 B9 68
2015-12-10 23:47:49.099586: PC
FE
2015-12-10 23:47:49.102589: MCU
00 20 00
2015-12-10 23:47:49.115089: PC
FE
2015-12-10 23:47:49.116479: MCU
0B 0D 21 12 BC 18 3E 1A 05 24 FA 2F B3 34 D1 4A
52 5E C0 52 DB 73 1A 00 00 08 7D 16
2015-12-10 23:47:49.266317: PC
46 B9 6A 00 20 00 0C 71 80 72 80 73 80 74 80 75
80 76 80 6F 40 70 40 71 40 72 40 73 40 74 40 0A
74 16 FE FE FE FE FE FE FE FE FE FE FE FE FE FE
2015-12-10 23:47:49.650397: MCU
46 B9 68
2015-12-10 23:47:49.661888: PC
FE
2015-12-10 23:47:49.664523: MCU
00 20 00
2015-12-10 23:47:49.677636: PC
FE
2015-12-10 23:47:49.678633: MCU
0C 23 BF 23 D3 23 E7 23 F6 24 0F 24 23 47 73 47
B9 47 E1 48 09 48 36 48 59 09 5B 16
2015-12-10 23:47:49.944529: PC
46 B9 6A 00 0E 01 72 40 F6 FF 80 73 81 04 94 16
2015-12-10 23:47:50.045100: MCU
46 B9 68 00 07 01 00 70 16
2015-12-10 23:47:50.116096: PC
46 B9 6A 00 0B 05 00 00 5A A5 01 79 16
2015-12-10 23:47:50.190036: MCU
46 B9 68 00 07 05 00 74 16
2015-12-10 23:47:50.255407: PC
46 B9 6A 00 0B 03 00 00 5A A5 01 77 16
2015-12-10 23:47:53.130695: MCU
46 B9 68 00 0E 03 F5 28 00 A5 03 27 49 02 AE 16
2015-12-10 23:47:53.210814: PC
46 B9 6A 00 8B 22 00 00 5A A5 01 04 01 36 75 81
07 12 00 6A E5 82 60 03 02 00 02 E4 78 FF F6 D8
FD 01 02 AF 82 8F 06 1F EE 60 0F 7D 90 7E 01 1D
BD FF 01 1E ED 4E 70 F7 80 EB 22 AF 82 DF FE 22
E5 B0 F4 F5 B0 75 82 05 11 31 75 82 D0 11 19 E5
B0 F4 F5 B0 75 82 64 11 19 E5 B0 F4 F5 B0 75 82
64 11 19 E5 B0 F4 F5 B0 75 82 64 11 19 E5 B0 F4
F5 B0 80 D6 75 82 00 22 FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF 49 E8 16
2015-12-10 23:47:54.003906: MCU
46 B9 68 00 08 02 54 00 C6 16
2015-12-10 23:47:54.068777: PC
46 B9 6A 00 8B 02 00 80 5A A5 FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF 81 F6 16
2015-12-10 23:47:54.867956: MCU
46 B9 68 00 08 02 54 00 C6 16
2015-12-10 23:47:54.932281: PC
46 B9 6A 00 8B 02 01 00 5A A5 FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF 81 77 16
2015-12-10 23:47:55.732519: MCU
46 B9 68 00 08 02 54 00 C6 16
2015-12-10 23:47:55.796791: PC
46 B9 6A 00 8B 02 01 80 5A A5 FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF 81 F7 16
2015-12-10 23:47:56.536325: MCU
46 B9 68 00 08 02 54 00 C6 16
2015-12-10 23:47:56.616743: PC
46 B9 6A 00 4B 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 00 FF A8 FF 91 FF 20 FF FD 03 FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF EC FF FF FF 74 BF F7 BC 9F 39 51 16
2015-12-10 23:47:57.070169: MCU
46 B9 68 00 08 04 54 00 C8 16

35
doc/usb15-protocol.txt Normal file
View File

@ -0,0 +1,35 @@
STC15 series USB ISP protocol
=============================
- 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 arbitrary size are used for writes
- packets from MCU
always start with 0x46 0xb9, similar to serial protocols
third byte is packet length
followed by data bytes
8 bit checksum at the end, looks like 8 bit modular subtraction
- packet types
most likely derived from the serial protocol, at least partially
info packet
- same as with serial protocol
option packet
- generally same as with serial protocol, some header stuff omitted
- 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 inverted modular sum
- option packet
wIndex is 0
wValue is 0xa55a
bRequest is 4
seems to use the same checksumming scheme

View File

@ -1,4 +1,25 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
#
# Copyright (c) 2016 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 stcgal import stcgal
from setuptools import setup, find_packages from setuptools import setup, find_packages
@ -6,8 +27,11 @@ from setuptools import setup, find_packages
setup( setup(
name = "stcgal", name = "stcgal",
version = stcgal.__version__, version = stcgal.__version__,
packages = find_packages(exclude=["doc"]), packages = find_packages(exclude=["doc", "test"]),
install_requires = ["pyserial"], install_requires = ["pyserial"],
extras_require = {
"usb": ["pyusb>=1.0.0"]
},
entry_points = { entry_points = {
"console_scripts": [ "console_scripts": [
"stcgal = stcgal.frontend:cli", "stcgal = stcgal.frontend:cli",
@ -31,4 +55,6 @@ setup(
"Topic :: Software Development :: Embedded Systems", "Topic :: Software Development :: Embedded Systems",
"Topic :: Software Development", "Topic :: Software Development",
], ],
test_suite = "test",
tests_require = ["PyYAML"],
) )

View File

@ -1 +1 @@
__version__ = "1.0" __version__ = "1.4"

27
stcgal/__main__.py Executable file
View File

@ -0,0 +1,27 @@
#
# 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())

View File

@ -20,10 +20,10 @@
# SOFTWARE. # SOFTWARE.
# #
import sys, os, time, struct import sys
import argparse import argparse
import stcgal import stcgal
from stcgal.utils import Utils, BaudType from stcgal.utils import BaudType
from stcgal.protocols import * from stcgal.protocols import *
from stcgal.ihex import IHex from stcgal.ihex import IHex
@ -32,29 +32,39 @@ class StcGal:
def __init__(self, opts): def __init__(self, opts):
self.opts = opts self.opts = opts
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":
self.protocol = Stc12AProtocol(opts.port, opts.handshake, opts.baud) self.protocol = Stc12AProtocol(opts.port, opts.handshake, opts.baud)
elif opts.protocol == "stc12b":
self.protocol = Stc12BProtocol(opts.port, opts.handshake, opts.baud)
elif opts.protocol == "stc12": elif opts.protocol == "stc12":
self.protocol = Stc12Protocol(opts.port, opts.handshake, opts.baud) self.protocol = Stc12Protocol(opts.port, opts.handshake, opts.baud)
elif opts.protocol == "stc15a": elif opts.protocol == "stc15a":
self.protocol = Stc15AProtocol(opts.port, opts.handshake, opts.baud, self.protocol = Stc15AProtocol(opts.port, opts.handshake, opts.baud,
round(opts.trim * 1000)) round(opts.trim * 1000))
else: 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 == "usb15":
self.protocol = StcUsb15Protocol()
else:
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):
for o in options: """Set options from command line to protocol handler."""
for opt in options:
try: try:
kv = o.split("=", 1) kv = opt.split("=", 1)
if len(kv) < 2: raise ValueError("incorrect format") if len(kv) < 2:
raise ValueError("incorrect format")
self.protocol.set_option(kv[0], kv[1]) self.protocol.set_option(kv[0], kv[1])
except ValueError as e: except ValueError as ex:
raise NameError("invalid option '%s' (%s)" % (kv[0], e)) raise NameError("invalid option '%s' (%s)" % (kv[0], ex))
def load_file_auto(self, fileobj): def load_file_auto(self, fileobj):
"""Load file with Intel Hex autodetection.""" """Load file with Intel Hex autodetection."""
@ -67,46 +77,48 @@ 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 e: except ValueError as ex:
raise IOError("invalid Intel HEX file (%s)" %e) raise IOError("invalid Intel HEX file (%s)" %ex)
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
print("Loading flash: ", end="") print("Loading flash: ", end="")
sys.stdout.flush() sys.stdout.flush()
bindata = self.load_file_auto(self.opts.code_binary) bindata = self.load_file_auto(self.opts.code_image)
# warn if it overflows # warn if it overflows
if len(bindata) > code_size: if len(bindata) > code_size:
print("WARNING: code_binary overflows into eeprom segment!", file=sys.stderr) print("WARNING: code_image overflows into eeprom segment!", file=sys.stderr)
if len(bindata) > (code_size + ee_size): if len(bindata) > (code_size + ee_size):
print("WARNING: code_binary truncated!", file=sys.stderr) print("WARNING: code_image truncated!", file=sys.stderr)
bindata = bindata[0:code_size + ee_size] bindata = bindata[0:code_size + ee_size]
# add eeprom data if supplied # add eeprom data if supplied
if self.opts.eeprom_binary: if self.opts.eeprom_image:
print("Loading EEPROM: ", end="") print("Loading EEPROM: ", end="")
sys.stdout.flush() sys.stdout.flush()
eedata = self.load_file_auto(self.opts.eeprom_binary) eedata = self.load_file_auto(self.opts.eeprom_image)
if len(eedata) > ee_size: if len(eedata) > ee_size:
print("WARNING: eeprom_binary truncated!", file=sys.stderr) print("WARNING: eeprom_image truncated!", file=sys.stderr)
eedata = eedata[0:ee_size] eedata = eedata[0:ee_size]
if len(bindata) < code_size: if len(bindata) < code_size:
bindata += bytes(code_size - len(bindata)) bindata += bytes(code_size - len(bindata))
elif len(bindata) > code_size: elif len(bindata) > code_size:
print("WARNING: eeprom_binary overlaps code_binary!", file=sys.stderr) print("WARNING: eeprom_image overlaps code_image!", file=sys.stderr)
bindata = bindata[0:code_size] bindata = bindata[0:code_size]
bindata += eedata bindata += eedata
# pad to 256 byte boundary # pad to 512 byte boundary
if len(bindata) % 256: if len(bindata) % 512:
bindata += bytes(256 - len(bindata) % 256) bindata += b'\xff' * (512 - len(bindata) % 512)
if self.opts.option: self.emit_options(self.opts.option) if self.opts.option: self.emit_options(self.opts.option)
@ -117,62 +129,84 @@ class StcGal:
self.protocol.disconnect() self.protocol.disconnect()
def run(self): def run(self):
try: self.protocol.connect() """Run programmer, main entry point."""
try:
self.protocol.connect(autoreset=self.opts.autoreset, resetcmd=self.opts.resetcmd)
if self.opts.protocol == "auto":
if not self.protocol.protocol_name:
raise StcProtocolException("cannot detect protocol")
base_protocol = self.protocol
self.opts.protocol = self.protocol.protocol_name
print("Protocol detected: %s" % self.opts.protocol)
# recreate self.protocol with proper protocol class
self.__init__(self.opts)
else:
base_protocol = None
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 e: except (StcFramingException, StcProtocolException) as ex:
sys.stdout.flush(); sys.stdout.flush()
print("Protocol error: %s" % e, file=sys.stderr) print("Protocol error: %s" % ex, file=sys.stderr)
self.protocol.disconnect() self.protocol.disconnect()
return 1 return 1
except serial.SerialException as e: except serial.SerialException as ex:
sys.stdout.flush(); sys.stdout.flush()
print("Serial port error: %s" % e, file=sys.stderr) print("Serial port error: %s" % ex, file=sys.stderr)
return 1
except IOError as ex:
sys.stdout.flush()
print("I/O error: %s" % ex, file=sys.stderr)
return 1 return 1
try: try:
if self.opts.code_binary: if self.opts.code_image:
self.program_mcu() self.program_mcu()
return 0 return 0
else: else:
self.protocol.disconnect() self.protocol.disconnect()
return 0 return 0
except NameError as e: except NameError as ex:
sys.stdout.flush(); sys.stdout.flush()
print("Option error: %s" % e, file=sys.stderr) print("Option error: %s" % ex, file=sys.stderr)
self.protocol.disconnect() self.protocol.disconnect()
return 1 return 1
except (StcFramingException, StcProtocolException) as e: except (StcFramingException, StcProtocolException) as ex:
sys.stdout.flush(); sys.stdout.flush()
print("Protocol error: %s" % e, file=sys.stderr) print("Protocol error: %s" % ex, 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 e: except serial.SerialException as ex:
print("Serial port error: %s" % e, file=sys.stderr) print("Serial port error: %s" % ex, file=sys.stderr)
return 1 return 1
except IOError as e: except IOError as ex:
sys.stdout.flush(); sys.stdout.flush()
print("I/O error: %s" % e, file=sys.stderr) print("I/O error: %s" % ex, file=sys.stderr)
self.protocol.disconnect() self.protocol.disconnect()
return 1 return 1
def cli(): def cli():
# check arguments # check arguments
parser = argparse.ArgumentParser(description="stcgal %s - an STC MCU ISP flash tool" %stcgal.__version__) parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
parser.add_argument("code_binary", help="code segment binary file to flash", type=argparse.FileType("rb"), nargs='?') description="stcgal %s - an STC MCU ISP flash tool\n(C) 2014-2017 Grigori Goronzy\nhttps://github.com/grigorig/stcgal" %stcgal.__version__)
parser.add_argument("eeprom_binary", help="eeprom segment binary file to flash", 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("-P", "--protocol", help="protocol version", choices=["stc89", "stc12a", "stc12", "stc15a", "stc15"], default="stc12") 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("-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", "--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: 1200)", type=BaudType(), default=1200) parser.add_argument("-l", "--handshake", help="handshake baud rate (default: 2400)", type=BaudType(), default=2400)
parser.add_argument("-o", "--option", help="set option (can be used multiple times)", action="append") parser.add_argument("-o", "--option", help="set option (can be used multiple times)", action="append")
parser.add_argument("-t", "--trim", help="RC oscillator frequency in kHz (STC15 series only)", type=float, default=0.0) parser.add_argument("-t", "--trim", help="RC oscillator frequency in kHz (STC15 series only)", type=float, default=0.0)
parser.add_argument("-D", "--debug", help="enable debug output", action="store_true") parser.add_argument("-D", "--debug", help="enable debug output", action="store_true")

View File

@ -32,14 +32,38 @@ class MCUModelDatabase:
MCUModel = collections.namedtuple("MCUModel", ["name", "magic", "total", "code", "eeprom"]) MCUModel = collections.namedtuple("MCUModel", ["name", "magic", "total", "code", "eeprom"])
models = ( models = (
MCUModel(name='STC15H4K08S4', magic=0xf601, total=65536, code=8192, eeprom=0), MCUModel(name='STC8F8K08S4A10', magic=0xf611, total=65536, code=8192, eeprom=57344),
MCUModel(name='STC15H4K16S4', magic=0xf602, total=65536, code=16384, eeprom=0), MCUModel(name='STC8F8K16S4A10', magic=0xf612, total=65536, code=16384, eeprom=49152),
MCUModel(name='STC15H4K24S4', magic=0xf603, total=65536, code=24576, eeprom=0), MCUModel(name='STC8F8K24S4A10', magic=0xf613, total=65536, code=24576, eeprom=40960),
MCUModel(name='STC15H4K32S4', magic=0xf604, total=65536, code=32768, eeprom=0), MCUModel(name='STC8F8K32S4A10', magic=0xf614, total=65536, code=32768, eeprom=32768),
MCUModel(name='STC15H4K40S4', magic=0xf605, total=65536, code=40960, eeprom=0), MCUModel(name='STC8F8K40S4A10', magic=0xf615, total=65536, code=40960, eeprom=24576),
MCUModel(name='STC15H4K48S4', magic=0xf606, total=65536, code=49152, eeprom=0), MCUModel(name='STC8F8K48S4A10', magic=0xf616, total=65536, code=49152, eeprom=16384),
MCUModel(name='STC15H4K56S4', magic=0xf607, total=65536, code=57344, eeprom=0), MCUModel(name='STC8F8K56S4A10', magic=0xf617, total=65536, code=57344, eeprom=8192),
MCUModel(name='STC15H4K64S4', magic=0xf608, total=65536, code=65024, eeprom=0), MCUModel(name='STC8F8K64S4A10', magic=0xf618, total=65536, code=65024, eeprom=512),
MCUModel(name='STC8A8K08S4A12', magic=0xf621, total=65536, code=8192, eeprom=57344),
MCUModel(name='STC8A8K16S4A12', magic=0xf622, total=65536, code=16384, eeprom=49152),
MCUModel(name='STC8A8K24S4A12', magic=0xf623, total=65536, code=24576, eeprom=40960),
MCUModel(name='STC8A8K32S4A12', magic=0xf624, total=65536, code=32768, eeprom=32768),
MCUModel(name='STC8A8K40S4A12', magic=0xf625, total=65536, code=40960, eeprom=24576),
MCUModel(name='STC8A8K48S4A12', magic=0xf626, total=65536, code=49152, eeprom=16384),
MCUModel(name='STC8A8K56S4A12', magic=0xf627, total=65536, code=57344, eeprom=8192),
MCUModel(name='STC8A8K64S4A12', magic=0xf628, total=65536, code=65024, eeprom=512),
MCUModel(name='STC8F2K08S4', magic=0xf631, total=65536, code=8192, eeprom=57344),
MCUModel(name='STC8F2K16S4', magic=0xf632, total=65536, code=16384, eeprom=49152),
MCUModel(name='STC8F2K24S4', magic=0xf633, total=65536, code=24576, eeprom=40960),
MCUModel(name='STC8F2K32S4', magic=0xf634, total=65536, code=32768, eeprom=32768),
MCUModel(name='STC8F2K40S4', magic=0xf635, total=65536, code=40960, eeprom=24576),
MCUModel(name='STC8F2K48S4', magic=0xf636, total=65536, code=49152, eeprom=16384),
MCUModel(name='STC8F2K56S4', magic=0xf637, total=65536, code=57344, eeprom=8192),
MCUModel(name='STC8F2K64S4', magic=0xf638, total=65536, code=65024, eeprom=512),
MCUModel(name='STC15H4K08S4', magic=0xf601, total=65536, code=8192, eeprom=57344),
MCUModel(name='STC15H4K16S4', magic=0xf602, total=65536, code=16384, eeprom=49152),
MCUModel(name='STC15H4K24S4', magic=0xf603, total=65536, code=24576, eeprom=40960),
MCUModel(name='STC15H4K32S4', magic=0xf604, total=65536, code=32768, eeprom=32768),
MCUModel(name='STC15H4K40S4', magic=0xf605, total=65536, code=40960, eeprom=24576),
MCUModel(name='STC15H4K48S4', magic=0xf606, total=65536, code=49152, eeprom=16384),
MCUModel(name='STC15H4K56S4', magic=0xf607, total=65536, code=57344, eeprom=8192),
MCUModel(name='STC15H4K64S4', magic=0xf608, total=65536, code=65024, eeprom=512),
MCUModel(name='STC15F2K08S2', magic=0xf401, total=65536, code=8192, eeprom=54272), MCUModel(name='STC15F2K08S2', magic=0xf401, total=65536, code=8192, eeprom=54272),
MCUModel(name='STC15F2K16S2', magic=0xf402, total=65536, code=16384, eeprom=46080), MCUModel(name='STC15F2K16S2', magic=0xf402, total=65536, code=16384, eeprom=46080),
MCUModel(name='STC15F2K24S2', magic=0xf403, total=65536, code=24576, eeprom=37888), MCUModel(name='STC15F2K24S2', magic=0xf403, total=65536, code=24576, eeprom=37888),
@ -209,6 +233,9 @@ class MCUModelDatabase:
MCUModel(name='STC15W1K08PWM', magic=0xf52d, total=65536, code=8192, eeprom=52224), MCUModel(name='STC15W1K08PWM', magic=0xf52d, total=65536, code=8192, eeprom=52224),
MCUModel(name='STC15W1K16PWM', magic=0xf52e, total=65536, code=16384, eeprom=44032), MCUModel(name='STC15W1K16PWM', magic=0xf52e, total=65536, code=16384, eeprom=44032),
MCUModel(name='STC15W1K20S', magic=0xf52f, total=65536, code=20480, eeprom=39936), MCUModel(name='STC15W1K20S', magic=0xf52f, total=65536, code=20480, eeprom=39936),
MCUModel(name='STC15W1K20AS', magic=0xf534, total=65536, code=20480, eeprom=39936),
MCUModel(name='STC15W1K32AS', magic=0xf535, total=65536, code=32768, eeprom=27648),
MCUModel(name='STC15W1K48AS', magic=0xf536, total=65536, code=49152, eeprom=11264),
MCUModel(name='STC15W2K32S2', magic=0xf530, total=65536, code=32768, eeprom=27648), MCUModel(name='STC15W2K32S2', magic=0xf530, total=65536, code=32768, eeprom=27648),
MCUModel(name='STC15W2K48S2', magic=0xf531, total=65536, code=49152, eeprom=11264), MCUModel(name='STC15W2K48S2', magic=0xf531, total=65536, code=49152, eeprom=11264),
MCUModel(name='STC15W2K32AS', magic=0xf532, total=65536, code=32768, eeprom=27648), MCUModel(name='STC15W2K32AS', magic=0xf532, total=65536, code=32768, eeprom=27648),
@ -812,28 +839,28 @@ class MCUModelDatabase:
MCUModel(name='STC12C5420', magic=0xe014, total=32768, code=20480, eeprom=12288), MCUModel(name='STC12C5420', magic=0xe014, total=32768, code=20480, eeprom=12288),
MCUModel(name='STC12C5424', magic=0xe018, total=32768, code=24576, eeprom=12288), MCUModel(name='STC12C5424', magic=0xe018, total=32768, code=24576, eeprom=12288),
MCUModel(name='STC12C5428', magic=0xe01c, total=32768, code=28672, eeprom=12288), MCUModel(name='STC12C5428', magic=0xe01c, total=32768, code=28672, eeprom=12288),
MCUModel(name='STC12LE5401AD', magic=0xe0e1, total=32768, code=1024, eeprom=22016), MCUModel(name='STC12LE5401AD', magic=0xe0e1, total=32768, code=1024, eeprom=12288),
MCUModel(name='STC12LE5402AD', magic=0xe0e2, total=32768, code=2048, eeprom=20992), MCUModel(name='STC12LE5402AD', magic=0xe0e2, total=32768, code=2048, eeprom=12288),
MCUModel(name='STC12LE5404AD', magic=0xe0e4, total=32768, code=4096, eeprom=18944), MCUModel(name='STC12LE5404AD', magic=0xe0e4, total=32768, code=4096, eeprom=12288),
MCUModel(name='STC12LE5406AD', magic=0xe0e6, total=32768, code=6144, eeprom=16896), MCUModel(name='STC12LE5406AD', magic=0xe0e6, total=32768, code=6144, eeprom=12288),
MCUModel(name='STC12LE5408AD', magic=0xe0e8, total=32768, code=8192, eeprom=10752), MCUModel(name='STC12LE5408AD', magic=0xe0e8, total=32768, code=8192, eeprom=12288),
MCUModel(name='STC12LE5410AD', magic=0xe0ea, total=32768, code=10240, eeprom=4608), MCUModel(name='STC12LE5410AD', magic=0xe0ea, total=32768, code=10240, eeprom=12288),
MCUModel(name='STC12LE5412AD', magic=0xe0ec, total=32768, code=12288, eeprom=11776), MCUModel(name='STC12LE5412AD', magic=0xe0ec, total=32768, code=12288, eeprom=12288),
MCUModel(name='STC12LE5416AD', magic=0xe0f0, total=32768, code=16384, eeprom=12288), MCUModel(name='STC12LE5416AD', magic=0xe0f0, total=32768, code=16384, eeprom=12288),
MCUModel(name='STC12LE5420AD', magic=0xe0f4, total=32768, code=20480, eeprom=8192), MCUModel(name='STC12LE5420AD', magic=0xe0f4, total=32768, code=20480, eeprom=12288),
MCUModel(name='STC12LE5424AD', magic=0xe0f8, total=32768, code=24576, eeprom=4096), MCUModel(name='STC12LE5424AD', magic=0xe0f8, total=32768, code=24576, eeprom=12288),
MCUModel(name='STC12LE5428AD', magic=0xe0fc, total=32768, code=28672, eeprom=0), MCUModel(name='STC12LE5428AD', magic=0xe0fc, total=32768, code=28672, eeprom=12288),
MCUModel(name='STC12LE5401', magic=0xe081, total=32768, code=1024, eeprom=22016), MCUModel(name='STC12LE5401', magic=0xe081, total=32768, code=1024, eeprom=12288),
MCUModel(name='STC12LE5402', magic=0xe082, total=32768, code=2048, eeprom=20992), MCUModel(name='STC12LE5402', magic=0xe082, total=32768, code=2048, eeprom=12288),
MCUModel(name='STC12LE5404', magic=0xe084, total=32768, code=4096, eeprom=18944), MCUModel(name='STC12LE5404', magic=0xe084, total=32768, code=4096, eeprom=12288),
MCUModel(name='STC12LE5406', magic=0xe086, total=32768, code=6144, eeprom=16896), MCUModel(name='STC12LE5406', magic=0xe086, total=32768, code=6144, eeprom=12288),
MCUModel(name='STC12LE5408', magic=0xe088, total=32768, code=8192, eeprom=10752), MCUModel(name='STC12LE5408', magic=0xe088, total=32768, code=8192, eeprom=12288),
MCUModel(name='STC12LE5410', magic=0xe08a, total=32768, code=10240, eeprom=4608), MCUModel(name='STC12LE5410', magic=0xe08a, total=32768, code=10240, eeprom=12288),
MCUModel(name='STC12LE5412', magic=0xe08c, total=32768, code=12288, eeprom=11776), MCUModel(name='STC12LE5412', magic=0xe08c, total=32768, code=12288, eeprom=12288),
MCUModel(name='STC12LE5416', magic=0xe090, total=32768, code=16384, eeprom=12288), MCUModel(name='STC12LE5416', magic=0xe090, total=32768, code=16384, eeprom=12288),
MCUModel(name='STC12LE5420', magic=0xe094, total=32768, code=20480, eeprom=8192), MCUModel(name='STC12LE5420', magic=0xe094, total=32768, code=20480, eeprom=12288),
MCUModel(name='STC12LE5424', magic=0xe098, total=32768, code=24576, eeprom=4096), MCUModel(name='STC12LE5424', magic=0xe098, total=32768, code=24576, eeprom=12288),
MCUModel(name='STC12LE5428', magic=0xe09c, total=32768, code=28672, eeprom=0), MCUModel(name='STC12LE5428', magic=0xe09c, total=32768, code=28672, eeprom=12288),
MCUModel(name='STC12C1052AD', magic=0xf211, total=8192, code=1024, eeprom=5120), MCUModel(name='STC12C1052AD', magic=0xf211, total=8192, code=1024, eeprom=5120),
MCUModel(name='STC12C2052AD', magic=0xf212, total=8192, code=2048, eeprom=4096), MCUModel(name='STC12C2052AD', magic=0xf212, total=8192, code=2048, eeprom=4096),
MCUModel(name='STC12C3052AD', magic=0xf213, total=8192, code=3072, eeprom=3072), MCUModel(name='STC12C3052AD', magic=0xf213, total=8192, code=3072, eeprom=3072),
@ -946,6 +973,46 @@ 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
@ -961,6 +1028,3 @@ 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))

608
stcgal/options.py Normal file
View File

@ -0,0 +1,608 @@
#
# Copyright (c) 2013-2016 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 struct
from stcgal.utils import Utils
class BaseOption:
def print(self):
print("Target options:")
for name, get_func, _ in self.options:
print(" %s=%s" % (name, get_func()))
def set_option(self, name, value):
for opt, _, set_func in self.options:
if opt == name:
print("Option %s=%s" % (name, value))
set_func(value)
return
raise ValueError("unknown")
def get_option(self, name):
for opt, get_func, _ in self.options:
if opt == name:
return get_func(name)
raise ValueError("unknown")
def get_msr(self):
return bytes(self.msr)
class Stc89Option(BaseOption):
"""Manipulation STC89 series option byte"""
def __init__(self, msr):
self.msr = msr
self.options = (
("cpu_6t_enabled", self.get_t6, self.set_t6),
("bsl_pindetect_enabled", self.get_pindetect, self.set_pindetect),
("eeprom_erase_enabled", self.get_ee_erase, self.set_ee_erase),
("clock_gain", self.get_clock_gain, self.set_clock_gain),
("ale_enabled", self.get_ale, self.set_ale),
("xram_enabled", self.get_xram, self.set_xram),
("watchdog_por_enabled", self.get_watchdog, self.set_watchdog),
)
def get_msr(self):
return self.msr
def get_t6(self):
return not bool(self.msr & 1)
def set_t6(self, val):
val = Utils.to_bool(val)
self.msr &= 0xfe
self.msr |= 0x01 if not bool(val) else 0x00
def get_pindetect(self):
return not bool(self.msr & 4)
def set_pindetect(self, val):
val = Utils.to_bool(val)
self.msr &= 0xfb
self.msr |= 0x04 if not bool(val) else 0x00
def get_ee_erase(self):
return not bool(self.msr & 8)
def set_ee_erase(self, val):
val = Utils.to_bool(val)
self.msr &= 0xf7
self.msr |= 0x08 if not bool(val) else 0x00
def get_clock_gain(self):
gain = bool(self.msr & 16)
return "high" if gain else "low"
def set_clock_gain(self, val):
gains = {"low": 0, "high": 0x10}
if val not in gains.keys():
raise ValueError("must be one of %s" % list(gains.keys()))
self.msr &= 0xef
self.msr |= gains[val]
def get_ale(self):
return bool(self.msr & 32)
def set_ale(self, val):
val = Utils.to_bool(val)
self.msr &= 0xdf
self.msr |= 0x20 if bool(val) else 0x00
def get_xram(self):
return bool(self.msr & 64)
def set_xram(self, val):
val = Utils.to_bool(val)
self.msr &= 0xbf
self.msr |= 0x40 if bool(val) else 0x00
def get_watchdog(self):
return not bool(self.msr & 128)
def set_watchdog(self, val):
val = Utils.to_bool(val)
self.msr &= 0x7f
self.msr |= 0x80 if not bool(val) else 0x00
class Stc12AOption(BaseOption):
"""Manipulate STC12A series option bytes"""
def __init__(self, msr):
assert len(msr) == 4
self.msr = bytearray(msr)
"""list of options and their handlers"""
self.options = (
("low_voltage_reset", self.get_low_voltage_detect, self.set_low_voltage_detect),
("clock_source", self.get_clock_source, self.set_clock_source),
("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),
("eeprom_erase_enabled", self.get_ee_erase, self.set_ee_erase),
("bsl_pindetect_enabled", self.get_pindetect, self.set_pindetect),
)
def get_low_voltage_detect(self):
lvd = bool(self.msr[3] & 64)
return "high" if not lvd else "low"
def set_low_voltage_detect(self, val):
lvds = {"low": 1, "high": 0}
if val not in lvds.keys():
raise ValueError("must be one of %s" % list(lvds.keys()))
self.msr[3] &= 0xbf
self.msr[3] |= lvds[val] << 6
def get_clock_source(self):
source = bool(self.msr[0] & 2)
return "external" if source else "internal"
def set_clock_source(self, val):
sources = {"internal": 0, "external": 1}
if val not in sources.keys():
raise ValueError("must be one of %s" % list(sources.keys()))
self.msr[0] &= 0xfd
self.msr[0] |= sources[val] << 1
def get_watchdog(self):
return not bool(self.msr[1] & 32)
def set_watchdog(self, val):
val = Utils.to_bool(val)
self.msr[1] &= 0xdf
self.msr[1] |= 0x20 if not val else 0x00
def get_watchdog_idle(self):
return not bool(self.msr[1] & 8)
def set_watchdog_idle(self, val):
val = Utils.to_bool(val)
self.msr[1] &= 0xf7
self.msr[1] |= 0x08 if not val else 0x00
def get_watchdog_prescale(self):
return 2 ** (((self.msr[1]) & 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[1] &= 0xf8
self.msr[1] |= wd_vals[val]
def get_ee_erase(self):
return not bool(self.msr[2] & 2)
def set_ee_erase(self, val):
val = Utils.to_bool(val)
self.msr[2] &= 0xfd
self.msr[2] |= 0x02 if not val else 0x00
def get_pindetect(self):
return not bool(self.msr[2] & 1)
def set_pindetect(self, val):
val = Utils.to_bool(val)
self.msr[2] &= 0xfe
self.msr[2] |= 0x01 if not val else 0x00
class Stc12Option(BaseOption):
"""Manipulate STC10/11/12 series option bytes"""
def __init__(self, msr):
assert len(msr) == 4
self.msr = bytearray(msr)
"""list of options and their handlers"""
self.options = (
("reset_pin_enabled", self.get_reset_pin_enabled, self.set_reset_pin_enabled),
("low_voltage_reset", self.get_low_voltage_detect, self.set_low_voltage_detect),
("oscillator_stable_delay", self.get_osc_stable_delay, self.set_osc_stable_delay),
("por_reset_delay", self.get_por_delay, self.set_por_delay),
("clock_gain", self.get_clock_gain, self.set_clock_gain),
("clock_source", self.get_clock_source, self.set_clock_source),
("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),
("eeprom_erase_enabled", self.get_ee_erase, self.set_ee_erase),
("bsl_pindetect_enabled", self.get_pindetect, self.set_pindetect),
)
def get_reset_pin_enabled(self):
return bool(self.msr[0] & 1)
def set_reset_pin_enabled(self, val):
val = Utils.to_bool(val)
self.msr[0] &= 0xfe
self.msr[0] |= 0x01 if bool(val) else 0x00
def get_low_voltage_detect(self):
return not bool(self.msr[0] & 64)
def set_low_voltage_detect(self, val):
val = Utils.to_bool(val)
self.msr[0] &= 0xbf
self.msr[0] |= 0x40 if not val else 0x00
def get_osc_stable_delay(self):
return 2 ** (((self.msr[0] >> 4) & 0x03) + 12)
def set_osc_stable_delay(self, val):
val = Utils.to_int(val)
osc_vals = {4096: 0, 8192: 1, 16384: 2, 32768: 3}
if val not in osc_vals.keys():
raise ValueError("must be one of %s" % list(osc_vals.keys()))
self.msr[0] &= 0xcf
self.msr[0] |= osc_vals[val] << 4
def get_por_delay(self):
delay = not bool(self.msr[1] & 128)
return "long" if delay else "short"
def set_por_delay(self, val):
delays = {"short": 1, "long": 0}
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_clock_gain(self):
gain = bool(self.msr[1] & 64)
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] &= 0xbf
self.msr[1] |= gains[val] << 6
def get_clock_source(self):
source = bool(self.msr[1] & 2)
return "external" if source else "internal"
def set_clock_source(self, val):
sources = {"internal": 0, "external": 1}
if val not in sources.keys():
raise ValueError("must be one of %s" % list(sources.keys()))
self.msr[1] &= 0xfd
self.msr[1] |= sources[val] << 1
def get_watchdog(self):
return not bool(self.msr[2] & 32)
def set_watchdog(self, val):
val = Utils.to_bool(val)
self.msr[2] &= 0xdf
self.msr[2] |= 0x20 if not val else 0x00
def get_watchdog_idle(self):
return not bool(self.msr[2] & 8)
def set_watchdog_idle(self, val):
val = Utils.to_bool(val)
self.msr[2] &= 0xf7
self.msr[2] |= 0x08 if not val else 0x00
def get_watchdog_prescale(self):
return 2 ** (((self.msr[2]) & 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[2] &= 0xf8
self.msr[2] |= wd_vals[val]
def get_ee_erase(self):
return not bool(self.msr[3] & 2)
def set_ee_erase(self, val):
val = Utils.to_bool(val)
self.msr[3] &= 0xfd
self.msr[3] |= 0x02 if not val else 0x00
def get_pindetect(self):
return not bool(self.msr[3] & 1)
def set_pindetect(self, val):
val = Utils.to_bool(val)
self.msr[3] &= 0xfe
self.msr[3] |= 0x01 if not val else 0x00
class Stc15AOption(BaseOption):
def __init__(self, msr):
assert len(msr) == 13
self.msr = bytearray(msr)
self.options = (
("reset_pin_enabled", self.get_reset_pin_enabled, self.set_reset_pin_enabled),
("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_lvd_inhibit", self.get_eeprom_lvd, self.set_eeprom_lvd),
("eeprom_erase_enabled", self.get_ee_erase, self.set_ee_erase),
("bsl_pindetect_enabled", self.get_pindetect, self.set_pindetect),
)
def set_trim(self, val):
self.msr[3:5] = struct.pack(">H", val)
def get_reset_pin_enabled(self):
return bool(self.msr[0] & 16)
def set_reset_pin_enabled(self, val):
val = Utils.to_bool(val)
self.msr[0] &= 0xef
self.msr[0] |= 0x10 if bool(val) else 0x00
def get_watchdog(self):
return not bool(self.msr[2] & 32)
def set_watchdog(self, val):
val = Utils.to_bool(val)
self.msr[2] &= 0xdf
self.msr[2] |= 0x20 if not val else 0x00
def get_watchdog_idle(self):
return not bool(self.msr[2] & 8)
def set_watchdog_idle(self, val):
val = Utils.to_bool(val)
self.msr[2] &= 0xf7
self.msr[2] |= 0x08 if not val else 0x00
def get_watchdog_prescale(self):
return 2 ** (((self.msr[2]) & 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[2] &= 0xf8
self.msr[2] |= wd_vals[val]
def get_lvrs(self):
return bool(self.msr[1] & 64)
def set_lvrs(self, val):
val = Utils.to_bool(val)
self.msr[1] &= 0xbf
self.msr[1] |= 0x40 if val else 0x00
def get_eeprom_lvd(self):
return bool(self.msr[1] & 128)
def set_eeprom_lvd(self, val):
val = Utils.to_bool(val)
self.msr[1] &= 0x7f
self.msr[1] |= 0x80 if val else 0x00
def get_low_voltage(self):
return self.msr[1] & 0x07
def set_low_voltage(self, val):
val = Utils.to_int(val)
if val not in range(0, 8):
raise ValueError("must be one of %s" % list(range(0, 8)))
self.msr[1] &= 0xf8
self.msr[1] |= val
def get_ee_erase(self):
return not bool(self.msr[12] & 2)
def set_ee_erase(self, val):
val = Utils.to_bool(val)
self.msr[12] &= 0xfd
self.msr[12] |= 0x02 if not val else 0x00
def get_pindetect(self):
return not bool(self.msr[12] & 1)
def set_pindetect(self, val):
val = Utils.to_bool(val)
self.msr[12] &= 0xfe
self.msr[12] |= 0x01 if not val else 0x00
class Stc15Option(BaseOption):
def __init__(self, msr):
assert len(msr) >= 4
self.msr = bytearray(msr)
self.options = (
("reset_pin_enabled", self.get_reset_pin_enabled, self.set_reset_pin_enabled),
("clock_source", self.get_clock_source, self.set_clock_source),
("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_lvd_inhibit", self.get_eeprom_lvd, self.set_eeprom_lvd),
("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_p33_state, self.set_p33_state),
("uart2_passthrough", self.get_uart_passthrough, self.set_uart_passthrough),
("uart2_pin_mode", self.get_uart_pin_mode, self.set_uart_pin_mode),
)
if len(msr) > 4:
self.options += ("cpu_core_voltage", self.get_core_voltage, self.set_core_voltage),
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_source(self):
source = bool(self.msr[2] & 0x01)
return "internal" if source else "external"
def set_clock_source(self, val):
sources = {"internal": 1, "external": 0}
if val not in sources.keys():
raise ValueError("must be one of %s" % list(sources.keys()))
self.msr[2] &= 0xfe
self.msr[2] |= sources[val]
def get_clock_gain(self):
gain = bool(self.msr[2] & 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[2] &= 0xfd
self.msr[2] |= gains[val] << 1
def get_watchdog(self):
return not bool(self.msr[0] & 32)
def set_watchdog(self, val):
val = Utils.to_bool(val)
self.msr[0] &= 0xdf
self.msr[0] |= 0x20 if not val else 0x00
def get_watchdog_idle(self):
return not bool(self.msr[0] & 8)
def set_watchdog_idle(self, val):
val = Utils.to_bool(val)
self.msr[0] &= 0xf7
self.msr[0] |= 0x08 if not val else 0x00
def get_watchdog_prescale(self):
return 2 ** (((self.msr[0]) & 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[0] &= 0xf8
self.msr[0] |= wd_vals[val]
def get_lvrs(self):
return not bool(self.msr[1] & 64)
def set_lvrs(self, val):
val = Utils.to_bool(val)
self.msr[1] &= 0xbf
self.msr[1] |= 0x40 if not val else 0x00
def get_eeprom_lvd(self):
return bool(self.msr[1] & 128)
def set_eeprom_lvd(self, val):
val = Utils.to_bool(val)
self.msr[1] &= 0x7f
self.msr[1] |= 0x80 if val else 0x00
def get_low_voltage(self):
return self.msr[1] & 0x07
def set_low_voltage(self, val):
val = Utils.to_int(val)
if val not in range(0, 8):
raise ValueError("must be one of %s" % list(range(0, 8)))
self.msr[1] &= 0xf8
self.msr[1] |= val
def get_ee_erase(self):
return bool(self.msr[3] & 2)
def set_ee_erase(self, val):
val = Utils.to_bool(val)
self.msr[3] &= 0xfd
self.msr[3] |= 0x02 if val else 0x00
def get_pindetect(self):
return not bool(self.msr[3] & 1)
def set_pindetect(self, val):
val = Utils.to_bool(val)
self.msr[3] &= 0xfe
self.msr[3] |= 0x01 if not val else 0x00
def get_por_delay(self):
delay = bool(self.msr[2] & 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[2] &= 0x7f
self.msr[2] |= delays[val] << 7
def get_p33_state(self):
return "high" if self.msr[2] & 0x08 else "low"
def set_p33_state(self, val):
val = Utils.to_bool(val)
self.msr[2] &= 0xf7
self.msr[2] |= 0x08 if val else 0x00
def get_uart_passthrough(self):
return bool(self.msr[2] & 0x40)
def set_uart_passthrough(self, val):
val = Utils.to_bool(val)
self.msr[2] &= 0xbf
self.msr[2] |= 0x40 if val else 0x00
def get_uart_pin_mode(self):
return "push-pull" if bool(self.msr[2] & 0x20) else "normal"
def set_uart_pin_mode(self, val):
delays = {"normal": 0, "push-pull": 1}
if val not in delays.keys():
raise ValueError("must be one of %s" % list(delays.keys()))
self.msr[2] &= 0xdf
self.msr[2] |= 0x20 if val else 0x00
def get_core_voltage(self):
if self.msr[4] == 0xea: return "low"
elif self.msr[4] == 0xf7: return "mid"
elif self.msr[4] == 0xfd: return "high"
else: return "unknown"
def set_core_voltage(self, val):
volt_vals = {"low": 0xea, "mid": 0xf7, "high": 0xfd}
if val not in volt_vals.keys():
raise ValueError("must be one of %s" % list(volt_vals.keys()))
self.msr[4] = volt_vals[val]

File diff suppressed because it is too large Load Diff

View File

@ -19,31 +19,41 @@
# SOFTWARE. # SOFTWARE.
# #
import serial
import argparse import argparse
import serial
class Utils: class Utils:
"""Common utility functions"""
@classmethod @classmethod
def to_bool(self, val): def to_bool(cls, val):
"""make sensible boolean from string or other type value""" """make sensible boolean from string or other type value"""
if isinstance(val, bool): return val if val is None:
if isinstance(val, int): return bool(val) return False
if len(val) == 0: return False if isinstance(val, bool):
return val
elif isinstance(val, int):
return bool(val)
elif len(val) == 0:
return False
else:
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(self, val): def to_int(cls, val):
"""make int from any value, nice error message if not possible""" """make int from any value, nice error message if not possible"""
try: return int(val, 0) try:
except: raise ValueError("invalid integer") return int(val, 0)
except:
raise ValueError("invalid integer")
@classmethod @classmethod
def hexstr(self, bytestr, sep=""): def hexstr(cls, 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 bytestr]) return sep.join(["%02X" % x for x in bytes(bytestr)])
class BaudType: class BaudType:
@ -55,5 +65,5 @@ class BaudType:
raise argparse.ArgumentTypeError("illegal baudrate") raise argparse.ArgumentTypeError("illegal baudrate")
return baud return baud
def __repr__(self): return "baudrate" def __repr__(self):
return "baudrate"

0
test/__init__.py Normal file
View File

19
test/iap15f2k61s2.yml Normal file
View File

@ -0,0 +1,19 @@
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]

19
test/stc12c2052ad.yml Normal file
View File

@ -0,0 +1,19 @@
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]

15
test/stc12c5a60s2.yml Normal file
View File

@ -0,0 +1,15 @@
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]

20
test/stc15f104e.yml Normal file
View File

@ -0,0 +1,20 @@
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]

19
test/stc15l104w.yml Normal file
View File

@ -0,0 +1,19 @@
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]

20
test/stc15w4k56s4.yml Normal file
View File

@ -0,0 +1,20 @@
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]

19
test/stc89c52rc.yml Normal file
View File

@ -0,0 +1,19 @@
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]

136
test/test_program.py Normal file
View File

@ -0,0 +1,136 @@
#
# 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("./test/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("./test/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("./test/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("./test/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("./test/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("./test/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("./test/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)

77
test/test_utils.py Normal file
View File

@ -0,0 +1,77 @@
#
# 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 unittest.mock import patch
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")