├── _config.yml ├── .gitignore ├── TODO ├── elf ├── esptool_elf.c ├── esptool_elf.h ├── esptool_elf_object.h ├── esptool_elf_enums.h └── esptool_elf_object.c ├── test_failure_rate.sh ├── espcomm ├── delay.h ├── delay.c ├── espcomm_boards.h ├── espcomm.h ├── espcomm_boards.c └── espcomm.c ├── argparse ├── argparse_commcmd.h ├── argparse_elfcmd.h ├── argparse_binimagecmd.h ├── argparse.h ├── argparse_elfcmd.c ├── argparse_commcmd.c ├── argparse_binimagecmd.c └── argparse.c ├── serialport ├── serialport.h └── serialport.c ├── infohelper ├── infohelper.h └── infohelper.c ├── .travis.yml ├── main.c ├── Makefile ├── binimage ├── esptool_binimage.h └── esptool_binimage.c ├── README.md └── LICENSE /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | esptool 2 | esptool.exe 3 | build/ 4 | */*.o 5 | *.o 6 | *.zip 7 | *.tar.gz 8 | esptool-* 9 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - clean up the code, it's a real mess 2 | - better documentation 3 | - rework the info/error message stuff 4 | - refine functionality to up/download firmware/memory to/from the chip 5 | so that it can use the internally generated images if wanted 6 | - ... 7 | -------------------------------------------------------------------------------- /elf/esptool_elf.c: -------------------------------------------------------------------------------- 1 | #include "esptool_elf.h" 2 | #include "esptool_elf_enums.h" 3 | 4 | unsigned long elf_hash(const unsigned char *name) 5 | { 6 | unsigned long h = 0, g; 7 | 8 | while(*name) 9 | { 10 | h = (h << 4) + *name++; 11 | if((g = h & 0xF0000000)) 12 | { 13 | h ^= g >> 24; 14 | } 15 | h &= ~g; 16 | } 17 | return h; 18 | } 19 | -------------------------------------------------------------------------------- /test_failure_rate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # 4 | repeat=$1 5 | cmd="${@:2}" 6 | 7 | if [[ -z "$repeat" || -z "$cmd" ]]; then 8 | echo "Usage: test_error_rate.sh command [ args ... ]" 9 | echo "For example, to test uploading a binary to nodemcu board 200 times, run:" 10 | echo "./test_failure_rate.sh 200 ./esptool -cp /dev/tty.SLAB_USBtoUART -cb 921600 -cd nodemcu -cf some_test_file.bin" 11 | exit 1 12 | fi 13 | 14 | success=0 15 | fail=0 16 | 17 | for i in $(seq 1 $repeat); do 18 | echo "Run $i" 19 | if $cmd; then 20 | success=$(($success+1)) 21 | else 22 | fail=$(($fail+1)) 23 | fi 24 | done 25 | 26 | echo "Success: $success" 27 | echo "Fail: $fail" 28 | -------------------------------------------------------------------------------- /espcomm/delay.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** delay.h 5 | *** - cross-platform delay function 6 | *** 7 | *** Copyright (C) 2015 Ivan Grokhotkov 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | 26 | #ifndef DELAY_H 27 | #define DELAY_H 28 | 29 | void espcomm_delay_ms(int ms); 30 | 31 | #endif//DELAY_H 32 | -------------------------------------------------------------------------------- /argparse/argparse_commcmd.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** argparse_commcmd.h 5 | *** - include file for the comm-commands argument parser 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #ifndef ARGPARSE_COMMCMD_H 26 | #define ARGPARSE_COMMCMD_H 27 | 28 | int argparse_commcmd(int num_args, char **arg_ptr); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /argparse/argparse_elfcmd.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** argparse_elfcmd.h 5 | *** - include file for the ELF object commands argument parser 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #ifndef ARGPARSE_ELFCMD_H 26 | #define ARGPARSE_ELFCMD_H 27 | 28 | int argparse_elfcmd(int num_args, char **arg_ptr); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /argparse/argparse_binimagecmd.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** argparse_binimagecmd.h 5 | *** - include file for the flash image commands argument parser 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #ifndef ARGPARSE_BINIMAGECMD_H 26 | #define ARGPARSE_BINIMAGECMD_H 27 | 28 | int argparse_binimagecmd(int num_args, char **arg_ptr); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /espcomm/delay.c: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** delay.c 5 | *** - cross-platform delay function 6 | *** 7 | *** Copyright (C) 2015 Ivan Grokhotkov 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | 26 | #if defined(_WIN32) 27 | #include 28 | 29 | void espcomm_delay_ms(int ms) 30 | { 31 | Sleep(ms); 32 | } 33 | 34 | 35 | #else 36 | #include 37 | 38 | void espcomm_delay_ms(int ms) 39 | { 40 | usleep(ms * 1000); 41 | } 42 | 43 | 44 | #endif 45 | 46 | -------------------------------------------------------------------------------- /argparse/argparse.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** argparese.h 5 | *** - header file for argparse.c 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #ifndef ARGPARSE_H 26 | #define ARGPARSE_H 27 | 28 | int parse_arg(int num_args, char **arg_ptr); 29 | int argparse_elfcmd(int num_args, char **arg_ptr); 30 | int argparse_binimagecmd(int num_args, char **arg_ptr); 31 | int argparse_commcmd(int num_args, char **arg_ptr); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /espcomm/espcomm_boards.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** espcomm_boards.h 5 | *** - board-specific upload methods interface 6 | *** 7 | *** Copyright (C) 2015 Ivan Grokhotkov 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #ifndef ESPCOMM_BOARDS_H 26 | #define ESPCOMM_BOARDS_H 27 | 28 | struct espcomm_board_; 29 | typedef struct espcomm_board_ espcomm_board_t; 30 | 31 | espcomm_board_t* espcomm_board_by_name(const char* name); 32 | espcomm_board_t* espcomm_board_first(); 33 | espcomm_board_t* espcomm_board_next(espcomm_board_t* board); 34 | 35 | const char* espcomm_board_name(espcomm_board_t* board); 36 | void espcomm_board_reset_into_bootloader(espcomm_board_t* board); 37 | void espcomm_board_reset_into_app(espcomm_board_t* board); 38 | 39 | 40 | 41 | 42 | #endif//ESPCOMM_BOARDS_H 43 | -------------------------------------------------------------------------------- /serialport/serialport.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** serialport.h 5 | *** - include file for serialport.c 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | 26 | #ifndef SERIALPORT_H 27 | #define SERIALPORT_H 28 | 29 | int serialport_open(const char *dev, unsigned int baudrate); 30 | int serialport_close(void); 31 | void serialport_set_dtr(unsigned char val); 32 | void serialport_set_rts(unsigned char val); 33 | void serialport_send_break(); 34 | void serialport_set_timeout(unsigned int timeout); 35 | unsigned serialport_get_timeout(); 36 | void serialport_drain(void); 37 | void serialport_flush(void); 38 | unsigned serialport_read(unsigned char* data, unsigned int size); 39 | unsigned serialport_write(const unsigned char* data, unsigned int size); 40 | 41 | int serialport_send_slip(unsigned char *data, unsigned int size); 42 | int serialport_receive_slip(unsigned char *data, unsigned int size); 43 | int serialport_send_C0(void); 44 | int serialport_receive_C0(void); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /infohelper/infohelper.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** infohelper.h 5 | *** - defines and prototypes for a crude verbositiy-controllabe info output 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #ifndef INFOHELPER_H 26 | #define INFOHELPER_H 27 | 28 | 29 | /* 30 | ** set verbositiy level 31 | ** 0 = only error messages 32 | ** 1 = warnings 33 | ** 2 = information messages (default) 34 | ** 3 = debugging info 35 | ** 4 = extra debugging info 36 | */ 37 | void infohelper_set_infolevel(char lvl); 38 | 39 | /* 40 | ** increase verbositylevel by 1 41 | */ 42 | void infohelper_increase_infolevel(void); 43 | 44 | /* 45 | ** set verbosity level according to arguments given 46 | */ 47 | void infohelper_set_argverbosity(int num_args, char **arg_ptr); 48 | 49 | void infohelper_output(int loglevel, const char* format, ...); 50 | void infohelper_output_plain(int loglevel, const char* format, ...); 51 | 52 | #define LOGERR(...) infohelper_output(0, __VA_ARGS__) 53 | #define LOGWARN(...) infohelper_output(1, __VA_ARGS__) 54 | #define LOGINFO(...) infohelper_output(2, __VA_ARGS__) 55 | #define LOGDEBUG(...) infohelper_output(3, __VA_ARGS__) 56 | #define LOGVERBOSE(...) infohelper_output(4, __VA_ARGS__) 57 | 58 | #define INFO(...) infohelper_output_plain(0, __VA_ARGS__) 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | sudo: required 3 | services: 4 | - docker 5 | 6 | matrix: 7 | include: 8 | - env: 9 | - TARGET_OS=linux64 10 | - DOCKER_IMAGE=multiarch/crossbuild 11 | - CROSS_TRIPLE=x86_64-linux-gnu 12 | - BUILD_DIR=/workdir 13 | - env: 14 | - TARGET_OS=linux32 15 | # multiarch/crossbuild doesn't come with 32-bit compilers, use a different image 16 | - DOCKER_IMAGE=dockcross/linux-x86 17 | - CROSS_TRIPLE=i686-linux-gnu 18 | - BUILD_DIR=/work 19 | - env: 20 | - TARGET_OS=linux-armhf 21 | - DOCKER_IMAGE=multiarch/crossbuild 22 | - CROSS_TRIPLE=arm-linux-gnueabihf 23 | - BUILD_DIR=/workdir 24 | - env: 25 | - TARGET_OS=win32 26 | - DOCKER_IMAGE=multiarch/crossbuild 27 | - CROSS_TRIPLE=i686-w64-mingw32 28 | - BUILD_DIR=/workdir 29 | # multiarch/crossbuild doesn't come with 'zip', 30 | # so we build a tgz archive in the container, and re-package it later in the script. 31 | - EXTRA_ARGS='-e ARCHIVE=tar' 32 | - env: 33 | - TARGET_OS=osx 34 | - DOCKER_IMAGE=multiarch/crossbuild 35 | - CROSS_TRIPLE=x86_64-apple-darwin 36 | - BUILD_DIR=/workdir 37 | 38 | 39 | script: 40 | - export VER=$(git describe) 41 | - echo ${VER} 42 | 43 | - >- 44 | docker run --rm 45 | -v ${PWD}:${BUILD_DIR} 46 | -e TARGET_OS=${TARGET_OS} 47 | -e CROSS_TRIPLE=${CROSS_TRIPLE} 48 | ${EXTRA_ARGS} 49 | ${DOCKER_IMAGE} 50 | make clean dist 51 | 52 | # for windows, prepare zip archive 53 | - | 54 | if [ $TARGET_OS = "win32" ]; then 55 | rm -f esptool-${VER}-win32.tar.gz 56 | zip -r esptool-${VER}-win32.zip esptool-${VER}-win32/ 57 | fi 58 | 59 | # Diagnostics 60 | - file esptool-${VER}-${TARGET_OS}/* 61 | - ls -l esptool-${VER}-${TARGET_OS}/* 62 | 63 | # Prepare a file with size and sha256 64 | - export DIST_NAME=$(ls -1 esptool-${VER}-${TARGET_OS}.*) 65 | - DIST_SIZE=$(wc -c <${DIST_NAME} 2>/dev/null | tr -d ' ') 66 | - DIST_SHA256=$(shasum -a 256 ${DIST_NAME} | cut -d ' ' -f1) 67 | - echo ${DIST_NAME} ${DIST_SIZE} ${DIST_SHA256} >esptool-${VER}-${TARGET_OS}.sha256.txt 68 | 69 | notifications: 70 | email: 71 | recipients: 72 | - igrokhotkov@gmail.com 73 | on_success: change 74 | on_failure: change 75 | 76 | deploy: 77 | provider: releases 78 | skip_cleanup: true 79 | file_glob: true 80 | api_key: 81 | secure: "SsAnTtkjpHq2OQCnfZskdUY2R3lIRgl4iuVbKtMsGBS7YYZvpv8l+TdCcPXGaOXDRymJnWiNZs2/wJU1haVhwnDkp46Suo3m9OKQ40K4YQ6rpXBM5/f2ahdSKhNxR7lbVaAZnJWXO3PgGTM73F+d619oj5GGF/1SbCQ1thSRMQs=" 82 | file: esptool-$TRAVIS_TAG-$TARGET_OS.* 83 | on: 84 | repo: igrr/esptool-ck 85 | tags: true 86 | -------------------------------------------------------------------------------- /argparse/argparse_elfcmd.c: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** argparse_elfcmd.c 5 | *** - parsing of ELF file related commands 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #include "argparse_elfcmd.h" 26 | #include "esptool_elf.h" 27 | #include "esptool_elf_object.h" 28 | 29 | int argparse_elfcmd(int num_args, char **arg_ptr) 30 | { 31 | char *cur_cmd; 32 | 33 | if(arg_ptr[0][1] == 'e' && num_args--) 34 | { 35 | cur_cmd = &arg_ptr[0][2]; 36 | arg_ptr++; 37 | 38 | switch(*cur_cmd++) 39 | { 40 | // open ELF file 41 | case 'o': 42 | if(num_args < 1) 43 | { 44 | return 0; 45 | } 46 | else if(create_elf_object(arg_ptr[0])) 47 | { 48 | return 2; 49 | } 50 | break; 51 | 52 | // command to save a section from the ELF to a new file 53 | case 's': 54 | if(num_args < 2) 55 | { 56 | return 0; 57 | } 58 | else if(save_elf_section_bindata(arg_ptr[0], arg_ptr[1])) 59 | { 60 | return 3; 61 | } 62 | break; 63 | 64 | // close ELF file 65 | case 'c': 66 | if(close_elf_object()) 67 | { 68 | return 1; 69 | } 70 | break; 71 | 72 | default: 73 | return 0; 74 | break; 75 | } 76 | } 77 | /* Catch-all for errors returned by commands */ 78 | return -1; 79 | } 80 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** esptool main routine 5 | *** - parses the command line parameters and executes the given commands 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "infohelper.h" 31 | #include "argparse.h" 32 | #include "espcomm.h" 33 | #include "elf/esptool_elf.h" 34 | #include "elf/esptool_elf_object.h" 35 | #include "binimage/esptool_binimage.h" 36 | 37 | int main(int argc, char **argv) 38 | { 39 | int num_args; 40 | int num_args_parsed; 41 | char **arg_ptr; 42 | 43 | num_args = argc-1; 44 | arg_ptr = argv; 45 | arg_ptr++; 46 | 47 | if(argc < 2) 48 | { 49 | LOGERR("No arguments given. Use -h for help."); 50 | return 0; 51 | } 52 | infohelper_set_infolevel(1); 53 | infohelper_set_argverbosity(num_args, arg_ptr); 54 | 55 | LOGINFO("esptool v" VERSION " - (c) 2014 Ch. Klippel "); 56 | 57 | while(num_args) 58 | { 59 | num_args_parsed = parse_arg(num_args, arg_ptr); 60 | if (num_args_parsed == 0) 61 | { 62 | LOGERR("Invalid argument or value after %s (argument #%d)", arg_ptr[0], arg_ptr - argv + 1); 63 | goto EXITERROR; 64 | } 65 | else if (num_args_parsed < 0) 66 | { 67 | /* Command failed, error is printed by the command */ 68 | goto EXITERROR; 69 | } 70 | 71 | num_args -= num_args_parsed; 72 | arg_ptr += num_args_parsed; 73 | } 74 | 75 | if (espcomm_file_uploaded()) 76 | { 77 | espcomm_start_app(0); 78 | } 79 | close_elf_object(); 80 | binimage_write_close(16); 81 | return 0; 82 | 83 | EXITERROR: 84 | close_elf_object(); 85 | binimage_write_close(16); 86 | return 2; 87 | } 88 | -------------------------------------------------------------------------------- /infohelper/infohelper.c: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** infohelper.c 5 | *** - implementation of a crude verbosity-controllabe info system 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #include 26 | #include 27 | #include "infohelper.h" 28 | 29 | static char infolevel = 0; 30 | 31 | void infohelper_set_infolevel(char lvl) 32 | { 33 | infolevel = lvl; 34 | } 35 | 36 | void infohelper_increase_infolevel(void) 37 | { 38 | if(infolevel < 20) 39 | { 40 | infolevel++; 41 | } 42 | } 43 | 44 | void infohelper_set_argverbosity(int num_args, char **arg_ptr) 45 | { 46 | char *cur_arg; 47 | 48 | while(num_args--) 49 | { 50 | cur_arg = arg_ptr[num_args]; 51 | 52 | if(*cur_arg++ == '-') 53 | { 54 | if(*cur_arg == 'q') 55 | { 56 | infolevel = 0; 57 | return; 58 | } 59 | else while(*cur_arg++ == 'v') 60 | { 61 | infolevel++; 62 | } 63 | } 64 | } 65 | } 66 | 67 | void infohelper_output(int loglevel, const char* format, ...) 68 | { 69 | if (infolevel < loglevel) 70 | return; 71 | const char* log_level_names[] = {"error: ", "warning: ", "", "\t", "\t\t"}; 72 | const int log_level_names_count = sizeof(log_level_names) / sizeof(const char*); 73 | if (loglevel >= log_level_names_count) 74 | loglevel = log_level_names_count - 1; 75 | 76 | va_list v; 77 | printf("%s", log_level_names[loglevel]); 78 | va_start(v, format); 79 | vprintf(format, v); 80 | va_end(v); 81 | printf("\n"); 82 | } 83 | 84 | void infohelper_output_plain(int loglevel, const char* format, ...) 85 | { 86 | if (infolevel < loglevel) 87 | return; 88 | va_list v; 89 | va_start(v, format); 90 | vprintf(format, v); 91 | va_end(v); 92 | } 93 | -------------------------------------------------------------------------------- /espcomm/espcomm.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** espcomm.h 5 | *** - include file for espcomm.c 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #ifndef ESPCOMM_H 26 | #define ESPCOMM_H 27 | 28 | #include 29 | #include 30 | 31 | enum 32 | { 33 | CMD0 = 0x00, 34 | CMD1 = 0x01, 35 | FLASH_DOWNLOAD_BEGIN = 0x02, 36 | FLASH_DOWNLOAD_DATA = 0x03, 37 | FLASH_DOWNLOAD_DONE = 0x04, 38 | RAM_DOWNLOAD_BEGIN = 0x05, 39 | RAM_DOWNLOAD_END = 0x06, 40 | RAM_DOWNLOAD_DATA = 0x07, 41 | SYNC_FRAME = 0x08, 42 | WRITE_REGISTER = 0x09, 43 | READ_REGISTER = 0x0A, 44 | SET_FLASH_PARAMS = 0x0B, 45 | NO_COMMAND = 0xFF 46 | }; 47 | 48 | 49 | typedef struct 50 | { 51 | uint8_t direction; 52 | uint8_t command; 53 | uint16_t size; 54 | union 55 | { 56 | uint32_t checksum; 57 | uint32_t response; 58 | }; 59 | 60 | unsigned char *data; 61 | 62 | } bootloader_packet; 63 | 64 | #define BLOCKSIZE_FLASH 0x0400 65 | #define BLOCKSIZE_RAM 0x1800 66 | 67 | int espcomm_set_port(char *port); 68 | int espcomm_set_baudrate(const char *baudrate); 69 | int espcomm_set_address(const char *address); 70 | int espcomm_set_board(const char* name); 71 | int espcomm_set_chip(const char* name); 72 | 73 | int espcomm_open(void); 74 | void espcomm_close(void); 75 | 76 | bool espcomm_upload_mem_to_RAM(uint8_t* src, size_t size, int address, int entry); 77 | bool espcomm_upload_mem(uint8_t* src, size_t sizev, const char* source_name); 78 | bool espcomm_upload_file(const char *name); 79 | bool espcomm_upload_file_compressed(const char* name); 80 | int espcomm_file_uploaded(); 81 | int espcomm_start_app(int reboot); 82 | bool espcomm_reset(); 83 | bool espcomm_erase_region(const char* size); 84 | bool espcomm_erase_flash(); 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # OS detection. Not used in CI builds 2 | ifndef TARGET_OS 3 | ifeq ($(OS),Windows_NT) 4 | TARGET_OS := win32 5 | else 6 | UNAME_S := $(shell uname -s) 7 | ifeq ($(UNAME_S),Linux) 8 | UNAME_M := $(shell uname -m) 9 | ifeq ($(UNAME_M),x86_64) 10 | TARGET_OS := linux64 11 | endif 12 | ifeq ($(UNAME_M),i686) 13 | TARGET_OS := linux32 14 | endif 15 | ifeq ($(UNAME_M),armv6l) 16 | TARGET_OS := linux-armhf 17 | endif 18 | endif 19 | ifeq ($(UNAME_S),Darwin) 20 | TARGET_OS := osx 21 | endif 22 | ifeq ($(UNAME_S),FreeBSD) 23 | TARGET_OS := freebsd 24 | endif 25 | endif 26 | endif # TARGET_OS 27 | 28 | # OS-specific settings and build flags 29 | ifeq ($(TARGET_OS),win32) 30 | ARCHIVE ?= zip 31 | TARGET := esptool.exe 32 | TARGET_LDFLAGS = -Wl,-static -static-libgcc 33 | else 34 | ARCHIVE ?= tar 35 | TARGET := esptool 36 | endif 37 | 38 | ifeq ($(TARGET_OS),osx) 39 | TARGET_CFLAGS = -mmacosx-version-min=10.6 -arch i386 -arch x86_64 40 | TARGET_CXXFLAGS = -mmacosx-version-min=10.6 -arch i386 -arch x86_64 41 | TARGET_LDFLAGS = -mmacosx-version-min=10.6 -arch i386 -arch x86_64 42 | endif 43 | 44 | # Packaging into archive (for 'dist' target) 45 | ifeq ($(ARCHIVE), zip) 46 | ARCHIVE_CMD := zip -r 47 | ARCHIVE_EXTENSION := zip 48 | endif 49 | ifeq ($(ARCHIVE), tar) 50 | ARCHIVE_CMD := tar czf 51 | ARCHIVE_EXTENSION := tar.gz 52 | endif 53 | 54 | VERSION ?= $(shell git describe --always) 55 | 56 | MODULES := infohelper elf binimage argparse serialport espcomm 57 | 58 | OBJECTS := \ 59 | argparse/argparse.o \ 60 | argparse/argparse_binimagecmd.o \ 61 | argparse/argparse_commcmd.o \ 62 | argparse/argparse_elfcmd.o \ 63 | binimage/esptool_binimage.o \ 64 | elf/esptool_elf.o \ 65 | elf/esptool_elf_object.o \ 66 | espcomm/delay.o \ 67 | espcomm/espcomm.o \ 68 | espcomm/espcomm_boards.o \ 69 | infohelper/infohelper.o \ 70 | serialport/serialport.o \ 71 | main.o 72 | 73 | INCLUDES := $(addprefix -I,$(MODULES)) 74 | 75 | override CFLAGS := -std=gnu99 -Os -Wall $(TARGET_CFLAGS) $(CFLAGS) 76 | override CXXFLAGS := -std=c++11 -Os -Wall $(TARGET_CXXFLAGS) ($CXXFLAGS) 77 | override LDFLAGS := $(TARGET_LDFLAGS) $(LDFLAGS) 78 | override CPPFLAGS := $(INCLUDES) $(SDK_INCLUDES) -DVERSION=\"$(VERSION)\" $(CPPFLAGS) 79 | 80 | DIST_NAME := esptool-$(VERSION)-$(TARGET_OS) 81 | DIST_DIR := $(DIST_NAME) 82 | DIST_ARCHIVE := $(DIST_NAME).$(ARCHIVE_EXTENSION) 83 | 84 | 85 | all: $(TARGET) 86 | 87 | dist: $(DIST_ARCHIVE) 88 | 89 | $(DIST_ARCHIVE): $(TARGET) $(DIST_DIR) 90 | cp $(TARGET) $(DIST_DIR)/ 91 | $(ARCHIVE_CMD) $(DIST_ARCHIVE) $(DIST_DIR) 92 | 93 | $(TARGET): $(OBJECTS) 94 | $(CC) $^ -o $@ $(LDFLAGS) 95 | strip $(TARGET) 2>/dev/null \ 96 | || $(CROSS_TRIPLE)-strip $(TARGET) 97 | 98 | $(BUILD_DIR): 99 | @mkdir -p $@ 100 | 101 | $(DIST_DIR): 102 | @mkdir -p $@ 103 | 104 | clean: 105 | @rm -f $(OBJECTS) 106 | @rm -f $(TARGET) 107 | @rm -rf $(DIST_DIR) 108 | @rm -f $(DIST_ARCHIVE) 109 | 110 | .PHONY: all clean dist 111 | -------------------------------------------------------------------------------- /espcomm/espcomm_boards.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "espcomm_boards.h" 4 | #include "serialport.h" 5 | #include "delay.h" 6 | 7 | struct espcomm_board_ 8 | { 9 | const char* name; 10 | void (*reset_into_bootloader)(void); 11 | void (*reset_into_app)(void); 12 | }; 13 | 14 | static espcomm_board_t s_boards[]; 15 | static size_t s_boards_count; 16 | 17 | espcomm_board_t* espcomm_board_by_name(const char* name) 18 | { 19 | for (size_t i = 0; i < s_boards_count; ++i) 20 | { 21 | espcomm_board_t* board = s_boards + i; 22 | if (strcmp(board->name, name) == 0) 23 | return board; 24 | } 25 | return 0; 26 | } 27 | espcomm_board_t* espcomm_board_first() 28 | { 29 | return s_boards; 30 | } 31 | 32 | espcomm_board_t* espcomm_board_next(espcomm_board_t* board) 33 | { 34 | if (++board < s_boards + s_boards_count) 35 | return board; 36 | 37 | return 0; 38 | } 39 | 40 | const char* espcomm_board_name(espcomm_board_t* board) 41 | { 42 | return (board)?board->name:""; 43 | } 44 | 45 | void espcomm_board_reset_into_bootloader(espcomm_board_t* board) 46 | { 47 | if (board && board->reset_into_bootloader) 48 | (*board->reset_into_bootloader)(); 49 | } 50 | void espcomm_board_reset_into_app(espcomm_board_t* board) 51 | { 52 | if (board && board->reset_into_app) 53 | (*board->reset_into_app)(); 54 | } 55 | 56 | 57 | 58 | /// board definitions go below 59 | // 60 | // _rb = reset into bootloader 61 | // _ra = reset into app 62 | // 63 | // 64 | 65 | // "ck" board: dtr pulls down gpio0, rts pulls down reset 66 | // also supports reset with RC circuit triggered by break signal 67 | 68 | void board_ck_rb() 69 | { 70 | serialport_set_rts(1); 71 | serialport_set_dtr(1); 72 | serialport_send_break(); 73 | espcomm_delay_ms(5); 74 | serialport_set_rts(0); 75 | espcomm_delay_ms(250); // wait for break to finish 76 | serialport_set_dtr(0); 77 | } 78 | 79 | void board_ck_ra() 80 | { 81 | serialport_set_dtr(0); 82 | serialport_set_rts(1); 83 | espcomm_delay_ms(5); 84 | serialport_set_rts(0); 85 | } 86 | 87 | // WIFIO board, rev 2: TXD controls gpio0 via a pnp, and DTR controls rst via a capacitor 88 | 89 | void board_wifio_rb() 90 | { 91 | serialport_set_dtr(0); 92 | espcomm_delay_ms(5); 93 | serialport_set_dtr(1); 94 | espcomm_delay_ms(5); 95 | serialport_set_dtr(0); 96 | serialport_send_break(); 97 | } 98 | 99 | void board_wifio_ra() 100 | { 101 | serialport_set_dtr(0); 102 | espcomm_delay_ms(5); 103 | serialport_set_dtr(1); 104 | } 105 | 106 | void board_nodemcu_rb() 107 | { 108 | serialport_set_rts(1); 109 | serialport_set_dtr(0); 110 | espcomm_delay_ms(5); 111 | serialport_set_rts(0); 112 | serialport_set_dtr(1); 113 | espcomm_delay_ms(50); 114 | serialport_set_dtr(0); 115 | } 116 | 117 | void board_nodemcu_ra() 118 | { 119 | serialport_set_dtr(0); 120 | serialport_set_rts(1); 121 | espcomm_delay_ms(5); 122 | serialport_set_rts(0); 123 | } 124 | 125 | // dtrset board: DTR is set during serial communications 126 | 127 | void board_dtrset_rb() 128 | { 129 | serialport_set_dtr(1); // This makes dtr active by setting line voltage low 130 | } 131 | 132 | void board_dtrset_ra() 133 | { 134 | serialport_set_dtr(0); 135 | } 136 | 137 | /// list of all boards 138 | 139 | static espcomm_board_t s_boards[] = { 140 | { "none", 0, 0 }, 141 | { "ck", &board_ck_rb, &board_ck_ra }, 142 | { "wifio", &board_wifio_rb, &board_wifio_ra }, 143 | { "nodemcu", &board_nodemcu_rb, &board_nodemcu_ra }, 144 | { "dtrset", &board_dtrset_rb, &board_dtrset_ra }, 145 | }; 146 | 147 | static size_t s_boards_count = sizeof(s_boards) / sizeof(espcomm_board_t); 148 | -------------------------------------------------------------------------------- /elf/esptool_elf.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** esptool_elf.h 5 | *** - defines, structs and other stuff to access ELF files 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #ifndef ESPTOOL_ELF_H 26 | #define ESPTOOL_ELF_H 27 | 28 | #include 29 | 30 | #define Elf32_Addr uint32_t 31 | #define Elf32_Half uint16_t 32 | #define Elf32_Off uint32_t 33 | #define Elf32_Sword int32_t 34 | #define Elf32_Word uint32_t 35 | 36 | #define ELF32_ST_BIND(i) ((i)>>4) 37 | #define ELF32_ST_TYPE(i) ((i)&0x0F) 38 | #define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0x0F)) 39 | 40 | #define ELF32_R_SYM(i) ((i)>>8) 41 | #define ELF32_R_TYPE(i) ((unsigned char)(i)) 42 | #define ELF32_R_INFO(s,t) ((s)<<8)+(unsigned char)(t)) 43 | 44 | #define SIZE_EI_NIDENT 16 45 | 46 | typedef struct { 47 | unsigned char e_ident[SIZE_EI_NIDENT]; 48 | Elf32_Half e_type; 49 | Elf32_Half e_machine; 50 | Elf32_Word e_version; 51 | Elf32_Addr e_entry; 52 | Elf32_Off e_phoff; 53 | Elf32_Off e_shoff; 54 | Elf32_Word e_flags; 55 | Elf32_Half e_ehsize; 56 | Elf32_Half e_phentsize; 57 | Elf32_Half e_phnum; 58 | Elf32_Half e_shentsize; 59 | Elf32_Half e_shnum; 60 | Elf32_Half e_shstrndx; 61 | } Elf32_Ehdr; 62 | 63 | typedef struct { 64 | Elf32_Word sh_name; 65 | Elf32_Word sh_type; 66 | Elf32_Word sh_flags; 67 | Elf32_Addr sh_addr; 68 | Elf32_Off sh_offset; 69 | Elf32_Word sh_size; 70 | Elf32_Word sh_link; 71 | Elf32_Word sh_info; 72 | Elf32_Word sh_addralign; 73 | Elf32_Word sh_entsize; 74 | } Elf32_Shdr; 75 | 76 | typedef struct { 77 | Elf32_Word st_name; 78 | Elf32_Addr st_value; 79 | Elf32_Word st_size; 80 | unsigned char st_info; 81 | unsigned char st_other; 82 | Elf32_Half st_shndx; 83 | } Elf32_Sym; 84 | 85 | typedef struct { 86 | Elf32_Addr r_offset; 87 | Elf32_Word r_info; 88 | } Elf32_Rel; 89 | 90 | typedef struct { 91 | Elf32_Addr r_offset; 92 | Elf32_Word r_info; 93 | Elf32_Sword r_addend; 94 | } Elf32_Rela; 95 | 96 | typedef struct { 97 | Elf32_Word p_type; 98 | Elf32_Off p_offset; 99 | Elf32_Addr p_vaddr; 100 | Elf32_Addr p_paddr; 101 | Elf32_Word p_filesz; 102 | Elf32_Word p_memsz; 103 | Elf32_Word p_flags; 104 | Elf32_Word p_align; 105 | } Elf32_Phdr; 106 | 107 | typedef struct { 108 | Elf32_Sword d_tag; 109 | union { 110 | Elf32_Word d_val; 111 | Elf32_Addr d_ptr; 112 | } d_un; 113 | } Elf32_Dyn; 114 | 115 | 116 | unsigned long elf_hash(const unsigned char *name); 117 | 118 | #endif -------------------------------------------------------------------------------- /argparse/argparse_commcmd.c: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** argparse_commcmd.c 5 | *** - parsing of comms related commands (flash upload, etc) 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #include 26 | #include 27 | #include 28 | #include "infohelper.h" 29 | #include "esptool_elf.h" 30 | #include "esptool_elf_object.h" 31 | #include "esptool_binimage.h" 32 | #include "espcomm.h" 33 | 34 | int argparse_commcmd(int num_args, char **arg_ptr) 35 | { 36 | char *cur_cmd; 37 | 38 | if(arg_ptr[0][1] == 'c' && num_args--) 39 | { 40 | cur_cmd = &arg_ptr[0][2]; 41 | arg_ptr++; 42 | 43 | switch(*cur_cmd++) 44 | { 45 | case 'p': 46 | if(num_args < 1) 47 | { 48 | return 0; 49 | } 50 | if(espcomm_set_port(arg_ptr[0])) 51 | { 52 | return 2; 53 | } 54 | break; 55 | 56 | case 'b': 57 | if(num_args < 1) 58 | { 59 | return 0; 60 | } 61 | if(espcomm_set_baudrate(arg_ptr[0])) 62 | { 63 | return 2; 64 | } 65 | break; 66 | 67 | case 'a': 68 | if(num_args < 1) 69 | { 70 | return 0; 71 | } 72 | if(espcomm_set_address(arg_ptr[0])) 73 | { 74 | return 2; 75 | } 76 | break; 77 | 78 | case 'f': 79 | if(num_args < 1) 80 | { 81 | return 0; 82 | } 83 | if(espcomm_upload_file(arg_ptr[0])) 84 | { 85 | return 2; 86 | } 87 | break; 88 | 89 | case 'z': 90 | if (num_args < 1) 91 | { 92 | return 0; 93 | } 94 | if (espcomm_erase_region(arg_ptr[0])) 95 | { 96 | return 2; 97 | } 98 | break; 99 | 100 | case 'd': 101 | if (num_args < 1) 102 | { 103 | return 0; 104 | } 105 | if (espcomm_set_board(arg_ptr[0])) 106 | { 107 | return 2; 108 | } 109 | break; 110 | 111 | case 'e': 112 | if (espcomm_erase_flash()) 113 | { 114 | return 1; 115 | } 116 | break; 117 | 118 | case 'r': 119 | if (espcomm_reset()) 120 | { 121 | return 1; 122 | } 123 | break; 124 | 125 | default: 126 | return 0; 127 | break; 128 | } 129 | } 130 | /* Catch-all for errors returned by commands */ 131 | return -1; 132 | } 133 | -------------------------------------------------------------------------------- /elf/esptool_elf_object.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** esptool_elf_object.h 5 | *** - defines and prototypes for accessing ELF object/executable files 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #ifndef ESPTOOL_ELF_OBJECT_H 26 | #define ESPTOOL_ELF_OBJECT_H 27 | 28 | #include 29 | #include 30 | 31 | /* 32 | ** structs used to hold a local ELF cache object of the informations 33 | ** retrieved from the firmware ELF file 34 | */ 35 | 36 | /* 37 | ** struct holding the information of a given section according to 38 | ** what is found in the ELF file 39 | */ 40 | typedef struct { 41 | const char *name; 42 | Elf32_Word offset; 43 | Elf32_Addr address; 44 | Elf32_Word size; 45 | } ELF_section; 46 | 47 | /* 48 | ** struct defining the local ELF cache object and whatever sections it has 49 | */ 50 | typedef struct { 51 | FILE *e_file; 52 | Elf32_Ehdr header; 53 | Elf32_Shdr section; 54 | ELF_section *sections; 55 | char *strings; 56 | } ELF_Object; 57 | 58 | 59 | 60 | /* 61 | ** creates a local ELF cache object 62 | ** filename: the name of the ELF file on disk 63 | */ 64 | int create_elf_object(const char *filename); 65 | 66 | /* 67 | ** cleanup and release allocated memory for the ELF cahce object 68 | ** also closes the the ELF file on disk 69 | */ 70 | int close_elf_object(void); 71 | 72 | /* 73 | ** list of all section information that is in the ELF cache object 74 | */ 75 | void list_elf_sections(void); 76 | 77 | /* 78 | ** print the information of a given section header in the ELF cache object 79 | ** secnum: the index position of the section header to query 80 | */ 81 | void print_elf_section_info( Elf32_Half secnum ); 82 | 83 | /* 84 | ** return the number of section header stored in the ELF cache object 85 | */ 86 | int get_elf_num_sections(void); 87 | 88 | /* 89 | ** retrieve the index position of a section, searched for by the sections name 90 | ** secname: the neame of the section to look up 91 | */ 92 | int get_elf_secnum_by_name(const char *secname); 93 | 94 | /* 95 | ** retrieve the binary data of a section 96 | ** allocates the memory required for this and returns a pointer to that byte array 97 | ** secnum: index number of the section from which the binary data should be retrieved 98 | ** pad_to: minimum blocksize in-powers-of-two to pad the resulting array to 99 | */ 100 | unsigned char* get_elf_section_bindata(Elf32_Half secnum, uint32_t pad_to); 101 | 102 | /* 103 | ** dump the binary data of a section into a file on disk 104 | ** secname: the name of the section to read and write out 105 | ** fname: the name of the file to write to 106 | */ 107 | int save_elf_section_bindata(const char *secname, const char *fname); 108 | 109 | /* 110 | ** retrieve the size of the binary data for a section 111 | ** secnum: index position of the section 112 | */ 113 | Elf32_Word get_elf_section_size(Elf32_Half secnum); 114 | 115 | /* 116 | ** retrieve the memory address as specified in the ELF cache object of the binary data for a section 117 | ** secnum: index position of the section 118 | */ 119 | Elf32_Word get_elf_section_addr(Elf32_Half secnum); 120 | 121 | /* 122 | ** retrieve the code entry point of the ELF file 123 | */ 124 | Elf32_Word get_elf_entry(void); 125 | 126 | /* 127 | ** retrieve the name of a section 128 | ** secnum: index position of the section 129 | ** returns a pointer to a string representing the name 130 | */ 131 | const char* get_elf_section_name(Elf32_Half secnum); 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /binimage/esptool_binimage.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** esptool_binimage.h 5 | *** - defines and prototypes for handling firmware files for the ESP8266 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #ifndef ESPTOOL_BINIMAGE_H 26 | #define ESPTOOL_BINIMAGE_H 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | /* 33 | ** structs used to build and maintain internal representation 34 | ** of the binary firmware image 35 | */ 36 | 37 | /* 38 | ** structure holding a given chunk of binary data 39 | */ 40 | 41 | typedef struct { 42 | uint32_t address; 43 | uint32_t size; 44 | unsigned char *data; 45 | } binary_segment; 46 | 47 | /* 48 | ** structure specifying the binary firmware image 49 | ** also stores the list of chunks used 50 | */ 51 | 52 | typedef struct { 53 | unsigned char magic; 54 | unsigned char num_segments; 55 | 56 | /* SPI Flash Interface (0 = QIO, 1 = QOUT, 2 = DIO, 0x3 = DOUT) */ 57 | unsigned char flash_mode; 58 | 59 | /* High four bits: 0 = 512K, 1 = 256K, 2 = 1M, 3 = 2M, 4 = 4M, 8 = 8M, 9 = 16M 60 | Low four bits: 0 = 40MHz, 1= 26MHz, 2 = 20MHz, 0xf = 80MHz */ 61 | unsigned char flash_size_freq; 62 | 63 | uint32_t entry; 64 | FILE *image_file; 65 | binary_segment *segments; 66 | } bin_image; 67 | 68 | #define FLASH_MODE_QIO 0 69 | #define FLASH_MODE_QOUT 1 70 | #define FLASH_MODE_DIO 2 71 | #define FLASH_MODE_DOUT 3 72 | 73 | #define FLASH_SIZE_512K 0 << 4 74 | #define FLASH_SIZE_256K 1 << 4 75 | #define FLASH_SIZE_1M 2 << 4 76 | #define FLASH_SIZE_2M 3 << 4 77 | #define FLASH_SIZE_4M 4 << 4 78 | #define FLASH_SIZE_8M 8 << 4 79 | #define FLASH_SIZE_16M 9 << 4 80 | 81 | // flash frequency in MHz 82 | #define FLASH_FREQ_40 0x0 83 | #define FLASH_FREQ_26 0x1 84 | #define FLASH_FREQ_20 0x2 85 | #define FLASH_FREQ_80 0xf 86 | 87 | /* 88 | ** function prototypes 89 | */ 90 | 91 | /* 92 | ** initializes the internal firmware image representation 93 | ** fname: the file name to which the image will finally be saved 94 | ** entry: the code entry point address 95 | ** returns 1 on success, 0 on failure 96 | */ 97 | int binimage_prepare(const char *fname, uint32_t entry); 98 | 99 | /* 100 | ** specify a new code entry address 101 | */ 102 | void bimage_set_entry(uint32_t entry); 103 | 104 | /* 105 | ** write the binary firmware image to disk 106 | ** padsize: specifies to what power-of-two blocksize the image needs to be padded 107 | ** returns 1 on success, 0 on failure 108 | */ 109 | int binimage_write_close(uint32_t padsize); 110 | 111 | 112 | int binimage_write_padto(uint32_t padsize, uint32_t address); 113 | 114 | 115 | 116 | /* 117 | ** add a new segment to the firmware image 118 | ** address: specifies the load address of the given segment 119 | ** size: specifies the size of the binary data segment in bytes 120 | ** data: a pointer to an array of bytes containing the binary segment data 121 | ** returns 1 on success, 0 on failure 122 | */ 123 | int binimage_add_segment(uint32_t address, uint32_t size, unsigned char *data); 124 | 125 | 126 | /* 127 | ** update the image header which specifies flash chip configuration 128 | ** mode: one of "qio", "qout", "dio", "dout" (case-insensitive) 129 | ** size: one of "512K", "256K", "1M", "2M", "4M" (case-insensitive) 130 | ** freq: one of "40", "26", "20", "80" 131 | ** if these methods are not called, the binary image will use the following parameters: 132 | ** QIO, 512K, 40MHz 133 | ** return 1 on success, 0 on failure 134 | */ 135 | int binimage_set_flash_mode(const char* mode); 136 | int binimage_set_flash_size(const char* size); 137 | int binimage_set_flash_freq(const char* freq); 138 | 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Esptool** is a tool to create firmware files for the ESP8266 chip and flash the firmware to the chip over serial port. Esptool runs on Windows, Linux and Mac OS X. 2 | 3 | Esptool reads the compiled program in ELF format, extracts code and data sections, and either dumps a section to a file or assembles the firmware file from several segments. Esptool also communicates with the ESP8266 bootloader to upload firmware files to flash. Esptool can automatically put the board into UART bootloader mode using a variety of methods. 4 | 5 | Build status 6 | ------------ 7 | [![Build status](http://img.shields.io/travis/igrr/esptool-ck.svg)](https://travis-ci.org/igrr/esptool-ck) 8 | 9 | 10 | Usage 11 | ----- 12 | ``` 13 | esptool 14 | ``` 15 | 16 | The program interprets the arguments given on the command line, and in the order they are given. 17 | The following commands are currently available: 18 | 19 | Argument | Description 20 | ---------|------------- 21 | ```-eo ``` | Open an ELF object file, parse it and cache some of the information found therein. Works only if there is no ELF file currently opened. 22 | ```-es
``` | Read the given section from the ELF file and make a raw dump into the specified file. 23 | ```-ec``` | Close the currently opened ELF file 24 | ```-bo ```| Prepare a firmware file in the format that is understood by the ESP chip. Works only if an ELF file is opened, and if no firmware file is prepared yet. Upon -bo the tool will start out with an empty image where only the main header is set up. The result of the operations done on the firmware image is saved when the it is finally closed using -bc command. 25 | ```-bm ``` | Set the flash chip interface mode. Default is QIO. This parameter is stored in the binary image header, along with the flash size and flash frequency. The ROM bootloader in the ESP8266 uses the value of these parameters in order to know how to talk to the flash chip. 26 | ```-bz <512K/256K/1M/2M/4M/8M/16M/32M>``` | Set the flash chip size. Default is 512K. 27 | ```-bf <40/26/20/80>``` | Set the flash chip frequency, in MHz. Default is 40M. 28 | ```-bs
``` | Read the specified section from the ELF file and append it to the firmware image. Sections will appear in the firmware image in the exact same order as the -bs commands are executed. 29 | ```-bp ``` | Finalize the firmware image, padding it with `0xaa` value until it is at least `` bytes long. Unlike `-bc`, this doesn't close the file. This option can be used to combine bootloader with the rest of the application 30 | ```-br ``` | Pad all the following sections to multiples of ``. Default is 4 bytes. This option can be used to place sections on specific boundaries, e.g. 4k or 64k. 31 | ```-bc``` | Close the firmware image and save the result as file to disk. 32 | ```-v``` | Increase verbosity level of the tool. Add more v's to increase it even more, e.g. -vv, -vvv. 33 | ```-q``` | Disable most of the output. 34 | ```-cp ``` | Select the serial port device to use for communicating with the ESP. Default is /dev/ttyUSB0 on Linux, COM1 on Windows, /dev/tty.usbserial on Mac OS X. 35 | ```-cd ``` | Select the reset method to use for resetting the board. Currently supported methods are listed below. 36 | ```-cb ``` | Select the baudrate to use, default is 115200. 37 | ```-ca
``` | Address in flash memory to upload the data to. This address is interpreted as hexadecimal. Default is 0x00000000. 38 | ```-cf ``` | Upload the file to flash. Parameters that set the port, baud rate, and address must precede the -cf command. 39 | ```-cp ``` | Pad last written section of firmware image to the given size, in bytes. 40 | ```-cz ``` | Erase `size` bytes of flash starting from address set using `-ca` flag. Erase region boundaries must be aligned to 4kB. 41 | ```-ce``` | Erase flash 42 | ```-cr``` | Reset chip into app using the selected reset method 43 | 44 | Supported boards 45 | ---------------- 46 | 47 | Name | Description 48 | -----------|------------- 49 | none | No DTR/RTS manipulation 50 | ck | RTS controls RESET or CH_PD, DTR controls GPIO0 51 | wifio | TXD controls GPIO0 via PNP transistor and DTR controls RESET via a capacitor 52 | nodemcu | GPIO0 and RESET controlled using two NPN transistors as in [NodeMCU devkit](https://raw.githubusercontent.com/nodemcu/nodemcu-devkit/master/Documents/NODEMCU_DEVKIT_SCH.png). 53 | dtrset | DTR is set during serial communications 54 | 55 | Examples 56 | -------- 57 | 58 | ##### Create firmware files from the ELF output 59 | Input: ```app.elf```, output: ```app_00000.bin```, ```app_40000.bin```. 60 | Note the option for 4M flash size. 61 | ``` 62 | esptool -bz 4M -eo app.elf -bo app_00000.bin -bs .text -bs .data -bs .rodata -bc -ec -eo app.elf -es .irom0.text app_40000.bin -ec 63 | ``` 64 | 65 | ##### Upload the firmware to the board connected to COM5 port at 115200 baud, using manual reset method. 66 | ``` 67 | esptool -cp COM5 -cd none -cb 115200 -ca 0x00000 -cf 00000.bin -ca 0x40000 -cf 40000.bin 68 | ``` 69 | or, equivalent: 70 | ``` 71 | esptool -cp COM5 -cf 00000.bin -ca 0x40000 -cf 40000.bin 72 | ``` 73 | 74 | ##### Erase flash on a NodeMCU board 75 | ``` 76 | esptool -cp /dev/ttyUSB0 -cd nodemcu -ce 77 | ``` 78 | 79 | License 80 | ------- 81 | Copyright (C) 2014 Christian Klippel . 82 | 83 | This code is licensed under GPL v2. 84 | -------------------------------------------------------------------------------- /argparse/argparse_binimagecmd.c: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** argparse_binimagecmd.c 5 | *** - parsing of command related to binary flash image functions 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #include 26 | #include 27 | #include 28 | #include "infohelper.h" 29 | #include "esptool_elf.h" 30 | #include "esptool_elf_object.h" 31 | #include "esptool_binimage.h" 32 | 33 | static unsigned section_pad_size = 4; 34 | 35 | static int argparse_binimagecmd_add_segment(const char *sname, uint32_t padsize) 36 | { 37 | uint32_t snum; 38 | uint32_t addr; 39 | uint32_t size; 40 | uint32_t pad; 41 | 42 | snum = get_elf_secnum_by_name(sname); 43 | addr = get_elf_section_addr(snum); 44 | size = get_elf_section_size(snum); 45 | if(snum) 46 | { 47 | print_elf_section_info(snum); 48 | pad = get_elf_section_size(snum); 49 | padsize--; 50 | 51 | while(pad & padsize) 52 | { 53 | pad++; 54 | } 55 | 56 | if(pad > size) 57 | { 58 | binimage_add_segment(get_elf_section_addr(snum), pad, get_elf_section_bindata(snum, pad)); 59 | LOGINFO("added section %s at 0x%08X size 0x%08X with padding 0x%08X", get_elf_section_name(snum), addr, size, pad-size); 60 | } 61 | else 62 | { 63 | binimage_add_segment(get_elf_section_addr(snum), size, get_elf_section_bindata(snum, size)); 64 | LOGINFO("added section %s at 0x%08X size 0x%08X", get_elf_section_name(snum), addr, size); 65 | } 66 | } 67 | 68 | return snum; 69 | } 70 | 71 | int argparse_binimagecmd(int num_args, char **arg_ptr) 72 | { 73 | char *cur_cmd; 74 | uint32_t addr; 75 | if(arg_ptr[0][1] == 'b' && num_args--) 76 | { 77 | cur_cmd = &arg_ptr[0][2]; 78 | arg_ptr++; 79 | 80 | switch(*cur_cmd++) 81 | { 82 | case 'o': 83 | if(num_args < 1) 84 | { 85 | return 0; 86 | } 87 | if(binimage_prepare(arg_ptr[0], get_elf_entry())) 88 | { 89 | return 2; 90 | } 91 | break; 92 | 93 | case 's': 94 | if(num_args < 1) 95 | { 96 | return 0; 97 | } 98 | if(argparse_binimagecmd_add_segment(arg_ptr[0], section_pad_size)) 99 | { 100 | bimage_set_entry(get_elf_entry()); 101 | return 2; 102 | } 103 | break; 104 | 105 | case 'c': 106 | if(binimage_write_close(16)) 107 | { 108 | return 1; 109 | } 110 | break; 111 | 112 | case 'p': 113 | if(num_args < 1) 114 | { 115 | return 0; 116 | } 117 | addr = (unsigned) atoi(arg_ptr[0]); 118 | if(binimage_write_padto(16, addr)) 119 | { 120 | return 2; 121 | } 122 | break; 123 | 124 | case 'r': 125 | if(num_args < 1) 126 | { 127 | return 0; 128 | } 129 | section_pad_size = (unsigned) atoi(arg_ptr[0]); 130 | return 2; 131 | 132 | case 'm': 133 | if (num_args < 1) 134 | { 135 | return 0; 136 | } 137 | if (binimage_set_flash_mode(arg_ptr[0])) 138 | { 139 | return 2; 140 | } 141 | break; 142 | 143 | case 'z': 144 | if (num_args < 1) 145 | { 146 | return 0; 147 | } 148 | if (binimage_set_flash_size(arg_ptr[0])) 149 | { 150 | return 2; 151 | } 152 | break; 153 | 154 | case 'f': 155 | if (num_args < 1) 156 | { 157 | return 0; 158 | } 159 | if (binimage_set_flash_freq(arg_ptr[0])) 160 | { 161 | return 2; 162 | } 163 | break; 164 | 165 | default: 166 | return 0; 167 | break; 168 | } 169 | } 170 | /* Catch-all for errors returned by commands */ 171 | return -1; 172 | } 173 | -------------------------------------------------------------------------------- /elf/esptool_elf_enums.h: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** esptool_elf_enums.h 5 | *** - various enumerations that appear in ELF formatted files 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #ifndef ESPTOOL_ELF_ENUMS_H 26 | #define ESPTOOL_ELF_ENUMS_H 27 | 28 | enum { 29 | ET_NONE = 0, 30 | ET_REL = 1, 31 | ET_EXEC = 2, 32 | ET_DYN = 3, 33 | ET_CORE = 4, 34 | ET_LOPROC = 0xFF00, 35 | ET_HIPROC = 0xFFFF 36 | }; 37 | 38 | enum { 39 | EM_NONE = 0, 40 | EM_M32 = 1, 41 | EM_SPARC = 2, 42 | EM_386 = 3, 43 | EM_68K = 4, 44 | EM_88K = 5, 45 | EM_860 = 7, 46 | EM_MIPS = 8 47 | }; 48 | 49 | enum { 50 | EV_NONE = 0, 51 | EV_CURRENT = 1 52 | }; 53 | 54 | enum { 55 | EI_MAG0 = 0, 56 | EI_MAG1 = 1, 57 | EI_MAG2 = 2, 58 | EI_MAG3 = 3, 59 | EI_CLASS = 4, 60 | EI_DATA = 5, 61 | EI_VERSION = 6, 62 | EI_PAD = 7, 63 | EI_NIDENT = 16 64 | }; 65 | 66 | enum { 67 | ELFCLASSNONE = 0, 68 | ELFCLASS32 = 1, 69 | ELFCLASS64 = 2 70 | }; 71 | 72 | enum { 73 | ELFDATANONE = 0, 74 | ELFDATA2LSB = 1, 75 | ELFDATA2MSB = 2 76 | }; 77 | 78 | enum { 79 | SHN_UNDEF = 0, 80 | SHN_LORESERVE = 0xFF00, 81 | SHN_LOPROC = 0xFF00, 82 | SHN_HIPROC = 0xFF1F, 83 | SHN_ABS = 0xFFF1, 84 | SHN_COMMON = 0xFFF2, 85 | SHN_HIRESERVE = 0xFFFF 86 | }; 87 | 88 | 89 | enum { 90 | SHT_NULL = 0, 91 | SHT_PROGBITS = 1, 92 | SHT_SYMTAB = 2, 93 | SHT_STRTAB = 3, 94 | SHT_RELA = 4, 95 | SHT_HASH = 5, 96 | SHT_DYNAMIC = 6, 97 | SHT_NOTE = 7, 98 | SHT_NOBITS = 8, 99 | SHT_REL = 9, 100 | SHT_SHLIB = 10, 101 | SHT_DYNSYM = 11, 102 | SHT_LOPROC = 0x70000000, 103 | SHT_HIPROC = 0x7FFFFFFF, 104 | SHT_LOUSER = 0x80000000, 105 | SHT_HIUSER = 0xFFFFFFFF 106 | }; 107 | 108 | enum { 109 | SHF_WRITE = 0x1, 110 | SHF_ALLOC = 0x2, 111 | SHF_EXECINSTR = 0x4, 112 | SHF_MASKPROC = 0xF0000000 113 | }; 114 | 115 | 116 | enum { 117 | STB_LOCAL = 0, 118 | STB_GLOBAL = 1, 119 | STB_WEAK = 2, 120 | STB_LOPROC = 13, 121 | STB_HIPROC = 15 122 | }; 123 | 124 | enum { 125 | STT_NOTYPE = 0, 126 | STT_OBJECT = 1, 127 | STT_FUNC = 2, 128 | STT_SECTION = 3, 129 | STT_FILE = 4, 130 | STT_LOPROC = 13, 131 | STT_HIPROC = 15 132 | }; 133 | 134 | 135 | enum { 136 | R_386_NONE = 0, 137 | R_386_32 = 1, 138 | R_386_PC32 = 2, 139 | R_386_GOT32 = 3, 140 | R_386_PLT32 = 4, 141 | R_386_COPY = 5, 142 | R_386_GLOB_DAT = 6, 143 | R_386_JMP_SLOT = 7, 144 | R_386_RELATIVE = 8, 145 | R_386_GOTOFF = 9, 146 | R_386_GOTPC = 10, 147 | }; 148 | 149 | 150 | enum { 151 | PT_NULL = 0, 152 | PT_LOAD = 1, 153 | PT_DYNAMIC = 2, 154 | PT_INTERP = 3, 155 | PT_NOTE = 4, 156 | PT_SHLIB = 5, 157 | PT_PHDR = 6, 158 | PT_LOPROC = 0x70000000, 159 | PT_HIPROC = 0x7FFFFFFF, 160 | }; 161 | 162 | enum { 163 | DT_NULL = 0, 164 | DT_NEEDED = 1, 165 | DT_PLTRELSZ = 2, 166 | DT_PLTGOT = 3, 167 | DT_HASH = 4, 168 | DT_STRTAB = 5, 169 | DT_SYMTAB = 6, 170 | DT_RELA = 7, 171 | DT_RELASZ = 8, 172 | DT_RELAENT = 9, 173 | DT_STRSZ = 10, 174 | DT_SYMENT = 11, 175 | DT_INIT = 12, 176 | DT_FINI = 13, 177 | DT_SONAME = 14, 178 | DT_RPATH = 15, 179 | DT_SYMBOLIC = 16, 180 | DT_REL = 17, 181 | DT_RELSZ = 18, 182 | DT_RELENT = 19, 183 | DT_PLTREL = 20, 184 | DT_DEBUG = 21, 185 | DT_TEXTREL = 22, 186 | DT_JMPREL = 23, 187 | DT_LOPROC = 0x70000000, 188 | DT_HIPROC = 0x7FFFFFFF 189 | }; 190 | 191 | #endif 192 | -------------------------------------------------------------------------------- /argparse/argparse.c: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** argparse.c 5 | *** - simple parser for command line arguments 6 | *** checks which command submodule an argument is for and then dispatches 7 | *** processing to the appropriate parser 8 | *** 9 | *** Copyright (C) 2014 Christian Klippel 10 | *** 11 | *** This program is free software; you can redistribute it and/or modify 12 | *** it under the terms of the GNU General Public License as published by 13 | *** the Free Software Foundation; either version 2 of the License, or 14 | *** (at your option) any later version. 15 | *** 16 | *** This program is distributed in the hope that it will be useful, 17 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | *** GNU General Public License for more details. 20 | *** 21 | *** You should have received a copy of the GNU General Public License along 22 | *** with this program; if not, write to the Free Software Foundation, Inc., 23 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 24 | *** 25 | **/ 26 | 27 | #include "infohelper.h" 28 | #include "argparse_binimagecmd.h" 29 | #include "argparse_commcmd.h" 30 | #include "argparse_elfcmd.h" 31 | 32 | // main parser state machine, returns the number of arguments used by 33 | // the called sub-parser 34 | #include "argparse.h" 35 | 36 | static void print_help() 37 | { 38 | const char* help = "\ 39 | esptool v" VERSION " - (c) 2014 Ch. Klippel \n\ 40 | ESP8266/ESP32 build and upload helper tool\n\ 41 | Maintained by Ivan Grokhotkov: https://github.com/igrr/esptool-ck\n\ 42 | \n\ 43 | The program interprets arguments given on the command line, and in the order\n\ 44 | they are given.\n\ 45 | \n\ 46 | -eo \n\ 47 | Open an ELF object file, parse it and cache some of the information found \n\ 48 | therein. Works only if there is no ELF file currently opened.\n\ 49 | \n\ 50 | -es
\n\ 51 | Read the given section from the ELF file and make a raw dump into the \n\ 52 | specified file.\n\ 53 | -ec\n\ 54 | Close the currently opened ELF file.\n\ 55 | \n\ 56 | -bo \n\ 57 | Prepare a firmware file in the format that is understood by the ESP chip. \n\ 58 | Works only if an ELF file is opened, and if no firmware file is prepared yet.\n\ 59 | Upon -bo the tool will start out with an empty image where only the main \n\ 60 | header is set up. The result of the operations done on the firmware image \n\ 61 | is saved when the it is finally closed using -bc command.\n\ 62 | \n\ 63 | -bm \n\ 64 | Set the flash chip interface mode. Default is QIO. \n\ 65 | This parameter is stored in the binary image header, along with the flash size\n\ 66 | and flash frequency. The ROM bootloader in the ESP8266 uses the value \n\ 67 | of these parameters in order to know how to talk to the flash chip.\n\ 68 | \n\ 69 | -bz <512K|256K|1M|2M|4M|8M|16M|32M> \n\ 70 | Set the flash chip size. Default is 512K.\n\ 71 | \n\ 72 | -bf <40|26|20|80>\n\ 73 | Set the flash chip frequency, in MHz. Default is 40M.\n\ 74 | \n\ 75 | -bs
\n\ 76 | Read the specified section from the ELF file and append it to the \n\ 77 | firmware image. Sections will appear in the firmware image in the exact \n\ 78 | same order as the -bs commands are executed.\n\ 79 | \n\ 80 | -bp \n\ 81 | Finalize the firmware image, padding it with '0xaa' value until it is at least\n\ 82 | bytes long. Unlike -bc, this doesn't close the file.\n\ 83 | This option can be used to combine bootloader with the rest of the application\n\ 84 | \n\ 85 | -br \n\ 86 | Pad all the following sections to multiples of . Default is 4 bytes.\n\ 87 | This option can be used to place sections on specific boundaries, e.g. 4k or 64k.\n\ 88 | \n\ 89 | -bc\n\ 90 | Close the firmware image and save the result as file to disk.\n\ 91 | \n\ 92 | -v\n\ 93 | Increase verbosity level of the tool.\n\ 94 | Add more v's to increase it even more, e.g. -vv, -vvv.\n\ 95 | \n\ 96 | -q\n\ 97 | Disable most of the output.\n\ 98 | \n\ 99 | -cp \n\ 100 | Select the serial port device to use for communicating with the ESP.\n\ 101 | Default is /dev/ttyUSB0 on Linux, COM1 on Windows, /dev/tty.usbserial on Mac OS.\n\ 102 | \n\ 103 | -cd \n\ 104 | Select the reset method to use for resetting the board.\n\ 105 | Currently supported methods are: none, ck, nodemcu, wifio.\n\ 106 | \n\ 107 | -cb \n\ 108 | Select the baudrate to use, default is 115200.\n\ 109 | \n\ 110 | -ca
\n\ 111 | Address in flash memory to upload the data to.\n\ 112 | This address is interpreted as hexadecimal. Default is 0x00000000.\n\ 113 | \n\ 114 | -cf \n\ 115 | Upload the file to flash. Parameters that set the port, baud rate, and address\n\ 116 | must precede the -cf command.\n\ 117 | \n\ 118 | -cz \n\ 119 | Erase bytes, starting from the address set using -ca flag.\n\ 120 | \n\ 121 | -cr\n\ 122 | Reset chip into app using the selected reset method.\n\ 123 | \n\ 124 | -ce\n\ 125 | Erase flash.\n\ 126 | \n\ 127 | -cp \n\ 128 | Pad last written section of firmware image to the given size, in bytes.\n\ 129 | \n"; 130 | INFO(help); 131 | } 132 | 133 | int parse_arg(int num_args, char **arg_ptr) 134 | { 135 | if(arg_ptr[0][0] == '-' && num_args) 136 | { 137 | switch(arg_ptr[0][1]) 138 | { 139 | // ELF file related commands 140 | case 'd': 141 | LOGWARN("USING -d IS DEPRECATED, USE -es INSTEAD. FIXING COMMAND"); 142 | arg_ptr[0][1] = 'e'; 143 | arg_ptr[0][2] = 's'; 144 | case 'e': 145 | return argparse_elfcmd(num_args, arg_ptr); 146 | break; 147 | 148 | // binary flash image related commands 149 | case 'b': 150 | return argparse_binimagecmd(num_args, arg_ptr); 151 | break; 152 | 153 | // comms related commands (flash upload, etc.) 154 | case 'c': 155 | return argparse_commcmd(num_args, arg_ptr); 156 | break; 157 | 158 | // verbosity setting commands 159 | case 'v': 160 | return 1; 161 | break; 162 | 163 | case 'q': 164 | return 1; 165 | break; 166 | 167 | case '?': 168 | case 'h': 169 | print_help(); 170 | return 1; 171 | break; 172 | 173 | default: 174 | return 0; 175 | break; 176 | } 177 | } 178 | 179 | return 0; 180 | } 181 | -------------------------------------------------------------------------------- /binimage/esptool_binimage.c: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** esptool_binimage.c 5 | *** - implementation of functions to handle firmware files for the ESP8266 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include "infohelper.h" 30 | #include "esptool_binimage.h" 31 | 32 | static bin_image b_image = { 33 | .magic = 0xe9, 34 | .num_segments = 0, 35 | .flash_mode = FLASH_MODE_QIO, 36 | .flash_size_freq = FLASH_SIZE_512K | FLASH_FREQ_40 37 | }; 38 | 39 | unsigned int total_size = 0; 40 | 41 | int binimage_add_segment(uint32_t address, uint32_t size, unsigned char *data) 42 | { 43 | if(!data) 44 | { 45 | LOGERR("no data for binimage segment #%i", b_image.num_segments); 46 | return 0; 47 | } 48 | 49 | if(b_image.segments == 0) 50 | { 51 | b_image.segments = malloc(size); 52 | if(b_image.segments == NULL) 53 | { 54 | LOGERR("can't allocate 0x%08X bytes for binimage segment #%i", 55 | b_image.segments[b_image.num_segments].size, b_image.num_segments); 56 | return 0; 57 | } 58 | } 59 | else 60 | { 61 | b_image.segments = realloc(b_image.segments, (b_image.num_segments+1)*sizeof(binary_segment)); 62 | if(b_image.segments == NULL) 63 | { 64 | LOGERR("can't allocate 0x%08X more bytes for binimage segment #%i", 65 | b_image.segments[b_image.num_segments].size, b_image.num_segments); 66 | return 0; 67 | } 68 | } 69 | 70 | b_image.segments[b_image.num_segments].address = address; 71 | b_image.segments[b_image.num_segments].size = size; 72 | b_image.segments[b_image.num_segments].data = data; 73 | 74 | LOGINFO("added segment #%i to binimage for address 0x%08X with size 0x%08X", 75 | b_image.num_segments, 76 | b_image.segments[b_image.num_segments].address, 77 | b_image.segments[b_image.num_segments].size); 78 | 79 | b_image.num_segments++; 80 | return 1; 81 | } 82 | 83 | int binimage_prepare(const char *fname, uint32_t entry) 84 | { 85 | if(b_image.image_file) 86 | { 87 | return 0; 88 | } 89 | 90 | b_image.entry = entry; 91 | 92 | if(fname[0]) 93 | { 94 | b_image.image_file = fopen(fname, "wb"); 95 | if(b_image.image_file == NULL) 96 | { 97 | LOGERR("can't open binimage file \"%s\" for writing, aborting", fname); 98 | return 0; 99 | } 100 | } 101 | else 102 | { 103 | return 0; 104 | } 105 | 106 | b_image.segments = 0; 107 | b_image.num_segments = 0; 108 | total_size = 0; 109 | 110 | LOGINFO("created structure for binimage \"%s\" with entry address 0x%08X", fname, b_image.entry); 111 | 112 | return 1; 113 | } 114 | 115 | void bimage_set_entry(uint32_t entry) 116 | { 117 | b_image.entry = entry; 118 | LOGINFO("set bimage entry to 0x%08X", b_image.entry); 119 | } 120 | 121 | int binimage_write(uint32_t padsize, bool close) 122 | { 123 | unsigned int cnt, cnt2; 124 | unsigned char chksum; 125 | 126 | chksum = 0xEF; 127 | 128 | if(b_image.image_file == 0) 129 | { 130 | return 0; 131 | } 132 | 133 | if(fwrite((unsigned char*)&b_image, 1, 8, b_image.image_file) != 8) 134 | { 135 | LOGERR("can't write main header to binimage file, aborting"); 136 | fclose(b_image.image_file); 137 | b_image.image_file = 0; 138 | return 0; 139 | } 140 | 141 | total_size = 8; 142 | 143 | for(cnt = 0; cnt < b_image.num_segments; cnt++) 144 | { 145 | if(fwrite((unsigned char*)&b_image.segments[cnt], 1, 8, b_image.image_file) != 8) 146 | { 147 | LOGERR("can't write header for segment #%i to binimage file, aborting", cnt); 148 | fclose(b_image.image_file); 149 | b_image.image_file = 0; 150 | return 0; 151 | } 152 | 153 | total_size += 8; 154 | 155 | if(fwrite(b_image.segments[cnt].data, 1, b_image.segments[cnt].size, b_image.image_file) != b_image.segments[cnt].size) 156 | { 157 | LOGERR("can't write data block for segment #%i to binimage file, aborting", cnt); 158 | fclose(b_image.image_file); 159 | b_image.image_file = 0; 160 | return 0; 161 | } 162 | 163 | total_size += b_image.segments[cnt].size; 164 | for(cnt2 = 0; cnt2 < b_image.segments[cnt].size; cnt2++) 165 | { 166 | chksum ^= b_image.segments[cnt].data[cnt2]; 167 | } 168 | } 169 | 170 | padsize--; 171 | 172 | while(++total_size & padsize) 173 | { 174 | if(fputc(0x00, b_image.image_file) == EOF) 175 | { 176 | LOGERR("can't write padding byte 0x00 at 0x%08X to binimage file, aborting", total_size); 177 | fclose(b_image.image_file); 178 | b_image.image_file = 0; 179 | return 0; 180 | } 181 | cnt++; 182 | } 183 | 184 | if(fputc(chksum, b_image.image_file) == EOF) 185 | { 186 | LOGERR("can't write checksum byte 0x%02X at 0x%08X to binimage file, aborting", chksum, total_size); 187 | fclose(b_image.image_file); 188 | b_image.image_file = 0; 189 | return 0; 190 | } 191 | 192 | LOGINFO("saved binimage file, total size is %i bytes, checksum byte is 0x%02X", total_size, chksum); 193 | 194 | if (close) 195 | { 196 | fclose(b_image.image_file); 197 | b_image.image_file = 0; 198 | } 199 | 200 | if(b_image.segments) 201 | { 202 | for(cnt = 0; cnt < b_image.num_segments; cnt++) 203 | { 204 | if(b_image.segments[cnt].data) 205 | { 206 | LOGDEBUG("releasing memory used for segment %i in binimage", cnt); 207 | free(b_image.segments[cnt].data); 208 | } 209 | } 210 | if(b_image.segments) 211 | { 212 | LOGDEBUG("releasing memory used for binimage segment pointers"); 213 | free(b_image.segments); 214 | b_image.segments = 0; 215 | b_image.num_segments = 0; 216 | } 217 | } 218 | 219 | return 1; 220 | } 221 | 222 | int binimage_write_close(uint32_t padsize) 223 | { 224 | return binimage_write(padsize, true); 225 | } 226 | 227 | int binimage_write_padto(uint32_t padsize, uint32_t address) 228 | { 229 | if (binimage_write(padsize, false) == 0) 230 | return 0; 231 | 232 | LOGDEBUG("binimage_write_padto: total:%x addr:%x", total_size, address); 233 | if (address < total_size) 234 | { 235 | LOGERR("binimage_write_padto: address is less than size written"); 236 | return 0; 237 | } 238 | 239 | while (total_size < address) 240 | { 241 | if (fputc(0xaa, b_image.image_file) == EOF) 242 | return 0; 243 | ++total_size; 244 | } 245 | 246 | return 1; 247 | } 248 | 249 | #define INVALID_VAL 0xff 250 | 251 | unsigned char binimage_parse_flash_mode(const char* str); 252 | unsigned char binimage_parse_flash_size(const char* str); 253 | unsigned char binimage_parse_flash_freq(const char* str); 254 | 255 | const char* binimage_flash_mode_to_str(unsigned char mode); 256 | const char* binimage_flash_size_to_str(unsigned char size); 257 | const char* binimage_flash_freq_to_str(unsigned char freq); 258 | 259 | 260 | int binimage_set_flash_mode(const char* modestr) 261 | { 262 | unsigned char mode = binimage_parse_flash_mode(modestr); 263 | if (mode == INVALID_VAL) 264 | { 265 | LOGERR("invalid flash mode value: %s", modestr); 266 | return 0; 267 | } 268 | 269 | LOGINFO("setting flash mode from %s to %s", 270 | binimage_flash_mode_to_str(b_image.flash_mode), 271 | binimage_flash_mode_to_str(mode)); 272 | 273 | b_image.flash_mode = mode; 274 | return 1; 275 | } 276 | 277 | int binimage_set_flash_size(const char* sizestr) 278 | { 279 | unsigned char size = binimage_parse_flash_size(sizestr); 280 | if (size == INVALID_VAL) 281 | { 282 | LOGERR("invalid flash size value: %s", sizestr); 283 | return 0; 284 | } 285 | 286 | LOGINFO("setting flash size from %s to %s", 287 | binimage_flash_size_to_str(b_image.flash_size_freq & 0xf0), 288 | binimage_flash_size_to_str(size)); 289 | 290 | b_image.flash_size_freq = size | (b_image.flash_size_freq & 0x0f); 291 | return 1; 292 | } 293 | 294 | int binimage_set_flash_freq(const char* freqstr) 295 | { 296 | unsigned char freq = binimage_parse_flash_freq(freqstr); 297 | if (freq == INVALID_VAL) 298 | { 299 | LOGERR("invalid flash frequency value: %s", freqstr); 300 | return 0; 301 | } 302 | 303 | LOGINFO("setting flash frequency from %s to %s", 304 | binimage_flash_freq_to_str(b_image.flash_size_freq & 0x0f), 305 | binimage_flash_freq_to_str(freq)); 306 | 307 | b_image.flash_size_freq = (b_image.flash_size_freq & 0xf0) | freq; 308 | return 1; 309 | } 310 | 311 | static const char* flash_mode_str[] = {"qio", "qout", "dio", "dout"}; 312 | static const char* flash_size_str[] = {"512K", "256K", "1M", "2M", "4M", NULL, NULL, NULL, "8M", "16M"}; 313 | 314 | unsigned char binimage_parse_flash_mode(const char* str) 315 | { 316 | const int n = sizeof(flash_mode_str)/sizeof(const char*); 317 | for (int i = 0; i < n; ++i) 318 | { 319 | if (flash_mode_str[i] && strcasecmp(str, flash_mode_str[i]) == 0) 320 | { 321 | return (unsigned char) i; 322 | } 323 | } 324 | return INVALID_VAL; 325 | } 326 | 327 | unsigned char binimage_parse_flash_size(const char* str) 328 | { 329 | const int n = sizeof(flash_size_str)/sizeof(const char*); 330 | for (int i = 0; i < n; ++i) 331 | { 332 | if (flash_size_str[i] && strcasecmp(str, flash_size_str[i]) == 0) 333 | { 334 | return (unsigned char) i << 4; 335 | } 336 | } 337 | return INVALID_VAL; 338 | } 339 | 340 | unsigned char binimage_parse_flash_freq(const char* str) 341 | { 342 | int val = atoi(str); 343 | switch (val) 344 | { 345 | case 40: return FLASH_FREQ_40; 346 | case 26: return FLASH_FREQ_26; 347 | case 20: return FLASH_FREQ_20; 348 | case 80: return FLASH_FREQ_80; 349 | default: return INVALID_VAL; 350 | } 351 | } 352 | 353 | const char* binimage_flash_mode_to_str(unsigned char mode) 354 | { 355 | if (mode > FLASH_MODE_DOUT) 356 | return ""; 357 | 358 | return flash_mode_str[mode]; 359 | } 360 | 361 | const char* binimage_flash_size_to_str(unsigned char size) 362 | { 363 | int index = size >> 4; 364 | if (index > FLASH_SIZE_16M || flash_size_str[index] == NULL) 365 | return ""; 366 | return flash_size_str[index]; 367 | } 368 | 369 | const char* binimage_flash_freq_to_str(unsigned char freq) 370 | { 371 | switch (freq) 372 | { 373 | case FLASH_FREQ_40: return "40"; 374 | case FLASH_FREQ_26: return "26"; 375 | case FLASH_FREQ_20: return "20"; 376 | case FLASH_FREQ_80: return "80"; 377 | default: return ""; 378 | } 379 | } 380 | 381 | -------------------------------------------------------------------------------- /elf/esptool_elf_object.c: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** esptool_elf_object.c 5 | *** - implementation of various functions to access ELF object/executable files 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | #include 25 | #include 26 | #include "infohelper.h" 27 | #include "esptool_elf.h" 28 | #include "esptool_elf_object.h" 29 | #include "esptool_elf_enums.h" 30 | 31 | static ELF_Object e_object; 32 | 33 | static int check_elf_header(void) 34 | { 35 | if(fread( (char*) &e_object.header, 1, sizeof(Elf32_Ehdr), e_object.e_file) != sizeof(Elf32_Ehdr)) 36 | { 37 | LOGERR("can't read ELF file header"); 38 | return 0; 39 | } 40 | 41 | 42 | if(e_object.header.e_ident[EI_MAG0] == 0x7F && 43 | e_object.header.e_ident[EI_MAG1] == 'E' && 44 | e_object.header.e_ident[EI_MAG2] == 'L' && 45 | e_object.header.e_ident[EI_MAG3] == 'F') 46 | { 47 | return 1; 48 | } 49 | 50 | return 0; 51 | } 52 | 53 | void get_elf_strings(void) 54 | { 55 | if(e_object.header.e_shstrndx) 56 | { 57 | if(fseek(e_object.e_file, e_object.header.e_shoff+(e_object.header.e_shstrndx*e_object.header.e_shentsize), SEEK_SET) != 0) 58 | { 59 | LOGERR("can't seek to stringtable section info in ELF file"); 60 | return; 61 | } 62 | 63 | if(fread((char*)&e_object.section, 1, sizeof(Elf32_Shdr), e_object.e_file) != sizeof(Elf32_Shdr) ) 64 | { 65 | LOGERR("can't read stringtable section info from ELF file!"); 66 | return; 67 | } 68 | 69 | if(e_object.section.sh_size) 70 | { 71 | LOGDEBUG("loading string table from ELF file"); 72 | e_object.strings = malloc(e_object.section.sh_size); 73 | 74 | if(e_object.strings == NULL) 75 | { 76 | LOGERR("can't malloc memory for stringtable of ELF file"); 77 | return; 78 | } 79 | 80 | if(fseek(e_object.e_file, e_object.section.sh_offset, SEEK_SET) != 0) 81 | { 82 | LOGERR("can't seek to stringtable section info in ELF file"); 83 | return; 84 | } 85 | 86 | if( fread(e_object.strings, 1, e_object.section.sh_size, e_object.e_file) != e_object.section.sh_size) 87 | { 88 | LOGERR("can't read stringtable from ELF file!"); 89 | return; 90 | } 91 | 92 | } 93 | 94 | } 95 | 96 | } 97 | 98 | void collect_elf_sections(void) 99 | { 100 | unsigned int cnt; 101 | 102 | e_object.sections = malloc(e_object.header.e_shnum*sizeof(ELF_section)); 103 | if(e_object.sections == NULL) 104 | { 105 | LOGERR("can't malloc memory for ELF section list"); 106 | return; 107 | } 108 | 109 | if(e_object.sections) 110 | { 111 | if(e_object.header.e_shnum) 112 | { 113 | LOGDEBUG("building ELF section list"); 114 | for(cnt = 1; cnt < e_object.header.e_shnum; cnt++) 115 | { 116 | if(fseek(e_object.e_file, e_object.header.e_shoff+(cnt*e_object.header.e_shentsize), SEEK_SET) != 0) 117 | { 118 | LOGERR("can't seek to ELF file section info #%i", cnt); 119 | return; 120 | } 121 | 122 | if(fread((char*)&e_object.section, 1, sizeof(Elf32_Shdr), e_object.e_file) != sizeof(Elf32_Shdr)) 123 | { 124 | LOGERR("can't read section info #%i from ELF file", cnt); 125 | return; 126 | } 127 | 128 | if(e_object.section.sh_name) 129 | { 130 | e_object.sections[cnt-1].name = e_object.strings+e_object.section.sh_name; 131 | } 132 | else 133 | { 134 | e_object.sections[cnt-1].name = 0; 135 | } 136 | 137 | e_object.sections[cnt-1].offset = e_object.section.sh_offset; 138 | e_object.sections[cnt-1].address = e_object.section.sh_addr; 139 | e_object.sections[cnt-1].size = e_object.section.sh_size; 140 | } 141 | LOGDEBUG("ELF section list created: %i entries", e_object.header.e_shnum-1); 142 | } 143 | else 144 | { 145 | LOGDEBUG("no sections in ELF object"); 146 | } 147 | } 148 | else 149 | { 150 | LOGERR("can't malloc memory for ELF sections list"); 151 | } 152 | } 153 | 154 | void list_elf_sections(void) 155 | { 156 | unsigned int cnt; 157 | for(cnt = 1; cnt < e_object.header.e_shnum; cnt++) 158 | { 159 | LOGVERBOSE("ADDR: 0x%08X - SIZE: 0x%08X - OFFSET: 0x%08X - Name: %s", e_object.sections[cnt-1].address, 160 | e_object.sections[cnt-1].size, 161 | e_object.sections[cnt-1].offset, 162 | e_object.sections[cnt-1].name); 163 | } 164 | } 165 | 166 | void print_elf_section_info(Elf32_Half secnum) 167 | { 168 | if(secnum && secnum < e_object.header.e_shnum) 169 | { 170 | if(fseek(e_object.e_file, e_object.header.e_shoff+(secnum*e_object.header.e_shentsize), SEEK_SET) != 0) 171 | { 172 | LOGERR("can't seek to ELF file section info %i", secnum); 173 | return; 174 | } 175 | 176 | if(fread((char*)&e_object.section, 1, sizeof(Elf32_Shdr), e_object.e_file) != sizeof(Elf32_Shdr)) 177 | { 178 | LOGERR("can't read ELF file section info %i", secnum); 179 | return; 180 | } 181 | 182 | if(e_object.section.sh_name) 183 | { 184 | LOGVERBOSE("section name : %s", e_object.strings+e_object.section.sh_name); 185 | } 186 | else 187 | { 188 | LOGVERBOSE("section name : "); 189 | } 190 | LOGVERBOSE("sh_name : 0x%08X", e_object.section.sh_name); 191 | LOGVERBOSE("sh_type : 0x%08X", e_object.section.sh_type); 192 | LOGVERBOSE("sh_flags : 0x%08X", e_object.section.sh_flags); 193 | LOGVERBOSE("sh_addr : 0x%08X", e_object.section.sh_addr); 194 | LOGVERBOSE("sh_offset : 0x%08X", e_object.section.sh_offset); 195 | LOGVERBOSE("sh_size : 0x%08X", e_object.section.sh_size); 196 | LOGVERBOSE("sh_link : 0x%08X", e_object.section.sh_link); 197 | LOGVERBOSE("sh_info : 0x%08X", e_object.section.sh_info); 198 | LOGVERBOSE("sh_addralign : 0x%08X", e_object.section.sh_addralign); 199 | LOGVERBOSE("sh_entsize : 0x%08X", e_object.section.sh_entsize); 200 | } 201 | } 202 | 203 | int get_elf_num_sections(void) 204 | { 205 | return e_object.header.e_shnum; 206 | } 207 | 208 | int get_elf_secnum_by_name(const char *secname) 209 | { 210 | unsigned int cnt; 211 | 212 | for(cnt = 1; cnt < e_object.header.e_shnum; cnt++) 213 | { 214 | if( strcmp(e_object.sections[cnt-1].name, secname) == 0) 215 | { 216 | LOGVERBOSE("found section %s at index %i", secname, cnt); 217 | return cnt; 218 | } 219 | } 220 | return 0; 221 | } 222 | 223 | unsigned char* get_elf_section_bindata(Elf32_Half secnum, uint32_t pad_to) 224 | { 225 | unsigned char *bindata; 226 | uint32_t pad_pos; 227 | 228 | if(secnum && secnum < e_object.header.e_shnum) 229 | { 230 | if(e_object.sections[secnum-1].size) 231 | { 232 | if(e_object.sections[secnum-1].size < pad_to) 233 | { 234 | LOGVERBOSE("padding section #%i binary data (size 0x%08X) with %i bytes", secnum, e_object.sections[secnum-1].size, (pad_to-e_object.sections[secnum-1].size)); 235 | bindata = malloc(pad_to); 236 | } 237 | else 238 | { 239 | bindata = malloc(e_object.sections[secnum-1].size); 240 | } 241 | 242 | if(bindata == NULL) 243 | { 244 | LOGERR("can't malloc memory for ELF section %d binary data", secnum); 245 | return 0; 246 | } 247 | 248 | if(fseek(e_object.e_file, e_object.sections[secnum-1].offset, SEEK_SET) != 0) 249 | { 250 | LOGERR("can't seek to ELF file section %i binary datai", secnum); 251 | return 0; 252 | } 253 | 254 | if(fread(bindata, 1, e_object.sections[secnum-1].size, e_object.e_file) != e_object.sections[secnum-1].size) 255 | { 256 | LOGERR("can't read section #%i binary data from ELF file", secnum); 257 | return 0; 258 | } 259 | 260 | 261 | for(pad_pos = e_object.sections[secnum-1].size; pad_pos < pad_to; pad_pos++) 262 | { 263 | bindata[pad_pos] = 0x00; 264 | } 265 | 266 | return bindata; 267 | } 268 | } 269 | 270 | return 0; 271 | } 272 | 273 | int save_elf_section_bindata( const char *secname, const char *fname ) 274 | { 275 | FILE *f; 276 | unsigned char *binblob; 277 | uint32_t secnum; 278 | 279 | secnum = get_elf_secnum_by_name(secname); 280 | 281 | binblob = get_elf_section_bindata(secnum, 0); 282 | 283 | if(binblob) 284 | { 285 | f = fopen( fname, "wb" ); 286 | if(f == NULL) 287 | { 288 | LOGERR("can't open file \"%s\" to save binary dump of ELF section \"%s\"", fname, e_object.sections[secnum-1].name); 289 | free(binblob); 290 | return 0; 291 | } 292 | 293 | if( fwrite(binblob, 1, e_object.sections[secnum-1].size, f) != e_object.sections[secnum-1].size) 294 | { 295 | LOGERR("can't open file \"%s\" to save binary dump of ELF section \"%s\"", fname, e_object.sections[secnum-1].name); 296 | fclose(f); 297 | free(binblob); 298 | return 0; 299 | } 300 | 301 | fclose(f); 302 | free(binblob); 303 | 304 | LOGINFO("saved section \"%s\" to file \"%s\"", e_object.sections[secnum-1].name, fname); 305 | } 306 | return 1; 307 | } 308 | 309 | Elf32_Word get_elf_section_size(Elf32_Half secnum) 310 | { 311 | if(secnum && secnum < e_object.header.e_shnum) 312 | { 313 | return e_object.sections[secnum-1].size; 314 | } 315 | return 0; 316 | } 317 | 318 | Elf32_Word get_elf_section_addr(Elf32_Half secnum) 319 | { 320 | if(secnum && secnum < e_object.header.e_shnum) 321 | { 322 | return e_object.sections[secnum-1].address; 323 | } 324 | return 0; 325 | } 326 | 327 | const char* get_elf_section_name(Elf32_Half secnum) 328 | { 329 | if(secnum && secnum < e_object.header.e_shnum) 330 | { 331 | return e_object.sections[secnum-1].name; 332 | } 333 | return 0; 334 | } 335 | 336 | Elf32_Word get_elf_entry(void) 337 | { 338 | return e_object.header.e_entry; 339 | } 340 | 341 | int create_elf_object(const char *filename) 342 | { 343 | if(e_object.e_file) 344 | { 345 | return 0; 346 | } 347 | 348 | e_object.strings = 0; 349 | e_object.e_file = 0; 350 | 351 | e_object.e_file = fopen(filename, "rb"); 352 | 353 | if(e_object.e_file) 354 | { 355 | LOGINFO("using ELF file \"%s\"", filename); 356 | 357 | if( check_elf_header() ) 358 | { 359 | LOGDEBUG("ELF header OK"); 360 | 361 | LOGVERBOSE("e_type : 0x%04X", e_object.header.e_type); 362 | LOGVERBOSE("e_machine : 0x%04X", e_object.header.e_machine); 363 | LOGVERBOSE("e_version : 0x%08X", e_object.header.e_version); 364 | LOGVERBOSE("e_entry : 0x%08X", e_object.header.e_entry); 365 | LOGVERBOSE("e_phoff : 0x%08X", e_object.header.e_phoff); 366 | LOGVERBOSE("e_shoff : 0x%08X", e_object.header.e_shoff); 367 | LOGVERBOSE("e_flags : 0x%08X", e_object.header.e_flags); 368 | LOGVERBOSE("e_ehsize : 0x%04X", e_object.header.e_ehsize); 369 | LOGVERBOSE("e_phentsize : 0x%04X", e_object.header.e_phentsize); 370 | LOGVERBOSE("e_phnum : 0x%04X", e_object.header.e_phnum); 371 | LOGVERBOSE("e_shentsize : 0x%04X", e_object.header.e_shentsize); 372 | LOGVERBOSE("e_shnum : 0x%04X", e_object.header.e_shnum); 373 | LOGVERBOSE("e_shstrndx : 0x%04X", e_object.header.e_shstrndx); 374 | 375 | get_elf_strings(); 376 | collect_elf_sections(); 377 | 378 | return 1; 379 | } 380 | else 381 | { 382 | LOGERR("wrong header for ELF file!"); 383 | } 384 | } 385 | else 386 | { 387 | LOGERR("can't open ELF file %s", filename); 388 | } 389 | 390 | return 0; 391 | } 392 | 393 | int close_elf_object(void) 394 | { 395 | if(e_object.strings) 396 | { 397 | LOGDEBUG("releasing memory from ELF file stringtable"); 398 | free(e_object.strings); 399 | e_object.strings = 0; 400 | } 401 | 402 | if(e_object.sections) 403 | { 404 | LOGDEBUG("releasing memory from ELF file section info"); 405 | free(e_object.sections); 406 | e_object.sections = 0; 407 | } 408 | 409 | if(e_object.e_file) 410 | { 411 | LOGDEBUG("closing ELF file"); 412 | fclose(e_object.e_file); 413 | e_object.e_file = 0; 414 | } 415 | else 416 | { 417 | return 0; 418 | } 419 | 420 | return 1; 421 | } 422 | -------------------------------------------------------------------------------- /serialport/serialport.c: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** serialport.c 5 | *** - low level functions to access the serial port 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #if defined (_WIN32) 31 | #include 32 | #else 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #endif 40 | 41 | #include "serialport.h" 42 | #include "infohelper.h" 43 | 44 | #if defined (_WIN32) 45 | static HANDLE sPort = NULL; 46 | static DCB sDCB; 47 | static COMMTIMEOUTS sTIMEOUTS; 48 | #else 49 | static int serial_port = -1; 50 | static struct termios term; 51 | static unsigned int timeout; 52 | #endif 53 | 54 | 55 | #ifdef _WIN32 56 | 57 | #ifndef CBR_230400 58 | #define CBR_230400 230400 59 | #endif 60 | #ifndef CBR_460800 61 | #define CBR_460800 460800 62 | #endif 63 | #ifndef CBR_512000 64 | #define CBR_512000 512000 65 | #endif 66 | #ifndef CBR_921600 67 | #define CBR_921600 921600 68 | #endif 69 | 70 | 71 | void serialport_setbaudrate(unsigned int baudrate) 72 | { 73 | DWORD br = 0; 74 | switch(baudrate) 75 | { 76 | case 9600: br = CBR_9600; break; 77 | case 14400: br = CBR_14400; break; 78 | case 19200: br = CBR_19200; break; 79 | case 38400: br = CBR_38400; break; 80 | case 56000: br = CBR_56000; break; 81 | case 57600: br = CBR_57600; break; 82 | case 115200: br = CBR_115200; break; 83 | case 128000: br = CBR_128000; break; 84 | case 230400: br = CBR_230400; break; 85 | case 256000: br = CBR_256000; break; 86 | case 512000: br = CBR_512000; break; 87 | case 460800: br = CBR_460800; break; 88 | case 921600: br = CBR_921600; break; 89 | } 90 | if (br == 0) 91 | { 92 | LOGWARN("unsupported baud rate: %d, using 115200", baudrate); 93 | br = CBR_115200; 94 | } 95 | 96 | memset(&sDCB, 0, sizeof(DCB)); 97 | BuildCommDCB("baud=9600 parity=N data=8 stop=1",&sDCB); 98 | sDCB.DCBlength = sizeof(DCB); 99 | sDCB.BaudRate = br; 100 | sDCB.fBinary = TRUE; 101 | sDCB.fParity = FALSE; 102 | // sDCB.fOutxCtsFlow = TRUE; 103 | sDCB.fDtrControl = DTR_CONTROL_DISABLE; 104 | sDCB.fDsrSensitivity= FALSE; 105 | sDCB.fRtsControl = RTS_CONTROL_DISABLE; 106 | sDCB.ByteSize = 8; 107 | sDCB.StopBits = ONESTOPBIT; 108 | sDCB.fAbortOnError = FALSE; 109 | sDCB.fOutX = FALSE; 110 | sDCB.fInX = FALSE; 111 | if (!SetCommState(sPort, &sDCB)) 112 | { 113 | LOGDEBUG("SetCommState call failed"); 114 | } 115 | } 116 | 117 | int serialport_open(const char *device, unsigned int baudrate) 118 | { 119 | char portName[40]; 120 | sprintf(portName,"\\\\.\\%s", device); 121 | sPort = CreateFile(portName, GENERIC_WRITE|GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 122 | 123 | if (sPort == INVALID_HANDLE_VALUE) 124 | { 125 | LOGERR("Failed to open %s", device); 126 | return 0; 127 | } 128 | 129 | SetupComm(sPort, 256, 256); 130 | serialport_setbaudrate(baudrate); 131 | serialport_set_timeout(1000); 132 | return 1; 133 | } 134 | 135 | void serialport_set_timeout(unsigned int timeout) 136 | { 137 | LOGDEBUG("setting serial port timeouts to %d ms", timeout); 138 | sTIMEOUTS.ReadIntervalTimeout = 0; 139 | sTIMEOUTS.ReadTotalTimeoutConstant = timeout; 140 | sTIMEOUTS.ReadTotalTimeoutMultiplier = 0; 141 | sTIMEOUTS.WriteTotalTimeoutConstant = timeout; 142 | sTIMEOUTS.WriteTotalTimeoutMultiplier = 0; 143 | if (!SetCommTimeouts(sPort,&sTIMEOUTS)) 144 | { 145 | LOGDEBUG("SetCommTimeouts call failed"); 146 | } 147 | SetCommMask(sPort, EV_TXEMPTY); 148 | } 149 | 150 | unsigned serialport_get_timeout() 151 | { 152 | return sTIMEOUTS.ReadTotalTimeoutConstant; 153 | } 154 | 155 | unsigned serialport_read(unsigned char* data, unsigned int size) 156 | { 157 | unsigned long cb; 158 | ReadFile(sPort, data, size, &cb, NULL); 159 | if (cb != size) 160 | { 161 | LOGDEBUG("read %d, requested %d", cb, size); 162 | } 163 | return (unsigned) cb; 164 | } 165 | 166 | unsigned serialport_write(const unsigned char* data, unsigned int size) 167 | { 168 | unsigned long cb; 169 | WriteFile(sPort, data, size, &cb, NULL); 170 | if (cb != size) 171 | { 172 | LOGDEBUG("wrote %d, requested %d", cb, size); 173 | } 174 | return (unsigned) cb; 175 | } 176 | 177 | void serialport_flush(void) 178 | { 179 | unsigned char tmp[512]; 180 | if(sPort) 181 | { 182 | LOGDEBUG("flush start"); 183 | unsigned old_timeout = sTIMEOUTS.ReadTotalTimeoutConstant; 184 | serialport_set_timeout(1); 185 | ClearCommError(sPort, NULL, NULL); 186 | PurgeComm(sPort, PURGE_TXCLEAR|PURGE_RXCLEAR); 187 | unsigned long cb; 188 | int result; 189 | do { 190 | result = ReadFile(sPort, tmp, 512, &cb, NULL); 191 | LOGVERBOSE("flushed %lu bytes", cb); 192 | } while(cb && result == 0); 193 | serialport_set_timeout(old_timeout); 194 | LOGDEBUG("flush complete"); 195 | } 196 | } 197 | 198 | void serialport_drain(void) 199 | { 200 | if(sPort) 201 | { 202 | FlushFileBuffers(sPort); 203 | } 204 | 205 | } 206 | 207 | int serialport_close(void) 208 | { 209 | if(!sPort) 210 | return 0; 211 | serialport_drain(); 212 | serialport_flush(); 213 | CloseHandle(sPort); 214 | sPort = NULL; 215 | return 1; 216 | } 217 | 218 | void serialport_set_dtr(unsigned char val) 219 | { 220 | if(sPort) 221 | { 222 | EscapeCommFunction(sPort,((val)?SETDTR:CLRDTR)); 223 | } 224 | } 225 | 226 | void serialport_set_rts(unsigned char val) 227 | { 228 | if(sPort) 229 | { 230 | EscapeCommFunction(sPort,((val)?SETRTS:CLRRTS)); 231 | } 232 | } 233 | 234 | void serialport_send_break() 235 | { 236 | if (sPort) 237 | { 238 | EscapeCommFunction(sPort, SETBREAK); 239 | Sleep(250); 240 | EscapeCommFunction(sPort, CLRBREAK); 241 | } 242 | } 243 | 244 | 245 | #else 246 | 247 | void serialport_set_baudrate(unsigned int baudrate) 248 | { 249 | switch(baudrate) 250 | { 251 | case 2400: 252 | cfsetispeed(&term,B2400); 253 | cfsetospeed(&term,B2400); 254 | break; 255 | 256 | case 4800: 257 | cfsetispeed(&term,B4800); 258 | cfsetospeed(&term,B4800); 259 | break; 260 | 261 | case 9600: 262 | cfsetispeed(&term,B9600); 263 | cfsetospeed(&term,B9600); 264 | break; 265 | 266 | case 19200: 267 | cfsetispeed(&term,B19200); 268 | cfsetospeed(&term,B19200); 269 | break; 270 | 271 | case 38400: 272 | cfsetispeed(&term,B38400); 273 | cfsetospeed(&term,B38400); 274 | break; 275 | 276 | case 57600: 277 | cfsetispeed(&term,B57600); 278 | cfsetospeed(&term,B57600); 279 | break; 280 | 281 | case 115200: 282 | cfsetispeed(&term,B115200); 283 | cfsetospeed(&term,B115200); 284 | break; 285 | 286 | case 230400: 287 | cfsetispeed(&term,B230400); 288 | cfsetospeed(&term,B230400); 289 | break; 290 | #ifndef __APPLE__ 291 | case 460800: 292 | cfsetispeed(&term,B460800); 293 | cfsetospeed(&term,B460800); 294 | break; 295 | 296 | case 921600: 297 | cfsetispeed(&term,B921600); 298 | cfsetospeed(&term,B921600); 299 | break; 300 | #endif 301 | default: 302 | LOGWARN("serialport_set_baudrate: baud rate %d may not work", baudrate); 303 | cfsetispeed(&term,baudrate); 304 | cfsetospeed(&term,baudrate); 305 | break; 306 | } 307 | } 308 | 309 | void serialport_set_timeout(unsigned int t) 310 | { 311 | if(t != timeout) 312 | { 313 | LOGDEBUG("setting timeout %i", t); 314 | timeout = t; 315 | } 316 | } 317 | 318 | unsigned serialport_get_timeout() 319 | { 320 | return timeout; 321 | } 322 | 323 | int serialport_open(const char *device, unsigned int baudrate) 324 | { 325 | LOGINFO("opening port %s at %d", device, baudrate); 326 | int flags = O_RDWR | O_NOCTTY; 327 | #ifdef __APPLE__ 328 | flags |= O_NONBLOCK; 329 | #endif 330 | serial_port = open(device, flags); 331 | 332 | if(serial_port<0) 333 | { 334 | LOGERR("cannot access %s\n",device); 335 | return 0; 336 | } 337 | 338 | #ifdef __APPLE__ 339 | flags = fcntl(serial_port, F_GETFL, 0); 340 | fcntl(serial_port, F_SETFL, flags & (~O_NONBLOCK)); 341 | #endif 342 | 343 | serialport_set_dtr(0); 344 | 345 | LOGDEBUG("tcgetattr"); 346 | tcgetattr(serial_port,&term); 347 | 348 | serialport_set_baudrate(baudrate); 349 | 350 | term.c_cflag = (term.c_cflag & ~CSIZE) | CS8; 351 | term.c_cflag |= CLOCAL | CREAD; 352 | 353 | term.c_cflag &= ~(PARENB | PARODD); 354 | term.c_cflag &= ~CSTOPB; 355 | 356 | term.c_iflag = IGNBRK; 357 | 358 | term.c_iflag &= ~(IXON | IXOFF); 359 | 360 | term.c_lflag = 0; 361 | 362 | term.c_oflag = 0; 363 | 364 | 365 | term.c_cc[VMIN]=0; 366 | term.c_cc[VTIME]=1; 367 | timeout = 1000; 368 | 369 | 370 | 371 | LOGDEBUG("tcsetattr"); 372 | if (tcsetattr(serial_port, TCSANOW, &term)!=0) 373 | { 374 | LOGERR("setattr stage 1 failed"); 375 | return 0; 376 | } 377 | 378 | 379 | if (tcgetattr(serial_port, &term)!=0) 380 | { 381 | LOGERR("getattr failed"); 382 | return 0; 383 | } 384 | 385 | term.c_cflag &= ~CRTSCTS; 386 | 387 | if (tcsetattr(serial_port, TCSANOW, &term)!=0) 388 | { 389 | LOGERR("setattr stage 2 failed"); 390 | return 0; 391 | } 392 | LOGDEBUG("serial open"); 393 | return serial_port; 394 | } 395 | 396 | unsigned serialport_read(unsigned char* data, unsigned int size) 397 | { 398 | struct timeval tv0, tv1; 399 | gettimeofday(&tv0, NULL); 400 | unsigned n = 0; 401 | unsigned time_spent = 0; 402 | do 403 | { 404 | unsigned cb = read(serial_port, data + n, size - n); 405 | n += cb; 406 | gettimeofday(&tv1, NULL); 407 | time_spent = (tv1.tv_sec - tv0.tv_sec) * 1000 + tv1.tv_usec / 1000 - tv0.tv_usec / 1000; 408 | } while (n < size && time_spent < timeout); 409 | return n; 410 | } 411 | 412 | unsigned serialport_write(const unsigned char* data, unsigned int size) 413 | { 414 | return write(serial_port, data, size); 415 | } 416 | 417 | void serialport_flush(void) 418 | { 419 | static unsigned char b; 420 | 421 | if(serial_port) 422 | { 423 | tcdrain(serial_port); 424 | while(read(serial_port, &b, 1) > 0); 425 | } 426 | } 427 | 428 | void serialport_drain(void) 429 | { 430 | if(serial_port) 431 | { 432 | tcdrain(serial_port); 433 | } 434 | } 435 | 436 | int serialport_close(void) 437 | { 438 | if(serial_port) 439 | { 440 | tcdrain(serial_port); 441 | tcflush(serial_port, TCIOFLUSH); 442 | close(serial_port); 443 | return 1; 444 | } 445 | else 446 | { 447 | return 0; 448 | } 449 | } 450 | 451 | void serialport_set_dtr(unsigned char val) 452 | { 453 | int mcs; 454 | 455 | if(serial_port) 456 | { 457 | ioctl (serial_port, TIOCMGET, &mcs); 458 | 459 | if(val) 460 | { 461 | mcs |= TIOCM_DTR; 462 | ioctl (serial_port, TIOCMSET, &mcs); 463 | } 464 | else 465 | { 466 | mcs &= ~TIOCM_DTR; 467 | ioctl (serial_port, TIOCMSET, &mcs); 468 | } 469 | } 470 | } 471 | 472 | void serialport_set_rts(unsigned char val) 473 | { 474 | int mcs; 475 | 476 | if(serial_port) 477 | { 478 | ioctl (serial_port, TIOCMGET, &mcs); 479 | 480 | if(val) 481 | { 482 | mcs |= TIOCM_RTS; 483 | ioctl (serial_port, TIOCMSET, &mcs); 484 | } 485 | else 486 | { 487 | mcs &= ~TIOCM_RTS; 488 | ioctl (serial_port, TIOCMSET, &mcs); 489 | } 490 | } 491 | } 492 | 493 | void serialport_send_break() 494 | { 495 | tcsendbreak(serial_port, 0); 496 | } 497 | 498 | 499 | 500 | #endif 501 | static unsigned char subst_C0[2] = { 0xDB, 0xDC }; 502 | static unsigned char subst_DB[2] = { 0xDB, 0xDD }; 503 | 504 | #define STATIC_SLIP_BUF_SIZE 4096 505 | int serialport_send_slip_static(unsigned char *data, unsigned int size) 506 | { 507 | unsigned char buf[STATIC_SLIP_BUF_SIZE]; 508 | unsigned out_pos = 0; 509 | for (int i = 0; i < size; ++i) 510 | { 511 | unsigned char cur = data[i]; 512 | if (cur == 0xC0) 513 | { 514 | buf[out_pos++] = subst_C0[0]; 515 | buf[out_pos++] = subst_C0[1]; 516 | } 517 | else if (cur == 0xDB) 518 | { 519 | buf[out_pos++] = subst_DB[0]; 520 | buf[out_pos++] = subst_DB[1]; 521 | } 522 | else 523 | buf[out_pos++] = cur; 524 | } 525 | 526 | if(serialport_write(buf, out_pos) != out_pos) 527 | { 528 | LOGERR("failed sending %d bytes", out_pos); 529 | return 0; 530 | } 531 | serialport_drain(); 532 | return size; 533 | } 534 | 535 | int serialport_send_slip(unsigned char *data, unsigned int size) 536 | { 537 | unsigned int sent; 538 | unsigned char cur_byte; 539 | 540 | if (size < STATIC_SLIP_BUF_SIZE / 2) 541 | return serialport_send_slip_static(data, size); 542 | 543 | sent = 0; 544 | 545 | while(sent != size) 546 | { 547 | cur_byte = *data++; 548 | if(cur_byte == 0xC0) 549 | { 550 | if(serialport_write(subst_C0, 2) != 2) 551 | { 552 | LOGERR("failed substituting 0xC0"); 553 | return 0; 554 | } 555 | } 556 | else if(cur_byte == 0xDB) 557 | { 558 | if(serialport_write(subst_DB, 2) != 2) 559 | { 560 | LOGERR("failed substituting 0xDB"); 561 | return 0; 562 | } 563 | } 564 | else 565 | { 566 | if(serialport_write(&cur_byte, 1) != 1) 567 | { 568 | LOGERR("failed sending byte %i", sent); 569 | return 0; 570 | } 571 | } 572 | sent++; 573 | } 574 | 575 | serialport_drain(); 576 | 577 | return sent; 578 | } 579 | 580 | int serialport_receive_slip(unsigned char *data, unsigned int size) 581 | { 582 | unsigned int received; 583 | unsigned char cur_byte; 584 | 585 | received = 0; 586 | 587 | while(received != size) 588 | { 589 | if(serialport_read(&cur_byte, 1) != 1) 590 | { 591 | LOGERR("failed reading byte"); 592 | return 0; 593 | } 594 | 595 | if(cur_byte == 0xDB) 596 | { 597 | if(serialport_read(&cur_byte, 1) != 1) 598 | { 599 | LOGERR("failed reading byte for unslip"); 600 | return 0; 601 | } 602 | 603 | if(cur_byte == 0xDC) 604 | { 605 | *data++ = 0xC0; 606 | } 607 | else if(cur_byte == 0xDD) 608 | { 609 | *data++ = 0xDB; 610 | } 611 | else 612 | { 613 | LOGERR("unslip sequence wrong"); 614 | return 0; 615 | } 616 | } 617 | else 618 | { 619 | *data++ = cur_byte; 620 | } 621 | 622 | received++; 623 | } 624 | 625 | return received; 626 | } 627 | 628 | int serialport_send_C0(void) 629 | { 630 | unsigned char b; 631 | 632 | b = 0xC0; 633 | 634 | if(serialport_write(&b, 1) != 1) 635 | { 636 | LOGERR("failed sending 0xC0"); 637 | return 0; 638 | } 639 | serialport_drain(); 640 | return 1; 641 | } 642 | 643 | int serialport_receive_C0(void) 644 | { 645 | unsigned char b; 646 | 647 | b = 0x00; 648 | 649 | if(serialport_read(&b, 1) != 1) 650 | { 651 | return 0; 652 | } 653 | 654 | if(b != 0xC0) 655 | { 656 | LOGDEBUG("serialport_receive_C0: %02X instead of C0", b); 657 | return 0; 658 | } 659 | 660 | return 1; 661 | } 662 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /espcomm/espcomm.c: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | ********************************************************************************** 3 | *** 4 | *** espcomm.c 5 | *** - routines to access the bootloader in the ESP 6 | *** 7 | *** Copyright (C) 2014 Christian Klippel 8 | *** 9 | *** This program is free software; you can redistribute it and/or modify 10 | *** it under the terms of the GNU General Public License as published by 11 | *** the Free Software Foundation; either version 2 of the License, or 12 | *** (at your option) any later version. 13 | *** 14 | *** This program is distributed in the hope that it will be useful, 15 | *** but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | *** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | *** GNU General Public License for more details. 18 | *** 19 | *** You should have received a copy of the GNU General Public License along 20 | *** with this program; if not, write to the Free Software Foundation, Inc., 21 | *** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | *** 23 | **/ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "infohelper.h" 36 | #include "espcomm.h" 37 | #include "serialport.h" 38 | #include "espcomm_boards.h" 39 | #include "delay.h" 40 | 41 | const int progress_line_width = 80; 42 | 43 | bootloader_packet send_packet; 44 | bootloader_packet receive_packet; 45 | 46 | static espcomm_board_t* espcomm_board = 0; 47 | static bool sync_stage = false; 48 | static bool upload_stage = false; 49 | static bool espcomm_is_open = false; 50 | 51 | static const char *espcomm_port = 52 | #if defined(__APPLE__) && defined(__MACH__) 53 | "/dev/tty.usbserial"; 54 | #elif defined(_WIN32) 55 | "COM1"; 56 | #elif defined(__linux__) 57 | "/dev/ttyUSB0"; 58 | #else 59 | ""; 60 | #endif 61 | 62 | static unsigned int espcomm_baudrate = 115200; 63 | static uint32_t espcomm_address = 0x00000; 64 | 65 | static unsigned char sync_frame[36] = { 0x07, 0x07, 0x12, 0x20, 66 | 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 67 | 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 68 | 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 69 | 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }; 70 | 71 | static uint32_t flash_packet[BLOCKSIZE_FLASH+32]; 72 | static uint32_t ram_packet[BLOCKSIZE_RAM+32]; 73 | 74 | static int file_uploaded = 0; 75 | 76 | static void espcomm_enter_boot(void) 77 | { 78 | espcomm_board_reset_into_bootloader(espcomm_board); 79 | } 80 | 81 | static void espcomm_reset_to_exec(void) 82 | { 83 | espcomm_board_reset_into_app(espcomm_board); 84 | } 85 | 86 | uint32_t espcomm_calc_checksum(unsigned char *data, uint16_t data_size) 87 | { 88 | uint16_t cnt; 89 | uint32_t result; 90 | 91 | result = 0xEF; 92 | 93 | for(cnt = 0; cnt < data_size; cnt++) 94 | { 95 | result ^= data[cnt]; 96 | } 97 | 98 | return result; 99 | } 100 | 101 | static uint32_t espcomm_send_command(unsigned char command, unsigned char *data, uint16_t data_size, int reply_timeout) 102 | { 103 | uint32_t result; 104 | uint32_t cnt; 105 | 106 | result = 0; 107 | if (command != NO_COMMAND) 108 | { 109 | send_packet.direction = 0x00; 110 | send_packet.command = command; 111 | send_packet.size = data_size; 112 | 113 | serialport_send_C0(); 114 | 115 | if (!upload_stage) 116 | LOGDEBUG("espcomm_send_command: sending command header"); 117 | else 118 | LOGVERBOSE("espcomm_send_command: sending command header"); 119 | 120 | serialport_send_slip((unsigned char*) &send_packet, 8); 121 | 122 | if(data_size) 123 | { 124 | if (!upload_stage) 125 | LOGDEBUG("espcomm_send_command: sending command payload"); 126 | else 127 | LOGVERBOSE("espcomm_send_command: sending command payload"); 128 | serialport_send_slip(data, data_size); 129 | } 130 | else 131 | { 132 | LOGDEBUG("espcomm_send_command: no payload"); 133 | } 134 | 135 | serialport_send_C0(); 136 | } 137 | 138 | espcomm_delay_ms(5); 139 | serialport_drain(); 140 | 141 | int old_timeout = 0; 142 | if (reply_timeout) 143 | { 144 | old_timeout = serialport_get_timeout(); 145 | serialport_set_timeout(reply_timeout); 146 | } 147 | 148 | if(serialport_receive_C0()) 149 | { 150 | if (old_timeout) 151 | serialport_set_timeout(old_timeout); 152 | 153 | if(serialport_receive_slip((unsigned char*) &receive_packet, 8)) 154 | { 155 | if(receive_packet.size) 156 | { 157 | if (!upload_stage) 158 | LOGDEBUG("espcomm_send_command: receiving %i bytes of data", receive_packet.size); 159 | else 160 | LOGVERBOSE("espcomm_send_command: receiving %i bytes of data", receive_packet.size); 161 | 162 | if(receive_packet.data) 163 | { 164 | free(receive_packet.data); 165 | receive_packet.data = NULL; 166 | } 167 | 168 | receive_packet.data = malloc(receive_packet.size); 169 | 170 | if(serialport_receive_slip(receive_packet.data, receive_packet.size) == 0) 171 | { 172 | LOGWARN("espcomm_send_command: can't receive slip payload data"); 173 | return 0; 174 | } 175 | else 176 | { 177 | LOGVERBOSE("espcomm_send_command: received %x bytes: ", receive_packet.size); 178 | for(cnt = 0; cnt < receive_packet.size; cnt++) 179 | { 180 | LOGVERBOSE("0x%02X ", receive_packet.data[cnt]); 181 | } 182 | } 183 | } 184 | 185 | if(serialport_receive_C0()) 186 | { 187 | if(receive_packet.direction == 0x01 && 188 | (command == NO_COMMAND || receive_packet.command == command)) 189 | { 190 | result = receive_packet.response; 191 | } 192 | else 193 | { 194 | LOGWARN("espcomm_send_command: wrong direction/command: 0x%02X 0x%02X, expected 0x%02X 0x%02X", 195 | receive_packet.direction, receive_packet.command, 1, command); 196 | return 0; 197 | } 198 | } 199 | else 200 | { 201 | if (!sync_stage) 202 | LOGWARN("espcomm_send_command: no final C0"); 203 | else 204 | LOGVERBOSE("espcomm_send_command: no final C0"); 205 | return 0; 206 | } 207 | } 208 | else 209 | { 210 | LOGWARN("espcomm_send_command: can't receive command response header"); 211 | return 0; 212 | } 213 | } 214 | else 215 | { 216 | if (old_timeout) 217 | serialport_set_timeout(old_timeout); 218 | 219 | if (!sync_stage) 220 | LOGWARN("espcomm_send_command: didn't receive command response"); 221 | else 222 | LOGVERBOSE("espcomm_send_command: didn't receive command response"); 223 | return 0; 224 | } 225 | 226 | LOGVERBOSE("espcomm_send_command: response 0x%08X", result); 227 | return result; 228 | } 229 | 230 | 231 | static int espcomm_sync(void) 232 | { 233 | sync_stage = true; 234 | for (int retry_boot = 0; retry_boot < 3; ++retry_boot) 235 | { 236 | LOGINFO("resetting board"); 237 | espcomm_enter_boot(); 238 | for (int retry_sync = 0; retry_sync < 3; ++retry_sync) 239 | { 240 | LOGINFO("trying to connect"); 241 | espcomm_delay_ms(100); 242 | serialport_flush(); 243 | 244 | send_packet.checksum = espcomm_calc_checksum((unsigned char*)&sync_frame, 36); 245 | if(espcomm_send_command(SYNC_FRAME, (unsigned char*) &sync_frame, 36, 0) == 0x20120707) 246 | { 247 | bool error = false; 248 | for (int i = 0; i < 7; ++i) 249 | { 250 | if (espcomm_send_command(NO_COMMAND, 0, 0, 0) != 0x20120707) 251 | { 252 | error = true; 253 | break; 254 | } 255 | } 256 | if (!error) 257 | { 258 | sync_stage = false; 259 | return 1; 260 | } 261 | } 262 | } 263 | } 264 | sync_stage = false; 265 | LOGWARN("espcomm_sync failed"); 266 | return 0; 267 | } 268 | 269 | int espcomm_open(void) 270 | { 271 | if (espcomm_is_open) 272 | return 1; 273 | 274 | if(serialport_open(espcomm_port, espcomm_baudrate)) 275 | { 276 | LOGINFO("opening bootloader"); 277 | if (espcomm_sync()) 278 | { 279 | espcomm_is_open = true; 280 | return 1; 281 | } 282 | } 283 | 284 | return 0; 285 | } 286 | 287 | void espcomm_close(void) 288 | { 289 | LOGINFO("closing bootloader"); 290 | serialport_close(); 291 | } 292 | 293 | int espcomm_set_flash_params(uint32_t device_id, uint32_t chip_size, 294 | uint32_t block_size, uint32_t sector_size, 295 | uint32_t page_size, uint32_t status_mask) 296 | { 297 | LOGDEBUG("espcomm_set_flash_params: %x %x %x %x %x %x", device_id, chip_size, 298 | block_size, sector_size, page_size, status_mask); 299 | 300 | flash_packet[0] = device_id; 301 | flash_packet[1] = chip_size; 302 | flash_packet[2] = block_size; 303 | flash_packet[3] = sector_size; 304 | flash_packet[4] = page_size; 305 | flash_packet[5] = status_mask; 306 | 307 | send_packet.checksum = espcomm_calc_checksum((unsigned char*) flash_packet, 24); 308 | 309 | uint32_t res = espcomm_send_command(SET_FLASH_PARAMS, (unsigned char*) &flash_packet, 24, 0); 310 | return res; 311 | } 312 | 313 | int espcomm_start_flash(uint32_t size, uint32_t address) 314 | { 315 | uint32_t res; 316 | 317 | LOGDEBUG("size: %06x address: %06x", size, address); 318 | 319 | uint32_t min_chip_size = size + address; 320 | uint32_t chip_size = 0x400000; 321 | /* Opportunistically assume that the flash chip size is sufficient. 322 | Todo: detect flash chip size using a stub */ 323 | if (min_chip_size > 0x1000000) { 324 | LOGWARN("Invalid size/address, too large: %x %x", size, address); 325 | return 0; 326 | } 327 | if (min_chip_size > 0x800000) { 328 | chip_size = 0x1000000; 329 | } else if (min_chip_size > 0x400000) { 330 | chip_size = 0x800000; 331 | } 332 | 333 | if (chip_size > 0x400000) { 334 | LOGINFO("Assuming flash chip size=%dMB", chip_size / 0x100000); 335 | res = espcomm_set_flash_params(0, chip_size, 64*1024, 16*1024, 256, 0xffff); 336 | if (res == 0) 337 | { 338 | LOGWARN("espcomm_send_command(SET_FLASH_PARAMS) failed"); 339 | return res; 340 | } 341 | } 342 | 343 | const int sector_size = 4096; 344 | const int sectors_per_block = 16; 345 | const int first_sector_index = address / sector_size; 346 | LOGDEBUG("first_sector_index: %d", first_sector_index); 347 | 348 | const int total_sector_count = ((size % sector_size) == 0) ? 349 | (size / sector_size) : (size / sector_size + 1); 350 | LOGDEBUG("total_sector_count: %d", total_sector_count); 351 | 352 | const int max_head_sector_count = sectors_per_block - (first_sector_index % sectors_per_block); 353 | const int head_sector_count = (max_head_sector_count > total_sector_count) ? 354 | total_sector_count : max_head_sector_count; 355 | LOGDEBUG("head_sector_count: %d", head_sector_count); 356 | 357 | // SPIEraseArea function in the esp8266 ROM has a bug which causes extra area to be erased. 358 | // If the address range to be erased crosses the block boundary, 359 | // then extra head_sector_count sectors are erased. 360 | // If the address range doesn't cross the block boundary, 361 | // then extra total_sector_count sectors are erased. 362 | 363 | const int adjusted_sector_count = (total_sector_count > 2 * head_sector_count) ? 364 | (total_sector_count - head_sector_count): 365 | (total_sector_count + 1) / 2; 366 | LOGDEBUG("adjusted_sector_count: %d", adjusted_sector_count); 367 | 368 | uint32_t erase_size = adjusted_sector_count * sector_size; 369 | 370 | LOGDEBUG("erase_size: %06x", erase_size); 371 | 372 | flash_packet[0] = erase_size; 373 | flash_packet[1] = (size + BLOCKSIZE_FLASH - 1) / BLOCKSIZE_FLASH; 374 | flash_packet[2] = BLOCKSIZE_FLASH; 375 | flash_packet[3] = address; 376 | 377 | send_packet.checksum = espcomm_calc_checksum((unsigned char*) flash_packet, 16); 378 | 379 | int delay_per_erase_block_ms = 7; 380 | int timeout_ms = erase_size / BLOCKSIZE_FLASH * delay_per_erase_block_ms + 5000; 381 | if (timeout_ms < 15000) timeout_ms = 15000; 382 | //LOGDEBUG("calculated erase delay: %dms = max(%db / %db * %dms + 5000, 15000)", timeout_ms, erase_size, BLOCKSIZE_FLASH, delay_per_erase_block_ms); 383 | res = espcomm_send_command(FLASH_DOWNLOAD_BEGIN, (unsigned char*) &flash_packet, 16, timeout_ms); 384 | return res; 385 | } 386 | 387 | bool espcomm_upload_mem(uint8_t* src, size_t size, const char* source_name) 388 | { 389 | LOGDEBUG("espcomm_upload_mem"); 390 | if(!espcomm_open()) 391 | { 392 | LOGERR("espcomm_open failed"); 393 | return false; 394 | } 395 | 396 | INFO("Uploading %i bytes from %s to flash at 0x%08X\n", size, source_name, espcomm_address); 397 | LOGDEBUG("erasing flash"); 398 | int res = espcomm_start_flash(size, espcomm_address); 399 | if (res == 0) 400 | { 401 | LOGWARN("espcomm_send_command(FLASH_DOWNLOAD_BEGIN) failed"); 402 | espcomm_close(); 403 | return false; 404 | } 405 | 406 | LOGDEBUG("writing flash"); 407 | upload_stage = true; 408 | size_t total_count = (size + BLOCKSIZE_FLASH - 1) / BLOCKSIZE_FLASH; 409 | size_t count = 0; 410 | while(size) 411 | { 412 | flash_packet[0] = BLOCKSIZE_FLASH; 413 | flash_packet[1] = count; 414 | flash_packet[2] = 0; 415 | flash_packet[3] = 0; 416 | 417 | memset(flash_packet + 4, 0xff, BLOCKSIZE_FLASH); 418 | 419 | size_t write_size = (size < BLOCKSIZE_FLASH)?size:BLOCKSIZE_FLASH; 420 | memcpy(flash_packet + 4, src, write_size); 421 | size -= write_size; 422 | src += write_size; 423 | 424 | send_packet.checksum = espcomm_calc_checksum((unsigned char *) (flash_packet + 4), BLOCKSIZE_FLASH); 425 | res = espcomm_send_command(FLASH_DOWNLOAD_DATA, (unsigned char*) flash_packet, BLOCKSIZE_FLASH + 16, 0); 426 | 427 | if(res == 0) 428 | { 429 | LOGWARN("espcomm_send_command(FLASH_DOWNLOAD_DATA) failed"); 430 | res = espcomm_send_command(FLASH_DOWNLOAD_DONE, (unsigned char*) flash_packet, 4, 0); 431 | espcomm_close(); 432 | upload_stage = false; 433 | return false; 434 | } 435 | 436 | ++count; 437 | INFO("."); 438 | if (count % progress_line_width == 0) { 439 | INFO(" [ %2d%% ]\n", count * 100 / total_count); 440 | } 441 | fflush(stdout); 442 | } 443 | if (count % progress_line_width) { 444 | while (++count % progress_line_width) { 445 | INFO(" "); 446 | } 447 | INFO(" [ 100%% ]\n"); 448 | } 449 | upload_stage = false; 450 | file_uploaded = 1; 451 | return true; 452 | } 453 | 454 | bool espcomm_upload_mem_to_RAM(uint8_t* src, size_t size, int address, int entry) 455 | { 456 | LOGDEBUG("espcomm_upload_mem_to_RAM"); 457 | if(!espcomm_open()) 458 | { 459 | LOGERR("espcomm_open failed"); 460 | return false; 461 | } 462 | 463 | INFO("Uploading %i bytes to RAM at 0x%08X\n", size, address); 464 | 465 | ram_packet[0] = size; 466 | ram_packet[1] = 0x00000200; 467 | ram_packet[2] = BLOCKSIZE_RAM; 468 | ram_packet[3] = address; 469 | 470 | send_packet.checksum = espcomm_calc_checksum((unsigned char*) ram_packet, 16); 471 | int res = espcomm_send_command(RAM_DOWNLOAD_BEGIN, (unsigned char*) &ram_packet, 16, 0); 472 | if (res == 0) 473 | { 474 | LOGWARN("espcomm_send_command(RAM_DOWNLOAD_BEGIN) failed"); 475 | espcomm_close(); 476 | return false; 477 | } 478 | 479 | LOGDEBUG("writing to RAM"); 480 | upload_stage = true; 481 | size_t count = 0; 482 | while(size) 483 | { 484 | size_t will_write = (size < BLOCKSIZE_RAM)?size:BLOCKSIZE_RAM; 485 | will_write = (will_write + 3) & (~3); 486 | 487 | ram_packet[0] = will_write; 488 | ram_packet[1] = count; 489 | ram_packet[2] = 0; 490 | ram_packet[3] = 0; 491 | 492 | memset(ram_packet + 4, 0xff, BLOCKSIZE_RAM); 493 | 494 | size_t write_size = (size < BLOCKSIZE_RAM)?size:BLOCKSIZE_RAM; 495 | memcpy(ram_packet + 4, src, write_size); 496 | size -= write_size; 497 | src += write_size; 498 | 499 | send_packet.checksum = espcomm_calc_checksum((unsigned char *) (ram_packet + 4), will_write); 500 | res = espcomm_send_command(RAM_DOWNLOAD_DATA, (unsigned char*) ram_packet, will_write + 16, 0); 501 | 502 | if(res == 0) 503 | { 504 | LOGWARN("espcomm_send_command(RAM_DOWNLOAD_DATA) failed"); 505 | espcomm_close(); 506 | upload_stage = false; 507 | return false; 508 | } 509 | ++count; 510 | INFO("."); 511 | fflush(stdout); 512 | } 513 | upload_stage = false; 514 | INFO("\n"); 515 | ram_packet[0] = (entry)?0:1; 516 | ram_packet[1] = entry; 517 | send_packet.checksum = 0; 518 | res = espcomm_send_command(RAM_DOWNLOAD_END, (unsigned char*) ram_packet, 8, 0); 519 | return true; 520 | } 521 | 522 | bool espcomm_upload_file(const char *name) 523 | { 524 | LOGDEBUG("espcomm_upload_file"); 525 | struct stat st; 526 | if(stat(name, &st) != 0) 527 | { 528 | LOGERR("stat %s failed: %s", name, strerror(errno)); 529 | return false; 530 | } 531 | 532 | FILE* f = fopen(name, "rb"); 533 | if (!f) 534 | { 535 | LOGERR("failed to open file for reading"); 536 | return false; 537 | } 538 | 539 | uint8_t* file_contents = (uint8_t*) malloc(st.st_size); 540 | if (!file_contents) 541 | { 542 | LOGERR("failed to allocate buffer for file contents"); 543 | fclose(f); 544 | return false; 545 | } 546 | 547 | size_t cb = fread(file_contents, 1, st.st_size, f); 548 | fclose(f); 549 | 550 | if (cb != st.st_size) 551 | { 552 | LOGERR("failed to read file contents"); 553 | free(file_contents); 554 | return false; 555 | } 556 | 557 | if (!espcomm_upload_mem(file_contents, st.st_size, name)) 558 | { 559 | LOGERR("espcomm_upload_mem failed"); 560 | free(file_contents); 561 | return false; 562 | } 563 | 564 | free(file_contents); 565 | return true; 566 | } 567 | 568 | bool espcomm_erase_region(const char* size) 569 | { 570 | uint32_t erase_size = (uint32_t) strtol(size, NULL, 16); 571 | LOGDEBUG("setting erase size to 0x%08X",erase_size); 572 | 573 | if(!espcomm_open()) 574 | { 575 | LOGERR("espcomm_open failed"); 576 | return false; 577 | } 578 | 579 | INFO("Erasing 0x%X bytes starting at 0x%08X\n", erase_size, espcomm_address); 580 | LOGDEBUG("erasing flash"); 581 | int res = espcomm_start_flash(erase_size, espcomm_address); 582 | if (res == 0) 583 | { 584 | LOGWARN("espcomm_send_command(FLASH_DOWNLOAD_BEGIN) failed"); 585 | espcomm_close(); 586 | return false; 587 | } 588 | 589 | return true; 590 | } 591 | 592 | int espcomm_start_app(int reboot) 593 | { 594 | if(!espcomm_open()) 595 | { 596 | LOGDEBUG("espcomm_open failed"); 597 | } 598 | 599 | if (reboot) 600 | { 601 | LOGINFO("starting app with reboot"); 602 | flash_packet[0] = 0; 603 | } 604 | else 605 | { 606 | LOGINFO("starting app without reboot"); 607 | flash_packet[0] = 1; 608 | } 609 | 610 | espcomm_send_command(FLASH_DOWNLOAD_DONE, (unsigned char*) &flash_packet, 4, 0); 611 | file_uploaded = 0; 612 | 613 | espcomm_close(); 614 | return 1; 615 | } 616 | 617 | int espcomm_file_uploaded() 618 | { 619 | return file_uploaded; 620 | } 621 | 622 | int espcomm_set_port(char *port) 623 | { 624 | LOGDEBUG("setting port from %s to %s", espcomm_port, port); 625 | espcomm_port = port; 626 | return 1; 627 | } 628 | 629 | int espcomm_set_baudrate(const char *baudrate) 630 | { 631 | uint32_t new_baudrate = (uint32_t) strtol(baudrate, NULL, 10); 632 | LOGDEBUG("setting baudrate from %i to %i", espcomm_baudrate, new_baudrate); 633 | espcomm_baudrate = new_baudrate; 634 | return 1; 635 | } 636 | 637 | int espcomm_set_address(const char *address) 638 | { 639 | uint32_t new_address = (uint32_t) strtol(address, NULL, 16); 640 | LOGDEBUG("setting address from 0x%08X to 0x%08X", espcomm_address, new_address); 641 | espcomm_address = new_address; 642 | return 1; 643 | } 644 | 645 | int espcomm_set_board(const char* name) 646 | { 647 | LOGDEBUG("setting board to %s", name); 648 | espcomm_board = espcomm_board_by_name(name); 649 | if (!espcomm_board) 650 | { 651 | LOGERR("unknown board: %s", name); 652 | INFO("known boards are: "); 653 | for (espcomm_board_t* b = espcomm_board_first(); b; b = espcomm_board_next(b)) 654 | { 655 | INFO("%s ", espcomm_board_name(b)); 656 | } 657 | INFO("\n"); 658 | return 0; 659 | } 660 | return 1; 661 | } 662 | 663 | bool espcomm_erase_flash() 664 | { 665 | LOGDEBUG("espcomm_erase_flash"); 666 | if(!espcomm_open()) 667 | { 668 | LOGERR("espcomm_open failed"); 669 | return false; 670 | } 671 | 672 | flash_packet[0] = 0; 673 | flash_packet[1] = 0x00000200; 674 | flash_packet[2] = BLOCKSIZE_FLASH; 675 | flash_packet[3] = 0; 676 | send_packet.checksum = espcomm_calc_checksum((unsigned char*) flash_packet, 16); 677 | int res = espcomm_send_command(FLASH_DOWNLOAD_BEGIN, (unsigned char*) &flash_packet, 16, 1000); 678 | if (res == 0) 679 | { 680 | LOGERR("espcomm_erase_flash: FLASH_DOWNLOAD_BEGIN failed"); 681 | return false; 682 | } 683 | 684 | ram_packet[0] = 0; 685 | ram_packet[1] = 0x00000200; 686 | ram_packet[2] = BLOCKSIZE_RAM; 687 | ram_packet[3] = 0x40100000; 688 | 689 | send_packet.checksum = espcomm_calc_checksum((unsigned char*) ram_packet, 16); 690 | res = espcomm_send_command(RAM_DOWNLOAD_BEGIN, (unsigned char*) &ram_packet, 16, 0); 691 | if (res == 0) 692 | { 693 | LOGERR("espcomm_erase_flash: RAM_DOWNLOAD_BEGIN failed"); 694 | return false; 695 | } 696 | 697 | ram_packet[0] = 0; 698 | ram_packet[1] = 0x40004984; 699 | send_packet.checksum = 0; 700 | espcomm_send_command(RAM_DOWNLOAD_END, (unsigned char*) ram_packet, 8, 0); 701 | return true; 702 | } 703 | 704 | bool espcomm_reset() 705 | { 706 | LOGDEBUG("espcomm_reset"); 707 | if (!espcomm_is_open) 708 | { 709 | LOGDEBUG("espcomm_reset: opening port"); 710 | if (!serialport_open(espcomm_port, espcomm_baudrate)) 711 | { 712 | LOGERR("espcomm_reset: failed to open port"); 713 | return false; 714 | } 715 | } 716 | espcomm_reset_to_exec(); 717 | return true; 718 | } 719 | --------------------------------------------------------------------------------