├── msvc ├── USBCompositeDevice.bin ├── stdafx.cpp ├── targetver.h ├── stdafx.h ├── ReadMe.txt ├── librech551.sln ├── librech551.vcxproj.filters ├── librech551.vcxproj └── getopt.h ├── usbisp ├── Makefile └── main.c ├── example ├── si5351 │ ├── i2c.h │ ├── Makefile │ ├── si5351.c │ ├── i2c.c │ └── si5351.h └── jump_to_bl │ ├── jump_to_bl.c │ └── Makefile ├── .gitignore └── README.md /msvc/USBCompositeDevice.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rgwan/librech551/HEAD/msvc/USBCompositeDevice.bin -------------------------------------------------------------------------------- /usbisp/Makefile: -------------------------------------------------------------------------------- 1 | DESTDIR := /usr/local 2 | CC := cc 3 | CFLAGS := -O2 4 | 5 | wchisptool:main.c 6 | $(CC) $(CFLAGS) main.c -o wchisptool `pkg-config --cflags --libs libusb-1.0` 7 | 8 | clean: 9 | rm -f wchisptool 10 | 11 | install: wchisptool 12 | cp wchisptool $(DESTDIR)/bin 13 | 14 | -------------------------------------------------------------------------------- /msvc/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // librech551.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /example/si5351/i2c.h: -------------------------------------------------------------------------------- 1 | typedef __bit bool; 2 | 3 | extern void i2c_init(); 4 | 5 | extern void i2c_start(); 6 | 7 | extern void i2c_stop(); 8 | 9 | extern void i2c_write(uint8_t data); 10 | 11 | extern bool i2c_read_ack(); 12 | 13 | extern bool i2c_read_nak(); 14 | 15 | extern uint8_t i2c_read(); 16 | 17 | #define TW_READ 0x01 18 | -------------------------------------------------------------------------------- /msvc/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /example/jump_to_bl/jump_to_bl.c: -------------------------------------------------------------------------------- 1 | #include <8051.h> 2 | 3 | #define BOOT_ADDR 0x3800 4 | 5 | /* This program just execute bootloader rom directly */ 6 | 7 | void main( void ) 8 | { 9 | EA = 0;/* Disable all interrupts */ 10 | 11 | __asm 12 | LJMP BOOT_ADDR /* Jump to bootloader */ 13 | __endasm; 14 | while(1); 15 | } 16 | -------------------------------------------------------------------------------- /example/jump_to_bl/Makefile: -------------------------------------------------------------------------------- 1 | jump_to_bl.bin: jump_to_bl.ihx 2 | objcopy -I ihex -O binary jump_to_bl.ihx jump_to_bl.bin 3 | 4 | jump_to_bl.ihx: jump_to_bl.c 5 | sdcc -I. -mmcs51 --model-small --opt-code-speed jump_to_bl.c 6 | 7 | clean: 8 | rm -f *.asm *.ihx *.lk *.lst *.bin *.map *.mem *.rel *.rst *.sym 9 | 10 | flash: jump_to_bl.bin 11 | wchisptool -f jump_to_bl.bin -g 12 | -------------------------------------------------------------------------------- /msvc/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | #include "targetver.h" 8 | 9 | // Suppress unsafe warnings 10 | //#define _CRT_SECURE_NO_DEPRECATE 11 | //#define _CRT_SECURE_NO_WARNINGS 12 | 13 | //#include 14 | //#include -------------------------------------------------------------------------------- /example/si5351/Makefile: -------------------------------------------------------------------------------- 1 | si5351.bin: si5351.ihx 2 | objcopy -I ihex -O binary si5351.ihx si5351.bin 3 | 4 | si5351.ihx: si5351.c i2c.c si5351.h 5 | sdcc -I. -mmcs51 --model-small --xram-size 1024 --opt-code-speed -c i2c.c 6 | sdcc -I. -mmcs51 --model-small --xram-size 1024 --opt-code-speed si5351.c i2c.rel 7 | 8 | clean: 9 | rm -f *.asm *.ihx *.lk *.lst *.bin *.map *.mem *.rel *.rst *.sym 10 | 11 | flash: si5351.bin 12 | wchisptool -f si5351.bin -g 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.hex 3 | wchisptool 4 | isptool 5 | *.asm 6 | *.ihx 7 | *.lk 8 | *.lst 9 | *.map 10 | *.mem 11 | *.rel 12 | *.rst 13 | *.sym 14 | 15 | #OS junk files 16 | [Tt]humbs.db 17 | *.DS_Store 18 | 19 | #Visual Studio files 20 | *.[Oo]bj 21 | *.user 22 | *.aps 23 | *.pch 24 | *.vspscc 25 | *.vssscc 26 | *_i.c 27 | *_p.c 28 | *.ncb 29 | *.suo 30 | *.tlb 31 | *.tlh 32 | *.bak 33 | *.[Cc]ache 34 | *.ilk 35 | *.log 36 | *.sbr 37 | *.sdf 38 | *.opensdf 39 | *.unsuccessfulbuild 40 | ipch/ 41 | obj/ 42 | [Ll]ib 43 | [Bb]in 44 | [Dd]ebug*/ 45 | [Rr]elease*/ 46 | Ankh.NoLoad 47 | *.VC.db 48 | 49 | #GCC files 50 | *.o 51 | *.d 52 | *.res 53 | *.a 54 | 55 | #Visual Studio Code files 56 | .vscode/ 57 | 58 | #Libusb headers and libs 59 | libusb/ -------------------------------------------------------------------------------- /msvc/ReadMe.txt: -------------------------------------------------------------------------------- 1 | Build Executables 2 | Generate EXE file for Microsoft Windows requires Microsoft Visual Studio 2017 and Windows Kits 10.0.15063.0 or above. 3 | If your system does not meet the stated requirement, go to Microsoft's website and download the installer for Microsoft Visual Studio 2017 Community Version (for free). 4 | Note: It is possible to compile the source with legacy Visual Studio although it is not officially supported. 5 | 1.Download the entire repository and unzip to anywhere you like 6 | 2.Navigate to "msvc" folder and create a folder called "libusb" under "msvc" directory 7 | 3.Go to https://github.com/libusb/libusb/releases to get the latest stable binary snapshots of libusb(e.g. libusb v1.0.21), 8 | download the file with extension "7z" or "tar.bz" , then unzip it to "msvc\libusb" . Now your "msvc\libusb" should contain at least these folders : "MS32", "MS64" and "include" 9 | 4.Launch "msvc\librech551.sln" and choose your targeting platform (e.g. Release x64), then start compiling. 10 | -------------------------------------------------------------------------------- /example/si5351/si5351.c: -------------------------------------------------------------------------------- 1 | #include <8051.h> 2 | #include 3 | 4 | #include "i2c.h" 5 | #include "si5351.h" 6 | 7 | 8 | #define BOOT_ADDR 0x3800 9 | 10 | /* This function provided a way to the internal bootloader */ 11 | void jump_to_bootloader() 12 | { 13 | EA = 0;/* Disable all interrupts */ 14 | 15 | __asm 16 | LJMP BOOT_ADDR /* Jump to bootloader */ 17 | __endasm; 18 | while(1); 19 | } 20 | 21 | 22 | bool si5351_write(uint8_t reg_address, uint8_t value) 23 | { 24 | i2c_start(); 25 | i2c_write(SI5351_AR); 26 | if(i2c_read_nak()) 27 | goto fault; 28 | 29 | i2c_write(reg_address); 30 | if(i2c_read_nak()) 31 | goto fault; 32 | 33 | i2c_write(value); 34 | if(i2c_read_nak()) 35 | goto fault; 36 | 37 | i2c_stop(); 38 | return 1; 39 | fault: 40 | i2c_stop(); 41 | return 0; 42 | } 43 | 44 | bool si5351_init() 45 | { 46 | si5351a_revb_register_t __code *pair; 47 | int i; 48 | for(i = 0; i < SI5351A_REVB_REG_CONFIG_NUM_REGS; i++) 49 | { 50 | pair = &si5351a_revb_registers[i]; 51 | if(!si5351_write(pair->address & 0xff, pair->value)) 52 | return 0; 53 | } 54 | return 1; 55 | } 56 | 57 | 58 | void main( void ) 59 | { 60 | i2c_init(); 61 | si5351_init(); 62 | jump_to_bootloader(); 63 | } 64 | -------------------------------------------------------------------------------- /msvc/librech551.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.6 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "librech551", "librech551.vcxproj", "{BC24F50A-AC7E-47B7-AE12-C9DC60284C46}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {BC24F50A-AC7E-47B7-AE12-C9DC60284C46}.Debug|x64.ActiveCfg = Debug|x64 17 | {BC24F50A-AC7E-47B7-AE12-C9DC60284C46}.Debug|x64.Build.0 = Debug|x64 18 | {BC24F50A-AC7E-47B7-AE12-C9DC60284C46}.Debug|x86.ActiveCfg = Debug|Win32 19 | {BC24F50A-AC7E-47B7-AE12-C9DC60284C46}.Debug|x86.Build.0 = Debug|Win32 20 | {BC24F50A-AC7E-47B7-AE12-C9DC60284C46}.Release|x64.ActiveCfg = Release|x64 21 | {BC24F50A-AC7E-47B7-AE12-C9DC60284C46}.Release|x64.Build.0 = Release|x64 22 | {BC24F50A-AC7E-47B7-AE12-C9DC60284C46}.Release|x86.ActiveCfg = Release|Win32 23 | {BC24F50A-AC7E-47B7-AE12-C9DC60284C46}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /example/si5351/i2c.c: -------------------------------------------------------------------------------- 1 | #include <8051.h> 2 | #include 3 | #include "i2c.h" 4 | 5 | #define I2C_SDAT P3_4 6 | #define I2C_SCLK P3_3 7 | 8 | 9 | 10 | void i2c_init() 11 | { /* GPIO port initial */ 12 | I2C_SDAT = 1; 13 | I2C_SCLK = 1; 14 | } 15 | 16 | void i2c_delay() 17 | { 18 | volatile char i = 20; 19 | while(i--); 20 | } 21 | 22 | void i2c_start() 23 | { 24 | I2C_SDAT = 0; 25 | i2c_delay(); 26 | 27 | I2C_SCLK = 0; 28 | i2c_delay(); 29 | } 30 | 31 | void i2c_stop() 32 | { 33 | I2C_SDAT = 0; 34 | I2C_SCLK = 1; 35 | i2c_delay(); 36 | 37 | I2C_SDAT = 1; 38 | i2c_delay(); 39 | } 40 | 41 | void i2c_write(uint8_t data) 42 | { 43 | int i; 44 | 45 | for(i = 0; i < 8; i++) 46 | { 47 | data <<= 1; 48 | I2C_SDAT = CY; 49 | 50 | I2C_SCLK = 1; 51 | i2c_delay(); 52 | 53 | I2C_SCLK = 0; 54 | i2c_delay(); 55 | } 56 | } 57 | 58 | uint8_t i2c_read() 59 | { 60 | int i; 61 | uint8_t ret = 0; 62 | 63 | I2C_SDAT = 1; 64 | for(i = 0; i < 8; i++) 65 | { 66 | ret <<= 1; 67 | I2C_SCLK = 1; 68 | i2c_delay(); 69 | 70 | if(I2C_SDAT) 71 | ret |= 0x01; 72 | 73 | I2C_SCLK = 0; 74 | i2c_delay(); 75 | 76 | } 77 | return ret; 78 | } 79 | 80 | bool i2c_read_ack() 81 | { 82 | bool status; 83 | 84 | I2C_SDAT = 1; 85 | 86 | I2C_SCLK = 1; 87 | i2c_delay(); 88 | 89 | status = I2C_SDAT; 90 | 91 | I2C_SCLK = 0; 92 | i2c_delay(); 93 | 94 | return !status; 95 | } 96 | 97 | bool i2c_read_nak() 98 | { 99 | return !i2c_read_ack(); 100 | } 101 | -------------------------------------------------------------------------------- /msvc/librech551.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {89f3b65c-ff85-4472-84ef-6a5faa951e06} 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | 32 | 33 | Source Files 34 | 35 | 36 | USBISP 37 | 38 | 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LibreCH551 2 | ---------- 3 | 4 | An __open-source__ command line flasher program and SDK library for WCH(Nanjing QinHeng Corp.)'s CH55x family. 5 | [Our Wiki contains a lot of useful tips, it's worth to check out!](../../wiki/Home) 6 | 7 | The CH55x is a series of 8051 microcontroller with dedicated USB peripheral. CH553/CH554 can be programmed as a USB host. 8 | The cheapest one, CH551 only costs 1.5 CNY in retail. It is the ultimate and ideal solution for many low-end USB applications. 9 | 10 | Up to now, we have tested out CH551 and CH554, all functions work fine except option byte. 11 | 12 | If someone want to help me, please __start__, __fork__ and support more chips, Thanks! 13 | 14 | 15 | TODO 16 | ------------ 17 | Implement chip programming via UART for devices workign on USB Host mode. (It is very simple to realize: just add serial port interface to the program and 0x619e, accumulate checksum in packet tail). 18 | 19 | Implement new CH55x ISP protocol (for bootloader version > 2.30), for now we don't have any chip shipped with the new bootloader: WCH's FAE said that they will release chips with new bootloader after Apr.2018. 20 | 21 | __Contributions are always welcome__ 22 | 23 | Command Line Parameters 24 | ------------ 25 | * __-f \__ Erase the code flash and download binary codes to CH55x, note that this tool only accepts `.bin` files, `.hex` files will not be accepted. 26 | The Eclipse SDCC environment with the setup [described in our wiki](../../wiki/Setup-SDCC-developing-environment-with-Eclipse) automatically generates `.bin` file. To convert a hex file to bin file, on Linux, use `objdump`, on Windows, use `hex2bin.exe` in [`win_tools.zip`](../../wiki/win_tools.zip). 27 | * __-g__ Execute the user program after downloading 28 | * __-e__ Erase chip only 29 | * __-D \__ Read data flash to a file 30 | * __-d \__ Write the content of a file to data flash 31 | * __-h__ Display help message 32 | 33 | For Linux Users 34 | ---------- 35 | 36 | * Build: Type `make` in `usbisp` directory. 37 | * Install:Type `make install` in `usbisp` directory, you can also pass DESTDIR to the script to set installation path. 38 | * Linux does not require a specific driver for this program. 39 | 40 | For Windows Users 41 | ---------- 42 | * The Tool pack for Windows is available [here](../../wiki/win_tools.zip). 43 | * The wiki page "[Setup SDCC developing environment with Eclipse](../../wiki/Setup-SDCC-developing-environment-with-Eclipse)" demonstrates how to setup an IDE for better code editing. 44 | * On Windows, CH554 ISP mode requires a libusb driver implementation to enable direct device access for librech551. 45 | 46 | __Driver Installation__ 47 | 48 | 1. Connect your CH55x to one of USB ports on your PC, make sure the MCU enters ISP mode. 49 | 2. Launch zadig (included in [`win_tools.zip`](../../wiki/win_tools.zip)), open `Options` menu and click `List All Devices`, 50 | you should be able to find your CH55x (Usually names `USB Module`), optionally you can change its name by check the `Edit` box. 51 | 3. Double check that the USB ID is correct, USB ID is VID plus PID, for CH554, the USB ID is `4348 55E0`. 52 | 4. Select `libusb-win32` and click `Install Driver`, quit Zadig after driver installation. 53 | * Note: due to unknown reason, sometimes the `libusbK` driver won't work on some machine with very new USB 3.1 controller. 54 | If your PC can not recognize the USB ISP device, try `winusb` or `libusb-win32` instead. 55 | 56 | __Build Executables__ 57 | * Generate EXE file for Microsoft Windows requires __Microsoft Visual Studio 2017__ and __Windows Kits 10.0.15063.0 or above__. 58 | If your system does not meet the stated requirement, go to Microsoft's website and download the installer for __Microsoft Visual Studio 2017 Community Version__. 59 | * It is possible to compile the source with legacy Visual Studio although it is not officially supported. 60 | 1. Download the entire repository and unzip to anywhere you like 61 | 2. Navigate to `msvc` folder and create a folder called `libusb` under `msvc` directory 62 | 3. Go to to get the latest __stable__ binary snapshots of libusb(e.g. [libusb v1.0.21](https://github.com/libusb/libusb/releases/tag/v1.0.21)), download the file with extension `7z` or `tar.bz`, then unzip it to `msvc\libusb`. Now your `msvc\libusb` should contain at least these folders : `MS32`, `MS64` and `include` 63 | 4. Launch `msvc\librech551.sln` and choose your targeting platform (e.g. Release x64), then start compiling. 64 | * (Windows version only) To remove VC runtime dependency, releases on Github release page is built on Visual C++ together with [`VC-LTL`](https://github.com/Chuyu-Team/VC-LTL). 65 | 66 | License 67 | ---------- 68 | 69 | GPLv3 70 | 71 | Author(s) 72 | ---------- 73 | 74 | [Zhiyuan Wan](https://github.com/rgwan) 75 | 76 | [Rikka0w0](https://github.com/rikka0w0) 77 | -------------------------------------------------------------------------------- /msvc/librech551.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {BC24F50A-AC7E-47B7-AE12-C9DC60284C46} 24 | Win32Proj 25 | librech551 26 | 10.0.15063.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v141_xp 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v141_xp 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v141_xp 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v141_xp 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | $(SolutionDir)$(Platform)\$(Configuration)\ 76 | $(Platform)\$(Configuration)\ 77 | 78 | 79 | true 80 | 81 | 82 | false 83 | $(SolutionDir)$(Platform)\$(Configuration)\ 84 | $(Platform)\$(Configuration)\ 85 | 86 | 87 | false 88 | 89 | 90 | 91 | 92 | 93 | Level3 94 | Disabled 95 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 96 | false 97 | 98 | 99 | Console 100 | 101 | 102 | 103 | 104 | 105 | 106 | Level3 107 | Disabled 108 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 109 | false 110 | 111 | 112 | Console 113 | 114 | 115 | 116 | 117 | Level3 118 | 119 | 120 | MaxSpeed 121 | true 122 | true 123 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 124 | false 125 | 126 | 127 | Console 128 | true 129 | true 130 | 131 | 132 | copy /Y $(SolutionDir)\libusb\MS32\dll\libusb-1.0.dll $(OutDir) 133 | Copying libusb dll... 134 | 135 | 136 | 137 | 138 | Level3 139 | 140 | 141 | MaxSpeed 142 | true 143 | true 144 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 145 | false 146 | 147 | 148 | Console 149 | true 150 | true 151 | 152 | 153 | copy /Y $(SolutionDir)\libusb\MS64\dll\libusb-1.0.dll $(OutDir) 154 | 155 | 156 | Copying libusb dll... 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /example/si5351/si5351.h: -------------------------------------------------------------------------------- 1 | /* 2 | * si5351.h - Si5351 library for ch55x 8051 series usb micro controller 3 | * 4 | * Copyright (C) 2018 Zhiyuan Wan 5 | * 6 | * This file is deriived from Jason Milldrum's AVR SI5351 library. 7 | * Copyright (C) 2014 Jason Milldrum 8 | * 9 | * Many defines derived from clk-si5351.h in the Linux kernel. 10 | * Sebastian Hesselbarth 11 | * Rabeeh Khoury 12 | * 13 | * do_div() macro derived from /include/asm-generic/div64.h in 14 | * the Linux kernel. 15 | * Copyright (C) 2003 Bernardo Innocenti 16 | * 17 | * This program is free software: you can redistribute it and/or modify 18 | * it under the terms of the GNU General Public License as published by 19 | * the Free Software Foundation, either version 3 of the License, or 20 | * (at your option) any later version. 21 | * 22 | * This program is distributed in the hope that it will be useful, 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | * GNU General Public License for more details. 26 | * 27 | * You should have received a copy of the GNU General Public License 28 | * along with this program. If not, see . 29 | */ 30 | 31 | 32 | #ifndef SI5351_H_ 33 | #define SI5351_H_ 34 | 35 | /* Define definitions */ 36 | 37 | #define SI5351_BUS_BASE_ADDR 0xC0 38 | #define SI5351_XTAL_FREQ 26000000 39 | #define SI5351_PLL_FIXED 900000000 40 | 41 | /* 42 | * Si5351A Rev B Configuration Register Export Header File 43 | * 44 | * This file represents a series of Silicon Labs Si5351A Rev B 45 | * register writes that can be performed to load a single configuration 46 | * on a device. It was created by a Silicon Labs ClockBuilder Pro 47 | * export tool. 48 | * 49 | * Part: Si5351A Rev B 50 | * Design ID: 51 | * Includes Pre/Post Download Control Register Writes: Yes 52 | * Created By: ClockBuilder Pro v2.21 [2018-01-19] 53 | * Timestamp: 2018-03-16 18:42:24 GMT+08:00 54 | * 55 | * A complete design report corresponding to this export is included at the end 56 | * of this header file. 57 | * 58 | */ 59 | 60 | #define SI5351A_REVB_REG_CONFIG_NUM_REGS 57 61 | 62 | typedef struct 63 | { 64 | unsigned int address; /* 16-bit register address */ 65 | unsigned char value; /* 8-bit register data */ 66 | 67 | } si5351a_revb_register_t; 68 | 69 | si5351a_revb_register_t const si5351a_revb_registers[SI5351A_REVB_REG_CONFIG_NUM_REGS] = 70 | { 71 | { 0x0002, 0x53 }, 72 | { 0x0003, 0x00 }, 73 | { 0x0007, 0x00 }, 74 | { 0x000F, 0x00 }, 75 | { 0x0010, 0x4F }, 76 | { 0x0011, 0x0F }, 77 | { 0x0012, 0x0F }, 78 | { 0x0013, 0x8C }, 79 | { 0x0014, 0x8C }, 80 | { 0x0015, 0x8C }, 81 | { 0x0016, 0x8C }, 82 | { 0x0017, 0x8C }, 83 | { 0x001A, 0x00 }, 84 | { 0x001B, 0x0D }, 85 | { 0x001C, 0x00 }, 86 | { 0x001D, 0x0D }, 87 | { 0x001E, 0x93 }, 88 | { 0x001F, 0x00 }, 89 | { 0x0020, 0x00 }, 90 | { 0x0021, 0x09 }, 91 | { 0x002A, 0x00 }, 92 | { 0x002B, 0x01 }, 93 | { 0x002C, 0x00 }, 94 | { 0x002D, 0x01 }, 95 | { 0x002E, 0x00 }, 96 | { 0x002F, 0x00 }, 97 | { 0x0030, 0x00 }, 98 | { 0x0031, 0x00 }, 99 | { 0x0032, 0x00 }, 100 | { 0x0033, 0x01 }, 101 | { 0x0034, 0x00 }, 102 | { 0x0035, 0x19 }, 103 | { 0x0036, 0x00 }, 104 | { 0x0037, 0x00 }, 105 | { 0x0038, 0x00 }, 106 | { 0x0039, 0x00 }, 107 | { 0x003A, 0x00 }, 108 | { 0x003B, 0x01 }, 109 | { 0x003C, 0x01 }, 110 | { 0x003D, 0x93 }, 111 | { 0x003E, 0x00 }, 112 | { 0x003F, 0x00 }, 113 | { 0x0040, 0x00 }, 114 | { 0x0041, 0x00 }, 115 | { 0x005A, 0x00 }, 116 | { 0x005B, 0x00 }, 117 | { 0x0095, 0x00 }, 118 | { 0x0096, 0x00 }, 119 | { 0x0097, 0x00 }, 120 | { 0x0098, 0x00 }, 121 | { 0x0099, 0x00 }, 122 | { 0x009A, 0x00 }, 123 | { 0x009B, 0x00 }, 124 | { 0x00A2, 0x00 }, 125 | { 0x00A3, 0x00 }, 126 | { 0x00A4, 0x00 }, 127 | { 0x00B7, 0x12 }, 128 | 129 | }; 130 | 131 | #define SI5351_AR 0xC0 132 | 133 | /* 134 | * Design Report 135 | * 136 | * Overview 137 | * ======== 138 | * Part: Si5351A 139 | * Project File: C:\Users\ZHIYUAN\Documents\Si5351A-RevB-Project.slabtimeproj 140 | * Created By: ClockBuilder Pro v2.21 [2018-01-19] 141 | * Timestamp: 2018-03-16 18:42:24 GMT+08:00 142 | * 143 | * Design Rule Check 144 | * ================= 145 | * Errors: 146 | * - No errors 147 | * 148 | * Warnings: 149 | * - No warnings 150 | * 151 | * Design 152 | * ====== 153 | * Inputs: 154 | * IN0: 26 MHz 155 | * 156 | * Outputs: 157 | * OUT0: 30 MHz 158 | * Enabled LVCMOS 8 mA 159 | * Offset 0.000 s 160 | * OUT1: 15 MHz 161 | * Enabled LVCMOS 8 mA 162 | * Offset 0.000 s 163 | * OUT2: 1 MHz 164 | * Enabled LVCMOS 8 mA 165 | * Offset 0.000 s 166 | * 167 | * Frequency Plan 168 | * ============== 169 | * PLL_A: 170 | * Enabled Features = None 171 | * Fvco = 900 MHz 172 | * M = 34.6153846153846153... [ 34 + 8/13 ] 173 | * Input0: 174 | * Source = Crystal 175 | * Source Frequency = 26 MHz 176 | * Fpfd = 26 MHz 177 | * Load Capacitance = Not_Applicable 178 | * Output0: 179 | * Features = None 180 | * Disabled State = StopLow 181 | * R = 1 (2^0) 182 | * Fout = 30 MHz 183 | * N = 30 184 | * Output1: 185 | * Features = None 186 | * Disabled State = StopLow 187 | * R = 1 (2^0) 188 | * Fout = 15 MHz 189 | * N = 60 190 | * Output2: 191 | * Features = None 192 | * Disabled State = StopLow 193 | * R = 1 (2^0) 194 | * Fout = 1 MHz 195 | * N = 900 196 | * 197 | * Settings 198 | * ======== 199 | * 200 | * Location Setting Name Decimal Value Hex Value 201 | * ------------ ------------- ----------------- ----------------- 202 | * 0x0002[3] XO_LOS_MASK 0 0x0 203 | * 0x0002[4] CLK_LOS_MASK 1 0x1 204 | * 0x0002[5] LOL_A_MASK 0 0x0 205 | * 0x0002[6] LOL_B_MASK 1 0x1 206 | * 0x0002[7] SYS_INIT_MASK 0 0x0 207 | * 0x0003[7:0] CLK_OEB 0 0x00 208 | * 0x0007[7:4] I2C_ADDR_CTRL 0 0x0 209 | * 0x000F[2] PLLA_SRC 0 0x0 210 | * 0x000F[3] PLLB_SRC 0 0x0 211 | * 0x000F[4] PLLA_INSELB 0 0x0 212 | * 0x000F[5] PLLB_INSELB 0 0x0 213 | * 0x000F[7:6] CLKIN_DIV 0 0x0 214 | * 0x0010[1:0] CLK0_IDRV 3 0x3 215 | * 0x0010[3:2] CLK0_SRC 3 0x3 216 | * 0x0010[4] CLK0_INV 0 0x0 217 | * 0x0010[5] MS0_SRC 0 0x0 218 | * 0x0010[6] MS0_INT 0 0x0 219 | * 0x0010[7] CLK0_PDN 0 0x0 220 | * 0x0011[1:0] CLK1_IDRV 3 0x3 221 | * 0x0011[3:2] CLK1_SRC 3 0x3 222 | * 0x0011[4] CLK1_INV 0 0x0 223 | * 0x0011[5] MS1_SRC 0 0x0 224 | * 0x0011[6] MS1_INT 0 0x0 225 | * 0x0011[7] CLK1_PDN 0 0x0 226 | * 0x0012[1:0] CLK2_IDRV 3 0x3 227 | * 0x0012[3:2] CLK2_SRC 3 0x3 228 | * 0x0012[4] CLK2_INV 0 0x0 229 | * 0x0012[5] MS2_SRC 0 0x0 230 | * 0x0012[6] MS2_INT 0 0x0 231 | * 0x0012[7] CLK2_PDN 0 0x0 232 | * 0x0013[1:0] CLK3_IDRV 0 0x0 233 | * 0x0013[3:2] CLK3_SRC 3 0x3 234 | * 0x0013[4] CLK3_INV 0 0x0 235 | * 0x0013[5] MS3_SRC 0 0x0 236 | * 0x0013[6] MS3_INT 0 0x0 237 | * 0x0013[7] CLK3_PDN 1 0x1 238 | * 0x0014[1:0] CLK4_IDRV 0 0x0 239 | * 0x0014[3:2] CLK4_SRC 3 0x3 240 | * 0x0014[4] CLK4_INV 0 0x0 241 | * 0x0014[5] MS4_SRC 0 0x0 242 | * 0x0014[6] MS4_INT 0 0x0 243 | * 0x0014[7] CLK4_PDN 1 0x1 244 | * 0x0015[1:0] CLK5_IDRV 0 0x0 245 | * 0x0015[3:2] CLK5_SRC 3 0x3 246 | * 0x0015[4] CLK5_INV 0 0x0 247 | * 0x0015[5] MS5_SRC 0 0x0 248 | * 0x0015[6] MS5_INT 0 0x0 249 | * 0x0015[7] CLK5_PDN 1 0x1 250 | * 0x0016[1:0] CLK6_IDRV 0 0x0 251 | * 0x0016[3:2] CLK6_SRC 3 0x3 252 | * 0x0016[4] CLK6_INV 0 0x0 253 | * 0x0016[5] MS6_SRC 0 0x0 254 | * 0x0016[6] FBA_INT 0 0x0 255 | * 0x0016[7] CLK6_PDN 1 0x1 256 | * 0x0017[1:0] CLK7_IDRV 0 0x0 257 | * 0x0017[3:2] CLK7_SRC 3 0x3 258 | * 0x0017[4] CLK7_INV 0 0x0 259 | * 0x0017[5] MS7_SRC 0 0x0 260 | * 0x0017[6] FBB_INT 0 0x0 261 | * 0x0017[7] CLK7_PDN 1 0x1 262 | * 0x001C[17:0] MSNA_P1 3918 0x00F4E 263 | * 0x001F[19:0] MSNA_P2 10 0x0000A 264 | * 0x001F[23:4] MSNA_P3 13 0x0000D 265 | * 0x002C[17:0] MS0_P1 3328 0x00D00 266 | * 0x002F[19:0] MS0_P2 0 0x00000 267 | * 0x002F[23:4] MS0_P4 1 0x00001 268 | * 0x0034[17:0] MS1_P1 7168 0x01C00 269 | * 0x0037[19:0] MS1_P2 0 0x00000 270 | * 0x0037[23:4] MS1_P4 1 0x00001 271 | * 0x003C[17:0] MS2_P1 114688 0x1C000 272 | * 0x003F[19:0] MS2_P2 0 0x00000 273 | * 0x003F[23:4] MS2_P4 1 0x00001 274 | * 0x005A[7:0] MS6_P2 0 0x00 275 | * 0x005B[7:0] MS7_P2 0 0x00 276 | * 0x0095[14:0] SSDN_P2 0 0x0000 277 | * 0x0095[7] SSC_EN 0 0x0 278 | * 0x0097[14:0] SSDN_P3 0 0x0000 279 | * 0x0097[7] SSC_MODE 0 0x0 280 | * 0x0099[11:0] SSDN_P1 0 0x000 281 | * 0x009A[15:4] SSUDP 0 0x000 282 | * 0x00A2[21:0] VCXO_PARAM 0 0x000000 283 | * 0x00B7[7:6] XTAL_CL 0 0x0 284 | * 285 | * 286 | */ 287 | 288 | 289 | #endif /* SI5351_H_ */ 290 | 291 | -------------------------------------------------------------------------------- /usbisp/main.c: -------------------------------------------------------------------------------- 1 | #ifdef _MSC_VER 2 | #include "..\msvc\stdafx.h" 3 | #endif 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #ifdef _MSC_VER 12 | // MSVC 13 | 14 | #include "..\msvc\libusb\include\libusb-1.0\libusb.h" 15 | #ifdef _WIN64 16 | #pragma comment(lib, "libusb\\MS64\\dll\\libusb-1.0.lib") 17 | #else 18 | #pragma comment(lib, "libusb\\MS32\\dll\\libusb-1.0.lib") 19 | #endif 20 | 21 | // POSIX getopt() 22 | #include "..\msvc\getopt.h" 23 | #else 24 | // Linux GCC 25 | #include 26 | #include 27 | #endif 28 | 29 | #define VENDOR_ID 0x4348 30 | #define PRODUCT_ID 0x55e0 /* CH551 Bootloader VID-PID pair */ 31 | 32 | 33 | 34 | static struct libusb_device_handle *devh = NULL; 35 | 36 | 37 | static int ep_in_addr = 0x82; 38 | static int ep_out_addr = 0x02; 39 | 40 | /* 命令格式:操作-1byte|长度-1byte|数据 */ 41 | 42 | static char detect_chip_cmd_v1[64] = {0xa2, 0x13, 0x55, 0x53, 0x42, 0x20, 0x44, 0x42, 43 | 0x47, 0x20, 0x43, 0x48, 0x35, 0x35, 0x39, 0x20, 44 | 0x26, 0x20, 0x49, 0x53, 0x50, 0x00}; /* 检测型号 */ 45 | 46 | static char use_interface_cmd_v1[2] = {0xbb, 0x00}; /* 使用IF */ 47 | 48 | static char erase_page_cmd_v1[4] = {0xa9, 0x02, 0x00, 0x00}; /* 1KB/Page? */ 49 | 50 | static char key_input_cmd_v1[6] = {0xa6, 0x04, 0x00, 0x00, 0x00, 0x00}; 51 | 52 | static char run_cmd_v1[4] = {0xa5, 0x02, 0x01, 0x00}; 53 | 54 | static char write_cmd_v1[64] = {0xa8, 0x00, 0x00, 0x00}; /* cmd, length, addrl, addrh, data */ 55 | static char verify_cmd_v1[64] = {0xa7, 0x00, 0x00, 0x00}; /* cmd, length, addrl, addrh, data */ 56 | 57 | static char read_df_cmd_v1[2] = {0xb7, 0x00}; 58 | static char claim_device_cmd_v1[4] = {0xa5, 0x02, 0x00, 0x00}; 59 | static char erase_df_cmd_v1[4] ={0xb5, 0x02, 0x00, 0xc0}; 60 | static char write_df_cmd_v1[64] = {0xb6, 0x00, 0x00, 0x00}; /* cmd, length, addrl, addrh, data */ 61 | 62 | static char detect_chip_cmd_v2[] = { //cmd, len, ?, model, series? 63 | 0xa1, 0x12, 0x00, 0x52, 0x11, 0x4d, 0x43, 0x55, 0x20, 0x49, 0x53, 64 | 0x50, 0x20, 0x26, 0x20, 0x57, 0x43, 0x48, 0x2e, 0x43, 0x4e 65 | }; 66 | static char read_cfg_cmd_v2[] = { 67 | 0xa7, 0x02, 0x00, 0x1f, 0x00 68 | }; 69 | static char erase_chip_cmd_v2[] = { //2KB per page? 70 | 0xa4, 0x01, 0x00, 0x08 71 | }; 72 | static char write_cmd_v2[64] = {0xa5, 0x00, 0x00, 0x00}; /* cmd, length, zero, addrl, 73 | addrh, z, z, random, data */ 74 | 75 | static char verify_cmd_v2[64] = {0xa6, 0x00, 0x00, 0x00}; /* cmd, length, zero, addrl, */ 76 | 77 | 78 | int write_to_device(unsigned char *data, int size) 79 | { 80 | int actual_length; 81 | int rc = libusb_bulk_transfer(devh, ep_out_addr, data, size, 82 | &actual_length, 4000); 83 | if (rc < 0) { 84 | fprintf(stderr, "Error while bulking out: %s\n", libusb_error_name(rc)); 85 | } 86 | return actual_length; 87 | } 88 | 89 | int read_from_device(unsigned char *data, int size) 90 | { 91 | int actual_length; 92 | int rc = libusb_bulk_transfer(devh, ep_in_addr, data, size, &actual_length, 93 | 400000); 94 | if (rc == LIBUSB_ERROR_TIMEOUT) { 95 | printf("timeout (%d)\n", actual_length); 96 | return -1; 97 | } else if (rc < 0) { 98 | fprintf(stderr, "Error while bulking in: %s\n", libusb_error_name(rc)); 99 | return -1; 100 | } 101 | 102 | return actual_length; 103 | } 104 | 105 | void hexdump(unsigned char *data, int size) 106 | { 107 | int i; 108 | for(i = 0; i < size; i++) 109 | { 110 | printf("0x%02X ", data[i]); 111 | if((i + 1) % 8 == 0) 112 | putchar('\n'); 113 | } 114 | putchar('\n'); 115 | } 116 | 117 | void printusage(char *selfname) 118 | { 119 | printf("Usage %s: [OPTIONS]\n", selfname); 120 | printf("\t-f \tSpecify your program file to be flash to the chip\n"); 121 | printf("\t-d \tSpecify data flash file to be flash to the chip\n"); 122 | printf("\t-D \tSpecify data flash file to be read from the chip\n"); 123 | printf("\t-e\t\t\tErase chip\n"); 124 | printf("\t-w\t\t\tErase data flash\n"); 125 | printf("\t-h\t\t\tShow this message and exit\n"); 126 | printf("\t-g\t\t\tRun your program after the device has been programmed (Not supported in v2 mode)\n"); 127 | printf("\t-n\t\t\tUse new ISP protocol for BL version > 2.30, only tested on CH552T\n\n"); 128 | printf("Copyright 2018\tZhiyuan Wan, GPL v3 License, all operations must to be based on the basic law, 0..0\n"); 129 | } 130 | 131 | uint8_t lastkey; 132 | 133 | void key_input_v2() 134 | { 135 | uint8_t inbuf[64]; 136 | uint8_t outbuf[64] = {0xa3, 0x30, 0x00}; 137 | int i; 138 | write_to_device(read_cfg_cmd_v2, sizeof(read_cfg_cmd_v2)); 139 | read_from_device(inbuf, 30); 140 | uint8_t checksum = inbuf[22]; 141 | checksum += inbuf[23]; 142 | checksum += inbuf[24]; 143 | checksum += inbuf[25]; 144 | 145 | for(i = 0; i < 0x30; i++) 146 | outbuf[i + 3] = checksum ^ 0; //给全零密钥 147 | 148 | lastkey = checksum ^ 0 + 0x52; //坑爹协议 149 | 150 | write_to_device(outbuf, 0x30 + 3); 151 | read_from_device(inbuf, 6); //TODO 152 | 153 | } 154 | 155 | int main(int argc, char **argv) 156 | { 157 | int rc; 158 | int i; 159 | 160 | char inbuffer[64]; 161 | 162 | char *file_buffer = 0; 163 | 164 | FILE *fp = 0; 165 | int file_length; 166 | 167 | char file_name[255]; 168 | 169 | int require_download = 0; 170 | int require_exec = 0; 171 | int require_erase = 0; 172 | int require_dataflash_read = 0; 173 | int require_dataflash_write = 0; 174 | int require_dataflash_erase = 0; 175 | int require_protocol_v2 = 0; 176 | 177 | char df_read_file_name[255]; 178 | char df_write_file_name[255]; 179 | 180 | int device_flash_size = 0; 181 | int device_dataflash_size = 0; 182 | char ch; 183 | 184 | while ((ch = getopt(argc,argv,"f:gewnhD:d:")) != -1) 185 | { 186 | switch(ch) 187 | { 188 | case 'f':/* 指定文件 */ 189 | strncpy(file_name, optarg, 255); 190 | require_download = 1; 191 | break; 192 | case 'g':/* 下载后执行 */ 193 | require_exec = 1; 194 | break; 195 | case 'e':/* 仅擦除芯片 */ 196 | require_erase = 1; 197 | break; 198 | case 'D':/* 读DataFlash */ 199 | require_dataflash_read = 1; 200 | strncpy(df_read_file_name, optarg, 255); 201 | break; 202 | case 'd':/* 写DataFlash */ 203 | require_dataflash_write = 1; 204 | strncpy(df_write_file_name, optarg, 255); 205 | break; 206 | case 'w':/* 擦DataFlash */ 207 | require_dataflash_erase = 1; 208 | break; 209 | case 'n': 210 | require_protocol_v2 = 1; 211 | break; 212 | default: 213 | printusage(argv[0]); 214 | exit(0); 215 | break; 216 | 217 | } 218 | } 219 | 220 | /* Initialize libusb 221 | */ 222 | rc = libusb_init(NULL); 223 | if (rc < 0) { 224 | fprintf(stderr, "Error initializing libusb: %s\n", libusb_error_name(rc)); 225 | exit(-1); 226 | } 227 | 228 | /* Set debugging output to max level. 229 | */ 230 | libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO); 231 | 232 | /* Look for a specific device and open it. 233 | */ 234 | devh = libusb_open_device_with_vid_pid(NULL, VENDOR_ID, PRODUCT_ID); 235 | if (!devh) { 236 | fprintf(stderr, "Can't find any suitable USB device!\n"); 237 | goto out; 238 | } 239 | 240 | libusb_claim_interface(devh, 0); 241 | 242 | if(require_protocol_v2) 243 | { 244 | write_to_device(detect_chip_cmd_v2, sizeof(detect_chip_cmd_v2)); 245 | read_from_device(inbuffer, 6); //TODO: 其他支持 246 | if(require_exec || require_dataflash_erase || require_dataflash_write || require_dataflash_read) 247 | { 248 | printf("Those feature currently not supported"); 249 | exit(-1); 250 | } 251 | } 252 | else 253 | { 254 | write_to_device(detect_chip_cmd_v1, 63); 255 | read_from_device(inbuffer, 2); 256 | //hexdump(inbuffer, 2); 257 | printf("Libre CH551 Flasher 2018\n"); 258 | 259 | if(inbuffer[0] == 0x51) 260 | { 261 | printf("Detected device CH551\n"); 262 | device_flash_size = 10240; 263 | device_dataflash_size = 128; 264 | } 265 | else if(inbuffer[0] == 0x52) 266 | { 267 | printf("Detected device CH552\n"); 268 | device_flash_size = 16384; 269 | device_dataflash_size = 128; 270 | } 271 | else if(inbuffer[0] == 0x53) 272 | { 273 | printf("Detected device CH553\n"); 274 | device_flash_size = 10240; 275 | device_dataflash_size = 128; 276 | } 277 | else if(inbuffer[0] == 0x54) 278 | { 279 | printf("Detected device CH554\n"); 280 | device_flash_size = 14336; 281 | device_dataflash_size = 128; 282 | } 283 | else if(inbuffer[0] == 0x59) 284 | { 285 | printf("Detected device CH559\n"); 286 | device_flash_size = 61440; 287 | device_dataflash_size = 1024; 288 | } 289 | else 290 | { 291 | fprintf(stderr, "The chip id 0x%02X is currently not support in this program\n", inbuffer[0]); 292 | goto out; 293 | } 294 | printf("Device rom capacity %d, data flash capacity %d\n", 295 | device_flash_size, device_dataflash_size); 296 | 297 | } 298 | 299 | if(require_download) 300 | { 301 | fp = fopen(file_name, "rb"); 302 | if(!fp) 303 | { 304 | fprintf(stderr, "Can't open file '%s' !\n", file_name); 305 | exit(1); 306 | } 307 | 308 | fseek(fp, 0, SEEK_END); 309 | file_length = ftell(fp); 310 | file_buffer = malloc(file_length); 311 | 312 | if(file_length > device_flash_size) 313 | { 314 | fprintf(stderr, "File size exceeded device's capacity!\n"); 315 | exit(1); 316 | } 317 | 318 | if(file_buffer == 0) 319 | { 320 | fprintf(stderr, "Can't allocate memory!\n"); 321 | exit(1); 322 | } 323 | printf("Binary length %d\n", file_length); 324 | 325 | fseek(fp, 0, SEEK_SET); 326 | 327 | fread(file_buffer, 1, file_length, fp); 328 | 329 | fclose(fp); 330 | fp = 0; 331 | } 332 | 333 | if(require_protocol_v2) 334 | { 335 | key_input_v2(); 336 | } 337 | else 338 | { 339 | write_to_device(use_interface_cmd_v1, 2); 340 | read_from_device(inbuffer, 2); 341 | printf("Device bootloader version: %d.%d\n\n", inbuffer[0] >> 4, inbuffer[0] & 0xf); 342 | //hexdump(inbuffer, 2); 343 | 344 | write_to_device(key_input_cmd_v1, 6); /* Input a dummy key that let we doesn't need to 'encrypt' */ 345 | read_from_device(inbuffer, 2); 346 | //hexdump(inbuffer, 2); 347 | } 348 | 349 | if(require_erase || require_download) 350 | { 351 | printf("Now performing erase...\n"); 352 | if(require_protocol_v2) 353 | { 354 | write_to_device(erase_chip_cmd_v2, sizeof(erase_chip_cmd_v2)); 355 | read_from_device(inbuffer, 6); 356 | } 357 | else 358 | { 359 | for(i = 0; i < (device_flash_size / 1024); i++) 360 | { 361 | erase_page_cmd_v1[3] = i * 4; 362 | write_to_device(erase_page_cmd_v1, 4); 363 | read_from_device(inbuffer, 2); 364 | //hexdump(erase_page_cmd_v1, 4); 365 | if(inbuffer[0] != 0x00) 366 | { 367 | fprintf(stderr, "Erase failed!\n"); 368 | goto out; 369 | } 370 | } 371 | } 372 | printf("Erase done\n"); 373 | } 374 | 375 | if(require_download) 376 | { 377 | i = file_length; 378 | 379 | int curr_addr = 0; 380 | int pkt_length; 381 | 382 | printf("Writing Flash\n"); 383 | if(require_protocol_v2) 384 | { 385 | while(curr_addr < file_length) 386 | { 387 | pkt_length = i >= 0x38? 0x38: i; 388 | write_cmd_v2[1] = pkt_length + 5; 389 | write_cmd_v2[3] = curr_addr & 0xff; 390 | write_cmd_v2[4] = (curr_addr >> 8) & 0xff; 391 | write_cmd_v2[7] = i; 392 | 393 | memcpy(write_cmd_v2 + 8, file_buffer + curr_addr, pkt_length); 394 | int j; 395 | for(j = 0; j < 0x38; j++) 396 | { //该死的最后一个字节的XOR加密 397 | if(j % 8 == 7) 398 | write_cmd_v2[j] ^= lastkey; 399 | } 400 | write_to_device(write_cmd_v2, 64); 401 | read_from_device(inbuffer, 6); 402 | //hexdump(inbuffer, 2); 403 | 404 | //printf("Write to addr %d, pkt_length %d\n", curr_addr, pkt_length); 405 | 406 | curr_addr += pkt_length; 407 | i -= pkt_length; 408 | 409 | if(inbuffer[4] != 0x00) 410 | { 411 | fprintf(stderr, "Write failed!\n"); 412 | goto out; 413 | } 414 | 415 | } 416 | } 417 | else 418 | { 419 | while(curr_addr < file_length) 420 | { 421 | pkt_length = i >= 0x3c? 0x3c: i; 422 | write_cmd_v1[1] = pkt_length; 423 | write_cmd_v1[2] = curr_addr & 0xff; 424 | write_cmd_v1[3] = (curr_addr >> 8) & 0xff; 425 | 426 | memcpy(write_cmd_v1 + 4, file_buffer + curr_addr, pkt_length); 427 | write_to_device(write_cmd_v1, 64); 428 | read_from_device(inbuffer, 2); 429 | //hexdump(inbuffer, 2); 430 | 431 | //printf("Write to addr %d, pkt_length %d\n", curr_addr, pkt_length); 432 | 433 | curr_addr += pkt_length; 434 | i -= pkt_length; 435 | 436 | if(inbuffer[0] != 0x00) 437 | { 438 | fprintf(stderr, "Write failed!\n"); 439 | goto out; 440 | } 441 | 442 | } 443 | } 444 | 445 | printf("Write done\n"); 446 | 447 | i = file_length; 448 | 449 | curr_addr = 0; 450 | 451 | printf("Verifying Flash\n"); 452 | if(require_protocol_v2) 453 | { 454 | while(curr_addr < file_length) 455 | { 456 | pkt_length = i >= 0x38? 0x38: i; 457 | verify_cmd_v2[1] = pkt_length + 5; 458 | verify_cmd_v2[3] = curr_addr & 0xff; 459 | verify_cmd_v2[4] = (curr_addr >> 8) & 0xff; 460 | verify_cmd_v2[7] = i; 461 | 462 | memcpy(verify_cmd_v2 + 8, file_buffer + curr_addr, pkt_length); 463 | int j; 464 | for(j = 0; j < 0x38; j++) 465 | { //该死的最后一个字节的XOR加密 466 | if(j % 8 == 7) 467 | verify_cmd_v2[j] ^= lastkey; 468 | } 469 | write_to_device(write_cmd_v1, 64); 470 | read_from_device(inbuffer, 6); 471 | //hexdump(inbuffer, 2); 472 | 473 | //printf("Write to addr %d, pkt_length %d\n", curr_addr, pkt_length); 474 | 475 | curr_addr += pkt_length; 476 | i -= pkt_length; 477 | 478 | if(inbuffer[4] != 0x00) 479 | { 480 | fprintf(stderr, "Write failed!\n"); 481 | goto out; 482 | } 483 | 484 | } 485 | } 486 | else 487 | { 488 | while(curr_addr < file_length) 489 | { 490 | pkt_length = i >= 0x3c? 0x3c: i; 491 | verify_cmd_v1[1] = pkt_length; 492 | verify_cmd_v1[2] = curr_addr & 0xff; 493 | verify_cmd_v1[3] = (curr_addr >> 8) & 0xff; 494 | 495 | memcpy(verify_cmd_v1 + 4, file_buffer + curr_addr, pkt_length); 496 | //memset(verify_cmd_v1 + 4, 0xff, pkt_length); 497 | 498 | write_to_device(verify_cmd_v1, 64); 499 | read_from_device(inbuffer, 2); 500 | //hexdump(inbuffer, 2); 501 | 502 | //printf("Verify addr %d\n", curr_addr); 503 | 504 | curr_addr += pkt_length; 505 | i -= pkt_length; 506 | 507 | if(inbuffer[0] != 0x00) 508 | { 509 | fprintf(stderr, "Verify failed!\n"); 510 | goto out; 511 | } 512 | 513 | } 514 | } 515 | printf("Verify done\n"); 516 | } 517 | if(require_dataflash_read) 518 | { 519 | printf("Read from chip data flash\n"); 520 | 521 | fp = fopen(df_read_file_name, "wb+"); 522 | if(!fp) 523 | { 524 | fprintf(stderr, "Can't create read back file!\n"); 525 | goto out; 526 | } 527 | write_to_device(read_df_cmd_v1, 2); 528 | 529 | read_from_device(inbuffer, 64); 530 | fwrite(inbuffer, 1, 64, fp); 531 | read_from_device(inbuffer, 64); 532 | fwrite(inbuffer, 1, 64, fp); 533 | fclose(fp); 534 | fp = 0; 535 | 536 | printf("Read done\n"); 537 | 538 | } 539 | if(require_dataflash_erase || require_dataflash_write) 540 | { 541 | write_to_device(claim_device_cmd_v1, 4); 542 | read_from_device(inbuffer, 2); 543 | write_to_device(key_input_cmd_v1, 6); /* Input a dummy key that let we doesn't need to 'encrypt' */ 544 | read_from_device(inbuffer, 2); 545 | 546 | printf("Erasing device's data flash\n"); 547 | write_to_device(erase_df_cmd_v1, 4); /* Erase DF */ 548 | read_from_device(inbuffer, 2); 549 | 550 | if(inbuffer[0] != 0x00) 551 | { 552 | fprintf(stderr, "Erase data flash failed!\n"); 553 | goto out; 554 | } 555 | 556 | printf("Erase done\n"); 557 | } 558 | 559 | if(require_dataflash_write) 560 | { 561 | 562 | fp = fopen(df_write_file_name, "rb"); 563 | if(!fp) 564 | { 565 | fprintf(stderr, "Can't open data flash file '%s'!\n", df_write_file_name); 566 | goto out; 567 | } 568 | fseek(fp, 0, SEEK_END); 569 | file_length = ftell(fp); 570 | 571 | if(file_length > device_dataflash_size) 572 | { 573 | fprintf(stderr, "File size exceeded device's capacity!\n"); 574 | goto out; 575 | } 576 | 577 | if(file_buffer) free(file_buffer); 578 | file_buffer = malloc(file_length); 579 | 580 | if(file_buffer == 0) 581 | { 582 | fprintf(stderr, "Can't allocate memory!\n"); 583 | exit(1); 584 | } 585 | printf("Data flash Binary length %d\n", file_length); 586 | fseek(fp, 0, SEEK_SET); 587 | 588 | fread(file_buffer, 1, file_length, fp); 589 | fclose(fp); 590 | fp = 0; 591 | 592 | printf("Flashing device's data flash\n"); 593 | 594 | i = file_length; 595 | 596 | int curr_addr = 0; 597 | int pkt_length; 598 | 599 | while(curr_addr < file_length) 600 | { 601 | pkt_length = i >= 0x3c? 0x3c: i; 602 | write_df_cmd_v1[1] = pkt_length; 603 | write_df_cmd_v1[2] = curr_addr & 0xff; 604 | write_df_cmd_v1[3] = (curr_addr >> 8) & 0xff; 605 | 606 | memcpy(write_df_cmd_v1 + 4, file_buffer + curr_addr, pkt_length); 607 | write_to_device(write_df_cmd_v1, 64); 608 | read_from_device(inbuffer, 2); 609 | //hexdump(inbuffer, 2); 610 | 611 | //printf("Write to addr %d, pkt_length %d\n", curr_addr, pkt_length); 612 | 613 | curr_addr += pkt_length; 614 | i -= pkt_length; 615 | 616 | if(inbuffer[0] != 0x00) 617 | { 618 | fprintf(stderr, "Write data flash failed!\n"); 619 | goto out; 620 | } 621 | 622 | } 623 | printf("Write data flash done\n"); 624 | printf("Verifing data flash\n"); 625 | 626 | write_to_device(read_df_cmd_v1, 2); 627 | read_from_device(inbuffer, 64); 628 | if(memcmp(inbuffer, file_buffer, file_length > 64? 64: file_length) != 0) 629 | { 630 | fprintf(stderr, "Verify data flash failed!\n"); 631 | goto out; 632 | } 633 | read_from_device(inbuffer, 64); 634 | if(file_length > 64) 635 | { 636 | if(memcmp(inbuffer, file_buffer + 64, file_length > 64? file_length - 64: 0) != 0) 637 | { 638 | fprintf(stderr, "Verify data flash failed!\n"); 639 | goto out; 640 | } 641 | } 642 | printf("Verify data flash done\n"); 643 | } 644 | 645 | if(require_exec) 646 | { 647 | printf("Let target run, keep it at Hong Kong reporter speed!\n"); 648 | write_to_device(run_cmd_v1, 4); 649 | } 650 | 651 | printf("\nExcited! 0..0\n"); 652 | 653 | out: 654 | if(file_buffer) 655 | free(file_buffer); 656 | if(fp) 657 | fclose(fp); 658 | 659 | if (devh) 660 | { 661 | libusb_release_interface(devh, 0); 662 | libusb_close(devh); 663 | } 664 | libusb_exit(NULL); 665 | return rc; 666 | } 667 | 668 | 669 | -------------------------------------------------------------------------------- /msvc/getopt.h: -------------------------------------------------------------------------------- 1 | #ifndef __GETOPT_H__ 2 | /** 3 | * DISCLAIMER 4 | * This file is part of the mingw-w64 runtime package. 5 | * 6 | * The mingw-w64 runtime package and its code is distributed in the hope that it 7 | * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR 8 | * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to 9 | * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 10 | */ 11 | /* 12 | * Copyright (c) 2002 Todd C. Miller 13 | * 14 | * Permission to use, copy, modify, and distribute this software for any 15 | * purpose with or without fee is hereby granted, provided that the above 16 | * copyright notice and this permission notice appear in all copies. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 19 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 20 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 21 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 22 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 23 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 24 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 25 | * 26 | * Sponsored in part by the Defense Advanced Research Projects 27 | * Agency (DARPA) and Air Force Research Laboratory, Air Force 28 | * Materiel Command, USAF, under agreement number F39502-99-1-0512. 29 | */ 30 | /*- 31 | * Copyright (c) 2000 The NetBSD Foundation, Inc. 32 | * All rights reserved. 33 | * 34 | * This code is derived from software contributed to The NetBSD Foundation 35 | * by Dieter Baron and Thomas Klausner. 36 | * 37 | * Redistribution and use in source and binary forms, with or without 38 | * modification, are permitted provided that the following conditions 39 | * are met: 40 | * 1. Redistributions of source code must retain the above copyright 41 | * notice, this list of conditions and the following disclaimer. 42 | * 2. Redistributions in binary form must reproduce the above copyright 43 | * notice, this list of conditions and the following disclaimer in the 44 | * documentation and/or other materials provided with the distribution. 45 | * 46 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 47 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 48 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 49 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 50 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 51 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 52 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 53 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 54 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 55 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 56 | * POSSIBILITY OF SUCH DAMAGE. 57 | */ 58 | 59 | #pragma warning(disable:4996) 60 | 61 | #define __GETOPT_H__ 62 | 63 | /* All the headers include this file. */ 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | 72 | #ifdef __cplusplus 73 | extern "C" { 74 | #endif 75 | 76 | #define REPLACE_GETOPT /* use this getopt as the system getopt(3) */ 77 | 78 | #ifdef REPLACE_GETOPT 79 | int opterr = 1; /* if error message should be printed */ 80 | int optind = 1; /* index into parent argv vector */ 81 | int optopt = '?'; /* character checked for validity */ 82 | #undef optreset /* see getopt.h */ 83 | #define optreset __mingw_optreset 84 | int optreset; /* reset getopt */ 85 | char *optarg; /* argument associated with option */ 86 | #endif 87 | 88 | //extern int optind; /* index of first non-option in argv */ 89 | //extern int optopt; /* single option character, as parsed */ 90 | //extern int opterr; /* flag to enable built-in diagnostics... */ 91 | // /* (user may set to zero, to suppress) */ 92 | // 93 | //extern char *optarg; /* pointer to argument of current option */ 94 | 95 | #define PRINT_ERROR ((opterr) && (*options != ':')) 96 | 97 | #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ 98 | #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ 99 | #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ 100 | 101 | /* return values */ 102 | #define BADCH (int)'?' 103 | #define BADARG ((*options == ':') ? (int)':' : (int)'?') 104 | #define INORDER (int)1 105 | 106 | #ifndef __CYGWIN__ 107 | #define __progname __argv[0] 108 | #else 109 | extern char __declspec(dllimport) *__progname; 110 | #endif 111 | 112 | #ifdef __CYGWIN__ 113 | static char EMSG[] = ""; 114 | #else 115 | #define EMSG "" 116 | #endif 117 | 118 | static int getopt_internal(int, char * const *, const char *, 119 | const struct option *, int *, int); 120 | static int parse_long_options(char * const *, const char *, 121 | const struct option *, int *, int); 122 | static int gcd(int, int); 123 | static void permute_args(int, int, int, char * const *); 124 | 125 | static char *place = EMSG; /* option letter processing */ 126 | 127 | /* XXX: set optreset to 1 rather than these two */ 128 | static int nonopt_start = -1; /* first non option argument (for permute) */ 129 | static int nonopt_end = -1; /* first option after non options (for permute) */ 130 | 131 | /* Error messages */ 132 | static const char recargchar[] = "option requires an argument -- %c"; 133 | static const char recargstring[] = "option requires an argument -- %s"; 134 | static const char ambig[] = "ambiguous option -- %.*s"; 135 | static const char noarg[] = "option doesn't take an argument -- %.*s"; 136 | static const char illoptchar[] = "unknown option -- %c"; 137 | static const char illoptstring[] = "unknown option -- %s"; 138 | 139 | static void 140 | _vwarnx(const char *fmt,va_list ap) 141 | { 142 | (void)fprintf(stderr,"%s: ",__progname); 143 | if (fmt != NULL) 144 | (void)vfprintf(stderr,fmt,ap); 145 | (void)fprintf(stderr,"\n"); 146 | } 147 | 148 | static void 149 | warnx(const char *fmt,...) 150 | { 151 | va_list ap; 152 | va_start(ap,fmt); 153 | _vwarnx(fmt,ap); 154 | va_end(ap); 155 | } 156 | 157 | /* 158 | * Compute the greatest common divisor of a and b. 159 | */ 160 | static int 161 | gcd(int a, int b) 162 | { 163 | int c; 164 | 165 | c = a % b; 166 | while (c != 0) { 167 | a = b; 168 | b = c; 169 | c = a % b; 170 | } 171 | 172 | return (b); 173 | } 174 | 175 | /* 176 | * Exchange the block from nonopt_start to nonopt_end with the block 177 | * from nonopt_end to opt_end (keeping the same order of arguments 178 | * in each block). 179 | */ 180 | static void 181 | permute_args(int panonopt_start, int panonopt_end, int opt_end, 182 | char * const *nargv) 183 | { 184 | int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; 185 | char *swap; 186 | 187 | /* 188 | * compute lengths of blocks and number and size of cycles 189 | */ 190 | nnonopts = panonopt_end - panonopt_start; 191 | nopts = opt_end - panonopt_end; 192 | ncycle = gcd(nnonopts, nopts); 193 | cyclelen = (opt_end - panonopt_start) / ncycle; 194 | 195 | for (i = 0; i < ncycle; i++) { 196 | cstart = panonopt_end+i; 197 | pos = cstart; 198 | for (j = 0; j < cyclelen; j++) { 199 | if (pos >= panonopt_end) 200 | pos -= nnonopts; 201 | else 202 | pos += nopts; 203 | swap = nargv[pos]; 204 | /* LINTED const cast */ 205 | ((char **) nargv)[pos] = nargv[cstart]; 206 | /* LINTED const cast */ 207 | ((char **)nargv)[cstart] = swap; 208 | } 209 | } 210 | } 211 | 212 | #ifdef REPLACE_GETOPT 213 | /* 214 | * getopt -- 215 | * Parse argc/argv argument vector. 216 | * 217 | * [eventually this will replace the BSD getopt] 218 | */ 219 | int 220 | getopt(int nargc, char * const *nargv, const char *options) 221 | { 222 | 223 | /* 224 | * We don't pass FLAG_PERMUTE to getopt_internal() since 225 | * the BSD getopt(3) (unlike GNU) has never done this. 226 | * 227 | * Furthermore, since many privileged programs call getopt() 228 | * before dropping privileges it makes sense to keep things 229 | * as simple (and bug-free) as possible. 230 | */ 231 | return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); 232 | } 233 | #endif /* REPLACE_GETOPT */ 234 | 235 | //extern int getopt(int nargc, char * const *nargv, const char *options); 236 | 237 | #ifdef _BSD_SOURCE 238 | /* 239 | * BSD adds the non-standard `optreset' feature, for reinitialisation 240 | * of `getopt' parsing. We support this feature, for applications which 241 | * proclaim their BSD heritage, before including this header; however, 242 | * to maintain portability, developers are advised to avoid it. 243 | */ 244 | # define optreset __mingw_optreset 245 | extern int optreset; 246 | #endif 247 | #ifdef __cplusplus 248 | } 249 | #endif 250 | /* 251 | * POSIX requires the `getopt' API to be specified in `unistd.h'; 252 | * thus, `unistd.h' includes this header. However, we do not want 253 | * to expose the `getopt_long' or `getopt_long_only' APIs, when 254 | * included in this manner. Thus, close the standard __GETOPT_H__ 255 | * declarations block, and open an additional __GETOPT_LONG_H__ 256 | * specific block, only when *not* __UNISTD_H_SOURCED__, in which 257 | * to declare the extended API. 258 | */ 259 | #endif /* !defined(__GETOPT_H__) */ 260 | 261 | #if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) 262 | #define __GETOPT_LONG_H__ 263 | 264 | #ifdef __cplusplus 265 | extern "C" { 266 | #endif 267 | 268 | struct option /* specification for a long form option... */ 269 | { 270 | const char *name; /* option name, without leading hyphens */ 271 | int has_arg; /* does it take an argument? */ 272 | int *flag; /* where to save its status, or NULL */ 273 | int val; /* its associated status value */ 274 | }; 275 | 276 | enum /* permitted values for its `has_arg' field... */ 277 | { 278 | no_argument = 0, /* option never takes an argument */ 279 | required_argument, /* option always requires an argument */ 280 | optional_argument /* option may take an argument */ 281 | }; 282 | 283 | /* 284 | * parse_long_options -- 285 | * Parse long options in argc/argv argument vector. 286 | * Returns -1 if short_too is set and the option does not match long_options. 287 | */ 288 | static int 289 | parse_long_options(char * const *nargv, const char *options, 290 | const struct option *long_options, int *idx, int short_too) 291 | { 292 | char *current_argv, *has_equal; 293 | size_t current_argv_len; 294 | int i, ambiguous, match; 295 | 296 | #define IDENTICAL_INTERPRETATION(_x, _y) \ 297 | (long_options[(_x)].has_arg == long_options[(_y)].has_arg && \ 298 | long_options[(_x)].flag == long_options[(_y)].flag && \ 299 | long_options[(_x)].val == long_options[(_y)].val) 300 | 301 | current_argv = place; 302 | match = -1; 303 | ambiguous = 0; 304 | 305 | optind++; 306 | 307 | if ((has_equal = strchr(current_argv, '=')) != NULL) { 308 | /* argument found (--option=arg) */ 309 | current_argv_len = has_equal - current_argv; 310 | has_equal++; 311 | } else 312 | current_argv_len = strlen(current_argv); 313 | 314 | for (i = 0; long_options[i].name; i++) { 315 | /* find matching long option */ 316 | if (strncmp(current_argv, long_options[i].name, 317 | current_argv_len)) 318 | continue; 319 | 320 | if (strlen(long_options[i].name) == current_argv_len) { 321 | /* exact match */ 322 | match = i; 323 | ambiguous = 0; 324 | break; 325 | } 326 | /* 327 | * If this is a known short option, don't allow 328 | * a partial match of a single character. 329 | */ 330 | if (short_too && current_argv_len == 1) 331 | continue; 332 | 333 | if (match == -1) /* partial match */ 334 | match = i; 335 | else if (!IDENTICAL_INTERPRETATION(i, match)) 336 | ambiguous = 1; 337 | } 338 | if (ambiguous) { 339 | /* ambiguous abbreviation */ 340 | if (PRINT_ERROR) 341 | warnx(ambig, (int)current_argv_len, 342 | current_argv); 343 | optopt = 0; 344 | return (BADCH); 345 | } 346 | if (match != -1) { /* option found */ 347 | if (long_options[match].has_arg == no_argument 348 | && has_equal) { 349 | if (PRINT_ERROR) 350 | warnx(noarg, (int)current_argv_len, 351 | current_argv); 352 | /* 353 | * XXX: GNU sets optopt to val regardless of flag 354 | */ 355 | if (long_options[match].flag == NULL) 356 | optopt = long_options[match].val; 357 | else 358 | optopt = 0; 359 | return (BADARG); 360 | } 361 | if (long_options[match].has_arg == required_argument || 362 | long_options[match].has_arg == optional_argument) { 363 | if (has_equal) 364 | optarg = has_equal; 365 | else if (long_options[match].has_arg == 366 | required_argument) { 367 | /* 368 | * optional argument doesn't use next nargv 369 | */ 370 | optarg = nargv[optind++]; 371 | } 372 | } 373 | if ((long_options[match].has_arg == required_argument) 374 | && (optarg == NULL)) { 375 | /* 376 | * Missing argument; leading ':' indicates no error 377 | * should be generated. 378 | */ 379 | if (PRINT_ERROR) 380 | warnx(recargstring, 381 | current_argv); 382 | /* 383 | * XXX: GNU sets optopt to val regardless of flag 384 | */ 385 | if (long_options[match].flag == NULL) 386 | optopt = long_options[match].val; 387 | else 388 | optopt = 0; 389 | --optind; 390 | return (BADARG); 391 | } 392 | } else { /* unknown option */ 393 | if (short_too) { 394 | --optind; 395 | return (-1); 396 | } 397 | if (PRINT_ERROR) 398 | warnx(illoptstring, current_argv); 399 | optopt = 0; 400 | return (BADCH); 401 | } 402 | if (idx) 403 | *idx = match; 404 | if (long_options[match].flag) { 405 | *long_options[match].flag = long_options[match].val; 406 | return (0); 407 | } else 408 | return (long_options[match].val); 409 | #undef IDENTICAL_INTERPRETATION 410 | } 411 | 412 | /* 413 | * getopt_internal -- 414 | * Parse argc/argv argument vector. Called by user level routines. 415 | */ 416 | static int 417 | getopt_internal(int nargc, char * const *nargv, const char *options, 418 | const struct option *long_options, int *idx, int flags) 419 | { 420 | char *oli; /* option letter list index */ 421 | int optchar, short_too; 422 | static int posixly_correct = -1; 423 | 424 | if (options == NULL) 425 | return (-1); 426 | 427 | /* 428 | * XXX Some GNU programs (like cvs) set optind to 0 instead of 429 | * XXX using optreset. Work around this braindamage. 430 | */ 431 | if (optind == 0) 432 | optind = optreset = 1; 433 | 434 | /* 435 | * Disable GNU extensions if POSIXLY_CORRECT is set or options 436 | * string begins with a '+'. 437 | * 438 | * CV, 2009-12-14: Check POSIXLY_CORRECT anew if optind == 0 or 439 | * optreset != 0 for GNU compatibility. 440 | */ 441 | if (posixly_correct == -1 || optreset != 0) 442 | posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); 443 | if (*options == '-') 444 | flags |= FLAG_ALLARGS; 445 | else if (posixly_correct || *options == '+') 446 | flags &= ~FLAG_PERMUTE; 447 | if (*options == '+' || *options == '-') 448 | options++; 449 | 450 | optarg = NULL; 451 | if (optreset) 452 | nonopt_start = nonopt_end = -1; 453 | start: 454 | if (optreset || !*place) { /* update scanning pointer */ 455 | optreset = 0; 456 | if (optind >= nargc) { /* end of argument vector */ 457 | place = EMSG; 458 | if (nonopt_end != -1) { 459 | /* do permutation, if we have to */ 460 | permute_args(nonopt_start, nonopt_end, 461 | optind, nargv); 462 | optind -= nonopt_end - nonopt_start; 463 | } 464 | else if (nonopt_start != -1) { 465 | /* 466 | * If we skipped non-options, set optind 467 | * to the first of them. 468 | */ 469 | optind = nonopt_start; 470 | } 471 | nonopt_start = nonopt_end = -1; 472 | return (-1); 473 | } 474 | if (*(place = nargv[optind]) != '-' || 475 | (place[1] == '\0' && strchr(options, '-') == NULL)) { 476 | place = EMSG; /* found non-option */ 477 | if (flags & FLAG_ALLARGS) { 478 | /* 479 | * GNU extension: 480 | * return non-option as argument to option 1 481 | */ 482 | optarg = nargv[optind++]; 483 | return (INORDER); 484 | } 485 | if (!(flags & FLAG_PERMUTE)) { 486 | /* 487 | * If no permutation wanted, stop parsing 488 | * at first non-option. 489 | */ 490 | return (-1); 491 | } 492 | /* do permutation */ 493 | if (nonopt_start == -1) 494 | nonopt_start = optind; 495 | else if (nonopt_end != -1) { 496 | permute_args(nonopt_start, nonopt_end, 497 | optind, nargv); 498 | nonopt_start = optind - 499 | (nonopt_end - nonopt_start); 500 | nonopt_end = -1; 501 | } 502 | optind++; 503 | /* process next argument */ 504 | goto start; 505 | } 506 | if (nonopt_start != -1 && nonopt_end == -1) 507 | nonopt_end = optind; 508 | 509 | /* 510 | * If we have "-" do nothing, if "--" we are done. 511 | */ 512 | if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { 513 | optind++; 514 | place = EMSG; 515 | /* 516 | * We found an option (--), so if we skipped 517 | * non-options, we have to permute. 518 | */ 519 | if (nonopt_end != -1) { 520 | permute_args(nonopt_start, nonopt_end, 521 | optind, nargv); 522 | optind -= nonopt_end - nonopt_start; 523 | } 524 | nonopt_start = nonopt_end = -1; 525 | return (-1); 526 | } 527 | } 528 | 529 | /* 530 | * Check long options if: 531 | * 1) we were passed some 532 | * 2) the arg is not just "-" 533 | * 3) either the arg starts with -- we are getopt_long_only() 534 | */ 535 | if (long_options != NULL && place != nargv[optind] && 536 | (*place == '-' || (flags & FLAG_LONGONLY))) { 537 | short_too = 0; 538 | if (*place == '-') 539 | place++; /* --foo long option */ 540 | else if (*place != ':' && strchr(options, *place) != NULL) 541 | short_too = 1; /* could be short option too */ 542 | 543 | optchar = parse_long_options(nargv, options, long_options, 544 | idx, short_too); 545 | if (optchar != -1) { 546 | place = EMSG; 547 | return (optchar); 548 | } 549 | } 550 | 551 | if ((optchar = (int)*place++) == (int)':' || 552 | (optchar == (int)'-' && *place != '\0') || 553 | (oli = (char*)strchr(options, optchar)) == NULL) { 554 | /* 555 | * If the user specified "-" and '-' isn't listed in 556 | * options, return -1 (non-option) as per POSIX. 557 | * Otherwise, it is an unknown option character (or ':'). 558 | */ 559 | if (optchar == (int)'-' && *place == '\0') 560 | return (-1); 561 | if (!*place) 562 | ++optind; 563 | if (PRINT_ERROR) 564 | warnx(illoptchar, optchar); 565 | optopt = optchar; 566 | return (BADCH); 567 | } 568 | if (long_options != NULL && optchar == 'W' && oli[1] == ';') { 569 | /* -W long-option */ 570 | if (*place) /* no space */ 571 | /* NOTHING */; 572 | else if (++optind >= nargc) { /* no arg */ 573 | place = EMSG; 574 | if (PRINT_ERROR) 575 | warnx(recargchar, optchar); 576 | optopt = optchar; 577 | return (BADARG); 578 | } else /* white space */ 579 | place = nargv[optind]; 580 | optchar = parse_long_options(nargv, options, long_options, 581 | idx, 0); 582 | place = EMSG; 583 | return (optchar); 584 | } 585 | if (*++oli != ':') { /* doesn't take argument */ 586 | if (!*place) 587 | ++optind; 588 | } else { /* takes (optional) argument */ 589 | optarg = NULL; 590 | if (*place) /* no white space */ 591 | optarg = place; 592 | else if (oli[1] != ':') { /* arg not optional */ 593 | if (++optind >= nargc) { /* no arg */ 594 | place = EMSG; 595 | if (PRINT_ERROR) 596 | warnx(recargchar, optchar); 597 | optopt = optchar; 598 | return (BADARG); 599 | } else 600 | optarg = nargv[optind]; 601 | } 602 | place = EMSG; 603 | ++optind; 604 | } 605 | /* dump back option letter */ 606 | return (optchar); 607 | } 608 | 609 | /* 610 | * getopt_long -- 611 | * Parse argc/argv argument vector. 612 | */ 613 | int 614 | getopt_long(int nargc, char * const *nargv, const char *options, 615 | const struct option *long_options, int *idx) 616 | { 617 | 618 | return (getopt_internal(nargc, nargv, options, long_options, idx, 619 | FLAG_PERMUTE)); 620 | } 621 | 622 | /* 623 | * getopt_long_only -- 624 | * Parse argc/argv argument vector. 625 | */ 626 | int 627 | getopt_long_only(int nargc, char * const *nargv, const char *options, 628 | const struct option *long_options, int *idx) 629 | { 630 | 631 | return (getopt_internal(nargc, nargv, options, long_options, idx, 632 | FLAG_PERMUTE|FLAG_LONGONLY)); 633 | } 634 | 635 | //extern int getopt_long(int nargc, char * const *nargv, const char *options, 636 | // const struct option *long_options, int *idx); 637 | //extern int getopt_long_only(int nargc, char * const *nargv, const char *options, 638 | // const struct option *long_options, int *idx); 639 | /* 640 | * Previous MinGW implementation had... 641 | */ 642 | #ifndef HAVE_DECL_GETOPT 643 | /* 644 | * ...for the long form API only; keep this for compatibility. 645 | */ 646 | # define HAVE_DECL_GETOPT 1 647 | #endif 648 | 649 | #ifdef __cplusplus 650 | } 651 | #endif 652 | 653 | #endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ 654 | --------------------------------------------------------------------------------