Inital english version commit

master
Robert Zaage 2 years ago
parent bf43faa4b5
commit e701ca2b74

@ -2,17 +2,17 @@ CC = gcc
LIBS = -lz LIBS = -lz
#BUILDNO = `cat build` #BUILDNO = `cat build`
BUILDNO=$(shell cat build) BUILDNO=$(shell cat build)
CFLAGS = -O2 -Wunused -Wno-unused-result -D BUILDNO=$(BUILDNO) -D_7ZIP_ST $(LIBS) CFLAGS = -O2 -Wunused -Wno-unused-result -D BUILDNO=$(BUILDNO) -D_7ZIP_ST $(LIBS)
.PHONY: all clean .PHONY: all clean
all: balong_flash all: balong_flash
clean: clean:
rm -f *.o lzma/*.o rm -f *.o lzma/*.o
rm -f balong_flash rm -f balong_flash
balong_flash: balong_flash.o hdlcio_linux.o ptable.o flasher.o util.o signver.o lzma/Alloc.o lzma/LzmaDec.o balong_flash: balong_flash.o hdlcio_linux.o ptable.o flasher.o util.o signver.o lzma/Alloc.o lzma/LzmaDec.o
@gcc $^ -o $@ $(LIBS) @gcc $^ -o $@ $(LIBS)
@echo Current buid: $(BUILDNO) @echo Current buid: $(BUILDNO)
@echo $$((`cat build`+1)) >build @echo $$((`cat build`+1)) >build

@ -1,22 +1,11 @@
# balongflash # balong-flash
## Russian
Программа для прошивки модемов и LTE-маршрутизаторов фирмы Huawei на чипсете Balong V7.
Эта утилита предназначена для прошивания BIN- и EXE-файлов прошивок из режима загрузки, а также набора файлов прошивки из указанной директории. Файл прошивки может быть разобран на составные части с заголовком и без. Файлы прошивок могут быть с цифровой подписью и без нее.
**Эта утилита может вывести ваше устройство из строя!**
Используйте ее, только если осознаете все риски и последствия. В случае каких-либо возникших проблем, не ждите помощи, рассчитывайте только на свои собственные силы.
## English
Huawei Balong V7 modem and LTE router flashing utility. Huawei Balong V7 modem and LTE router flashing utility.
This program is used to flash BIN and EXE firmware files to device in download mode. It also supports flashing separate firmware components from selected directory. Firmware files could be extracted to separate files with header and without it. Both files with and without digital signature supported. This program is used to flash BIN and EXE firmware files to device in download mode.
It also supports flashing separate firmware components from selected directory.
This software is in Russian only. Use machine translation if needed. Firmware files could be extracted to separate files with header and without it.
Please ask questions only about the program itself. No questions about devices, boot pins, loaders, backups allowed. Both files with and without digital signature supported.
**This utility can make your device unbootable!** **This utility can make your device unbootable!**
Use it only if you fully understand all risks and consequences. In case of any issues, you're on your own. Do not expect any help. Use it only if you fully understand all risks and consequences. In case of any issues, you're on your own. Do not expect any help.

@ -24,22 +24,22 @@
#include "signver.h" #include "signver.h"
#include "zlib.h" #include "zlib.h"
// флаг ошибки структуры файла // file structure error flag
unsigned int errflag=0; unsigned int errflag=0;
// флаг цифровой подписи // digital signature flag
int gflag=0; int gflag=0;
// флаг типа прошивки // firmware type flag
int dflag=0; int dflag=0;
// тип прошивки из заголовка файла // firmware type from file header
int dload_id=-1; int dload_id=-1;
//*********************************************** //***********************************************
//* Таблица разделов //* Partition table
//*********************************************** //***********************************************
struct ptb_t ptable[120]; struct ptb_t ptable[120];
int npart=0; // число разделов в таблице int npart=0; // number of partitions in the table
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ -51,33 +51,33 @@ int res;
FILE* in; FILE* in;
char devname[50] = ""; char devname[50] = "";
unsigned int mflag=0,eflag=0,rflag=0,sflag=0,nflag=0,kflag=0,fflag=0; unsigned int mflag=0,eflag=0,rflag=0,sflag=0,nflag=0,kflag=0,fflag=0;
unsigned char fdir[40]; // каталог для мультифайловой прошивки unsigned char fdir[40]; // directory for multi-file firmware
// разбор командной строки // command line parsing
while ((opt = getopt(argc, argv, "d:hp:mersng:kf")) != -1) { while ((opt = getopt(argc, argv, "d:hp:mersng:kf")) != -1) {
switch (opt) { switch (opt) {
case 'h': case 'h':
printf("\n Утилита предназначена для прошивки модемов на чипсете Balong V7\n\n\ printf("\n This utility is intended for flashing modems with a Balong V7 chipset\n\n\
%s [ключи] <имя файла для загрузки или имя каталога с файлами>\n\n\ %s [options] <boot file name or directory name>\n\n\
Допустимы следующие ключи:\n\n" Following options are allowed:\n\n"
#ifndef WIN32 #ifndef WIN32
"-p <tty> - последовательный порт для общения с загрузчиком (по умолчанию /dev/ttyUSB0)\n" "-p <tty> - Serial port for communicating with the bootloader (by default /dev/ttyUSB0)\n"
#else #else
"-p # - номер последовательного порта для общения с загрузчиком (например, -p8)\n" "-p # - Number of the serial port for communicating with the loader (e.g. -p8)\n"
" если ключ -p не указан, производится автоопределение порта\n" " if the -p option is not specified, the port is auto-detected\n"
#endif #endif
"-n - режим мультифайловой прошивки из указанного каталога\n\ "-n - Multi-file firmware from a specified directory\n\
-g# - установка режима цифровой подписи\n\ -g# - Set digital signature mode\n\
-gl - описание параметров\n\ -gl - parameter definition\n\
-gd - запрет автоопределения подписи\n\ -gd - disable signature autodetection\n\
-m - вывести карту файла прошивки и завершить работу\n\ -m - Display the firmware file map and exit\n\
-e - разобрать файл прошивки на разделы без заголовков\n\ -e - Disassemble the firmware file into partitions without headers\n\
-s - разобрать файл прошивки на разделы с заголовками\n\ -s - Disassemble the firmware file into partitions with headers\n\
-k - не перезагружать модем по окончании прошивки\n\ -k - Don't restart the modem after flashing\n\
-r - принудительно перезагрузить модем без прошивки разделов\n\ -r - Force reboot of the modem without flashing partitions\n\
-f - прошить даже при наличии ошибок CRC в исходном файле\n\ -f - Flash even if there are CRC errors in the source file\n\
-d# - установка типа прошивки (DLOAD_ID, 0..7), -dl - список типов\n\ -d# - Set the firmware type (DLOAD_ID, 0...7), -dl - List of types\n\
\n",argv[0]); \n",argv[0]);
return 0; return 0;
@ -88,23 +88,23 @@ printf("\n Утилита предназначена для прошивки м
case 'm': case 'm':
mflag=1; mflag=1;
break; break;
case 'n': case 'n':
nflag=1; nflag=1;
break; break;
case 'f': case 'f':
fflag=1; fflag=1;
break; break;
case 'r': case 'r':
rflag=1; rflag=1;
break; break;
case 'k': case 'k':
kflag=1; kflag=1;
break; break;
case 'e': case 'e':
eflag=1; eflag=1;
break; break;
@ -116,85 +116,86 @@ printf("\n Утилита предназначена для прошивки м
case 'g': case 'g':
gparm(optarg); gparm(optarg);
break; break;
case 'd': case 'd':
dparm(optarg); dparm(optarg);
break; break;
case '?': case '?':
case ':': case ':':
return -1; return -1;
} }
} }
printf("\n Программа для прошивки устройств на Balong-чипсете, V3.0.%i, (c) forth32, 2015, GNU GPLv3",BUILDNO); printf("\n Program for flashing Balong-chipset devices, V3.0.%i, (c) forth32, 2015, GNU GPLv3\n",BUILDNO);
printf("English Version (c) robertzaage, 2022\n");
#ifdef WIN32 #ifdef WIN32
printf("\n Порт для Windows 32bit (c) rust3028, 2016"); printf("Windows Port 32bit (c) rust3028, 2016\n");
#endif #endif
printf("\n--------------------------------------------------------------------------------------------------\n"); printf("\n--------------------------------------------------------------------------------------------------\n");
if (eflag&sflag) { if (eflag&sflag) {
printf("\n Ключи -s и -e несовместимы\n"); printf("\n The -s and -e options are incompatible\n");
return -1; return -1;
} }
if (kflag&rflag) { if (kflag&rflag) {
printf("\n Ключи -k и -r несовместимы\n"); printf("\n The -k and -r options are incompatible\n");
return -1; return -1;
} }
if (nflag&(eflag|sflag|mflag)) { if (nflag&(eflag|sflag|mflag)) {
printf("\n Ключ -n несовместим с ключами -s, -m и -e\n"); printf("\n The -n option is incompatible with -s, -m, and -e options\n");
return -1; return -1;
} }
// ------ перезагрузка без указания файла // reboot without specifying a file
//-------------------------------------------- //--------------------------------------------
if ((optind>=argc)&rflag) goto sio; if ((optind>=argc)&rflag) goto sio;
// Открытие входного файла // open an input file
//-------------------------------------------- //--------------------------------------------
if (optind>=argc) { if (optind>=argc) {
if (nflag) if (nflag)
printf("\n - Не указан каталог с файлами\n"); printf("\n - Directory containing the files is not specified\n");
else else
printf("\n - Не указано имя файла для загрузки, используйте ключ -h для подсказки\n"); printf("\n - No file name specified, use the -h option to display help\n");
return -1; return -1;
} }
if (nflag) if (nflag)
// для -n - просто копируем префикс // for -n - just copy the prefix
strncpy(fdir,argv[optind],39); strncpy(fdir,argv[optind],39);
else { else {
// для однофайловых операций // for single-file operations
in=fopen(argv[optind],"rb"); in=fopen(argv[optind],"rb");
if (in == 0) { if (in == 0) {
printf("\n Ошибка открытия %s",argv[optind]); printf("\n Can't open file %s",argv[optind]);
return -1; return -1;
} }
} }
// Поиск разделов внутри файла // search for partitions within a file
if (!nflag) { if (!nflag) {
findparts(in); findparts(in);
show_fw_info(); show_fw_info();
} }
// Поиск файлов прошивок в указанном каталоге // search for firmware files in a specified directory
else findfiles(fdir); else findfiles(fdir);
//------ Режим вывода карты файла прошивки // firmware file map output
if (mflag) show_file_map(); if (mflag) show_file_map();
// выход по ошибкам CRC // CRC error ouput
if (!fflag && errflag) { if (!fflag && errflag) {
printf("\n\n! Входной файл содержит ошибки - завершаем работу\n"); printf("\n\n! Input file contains errors - exiting\n");
return -1; return -1;
} }
//------- Режим разрезания файла прошивки // split firmware file
if (eflag|sflag) { if (eflag|sflag) {
fwsplit(sflag); fwsplit(sflag);
printf("\n"); printf("\n");
@ -202,54 +203,51 @@ if (eflag|sflag) {
} }
sio: sio:
//--------- Основной режим - запись прошивки // standard procedure - flash firmware
//--------------------------------------------
// Настройка SIO // SIO setup
open_port(devname); open_port(devname);
// Определяем режим порта и версию dload-протокола // define port and dload protocol version
res=dloadversion(); res=dloadversion();
if (res == -1) return -2; if (res == -1) return -2;
if (res == 0) { if (res == 0) {
printf("\n Модем уже находится в HDLC-режиме"); printf("\n Modem is already in HDLC mode");
goto hdlc; goto hdlc;
} }
// Если надо, отправляем команду цифровой подписи // if necessary, send a digital signature command
if (gflag != -1) send_signver(); if (gflag != -1) send_signver();
// Входим в HDLC-режим // enter HDLC mode
usleep(100000); usleep(100000);
enter_hdlc(); enter_hdlc();
// Вошли в HDLC // we have entered HDLC mode
//------------------------------ //------------------------------
hdlc: hdlc:
// получаем версию протокола и идентификатор устройства // get the protocol version and the device identifier
protocol_version(); protocol_version();
dev_ident(); dev_ident();
printf("\n----------------------------------------------------\n"); printf("\n----------------------------------------------------\n");
if ((optind>=argc)&rflag) { if ((optind>=argc)&rflag) {
// перезагрузка без указания файла // reboot without pointing a file
restart_modem(); restart_modem();
exit(0); exit(0);
} }
// Записываем всю флешку // flash all memory
flash_all(); flash_all();
printf("\n"); printf("\n");
port_timeout(1); port_timeout(1);
// выходим из режима HDLC и перезагружаемся // exit HDLC mode and reboot
if (rflag || !kflag) restart_modem(); if (rflag || !kflag) restart_modem();
// выход из HDLC без перезагрузки // exit HDLC mode without rebooting
else leave_hdlc(); else leave_hdlc();
} }

@ -27,35 +27,34 @@
//*************************************************** //***************************************************
//* Хранилище кода ошибки //* Error code
//*************************************************** //***************************************************
int errcode; int errcode;
//*************************************************** //***************************************************
//* Вывод кода ошибки команды //* Error code output command
//*************************************************** //***************************************************
void printerr() { void printerr() {
if (errcode == -1) printf(" - таймаут команды\n"); if (errcode == -1) printf(" - Timeout\n");
else printf(" - код ошибки %02x\n",errcode); else printf(" - Error Code %02x\n",errcode);
} }
//*************************************************** //***************************************************
// Отправка команды начала раздела // Send partition start command
// //
// code - 32-битный код раздела // code - 32-bit partition code
// size - полный размер записываемого раздела // size - full size of the writable partition
// //
//* результат: //* result:
// false - ошибка // false - error
// true - команда принята модемом // true - command was accepted by the modem
//*************************************************** //***************************************************
int dload_start(uint32_t code,uint32_t size) { int dload_start(uint32_t code,uint32_t size) {
uint32_t iolen; uint32_t iolen;
uint8_t replybuf[4096]; uint8_t replybuf[4096];
#ifndef WIN32 #ifndef WIN32
static struct __attribute__ ((__packed__)) { static struct __attribute__ ((__packed__)) {
#else #else
@ -79,19 +78,19 @@ errcode=replybuf[3];
if ((iolen == 0) || (replybuf[1] != 2)) { if ((iolen == 0) || (replybuf[1] != 2)) {
if (iolen == 0) errcode=-1; if (iolen == 0) errcode=-1;
return false; return false;
} }
else return true; else return true;
} }
//*************************************************** //***************************************************
// Отправка блока раздела // Sending a partition block
// //
// blk - # блока // blk - # of block
// pimage - адрес начала образа раздела в памяти // pimage - address of the partition image start in memory
// //
//* результат: //* result:
// false - ошибка // false - error
// true - команда принята модемом // true - command was accepted by the modem
//*************************************************** //***************************************************
int dload_block(uint32_t part, uint32_t blk, uint8_t* pimage) { int dload_block(uint32_t part, uint32_t blk, uint8_t* pimage) {
@ -108,25 +107,25 @@ static struct {
uint32_t blk; uint32_t blk;
uint16_t bsize; uint16_t bsize;
uint8_t data[fblock]; uint8_t data[fblock];
} cmd_dload_block; } cmd_dload_block;
#ifdef WIN32 #ifdef WIN32
#pragma pack(pop) #pragma pack(pop)
#endif #endif
blksize=fblock; // начальное значение размера блока blksize=fblock; // initial block size value
res=ptable[part].hd.psize-blk*fblock; // размер оставшегося куска до конца файла res=ptable[part].hd.psize-blk*fblock; // size of the remaining chunk to the end of the file
if (res<fblock) blksize=res; // корректируем размер последнего блока if (res<fblock) blksize=res; // correct the size of the last block
// код команды // command code
cmd_dload_block.cmd=0x42; cmd_dload_block.cmd=0x42;
// номер блока // block number
cmd_dload_block.blk=htonl(blk+1); cmd_dload_block.blk=htonl(blk+1);
// размер блока // block size
cmd_dload_block.bsize=htons(blksize); cmd_dload_block.bsize=htons(blksize);
// порция данных из образа раздела // portion of data from the partition image
memcpy(cmd_dload_block.data,pimage+blk*fblock,blksize); memcpy(cmd_dload_block.data,pimage+blk*fblock,blksize);
// отсылаем блок в модем // send block to the modem
iolen=send_cmd((uint8_t*)&cmd_dload_block,sizeof(cmd_dload_block)-fblock+blksize,replybuf); // отсылаем команду iolen=send_cmd((uint8_t*)&cmd_dload_block,sizeof(cmd_dload_block)-fblock+blksize,replybuf); // send command
errcode=replybuf[3]; errcode=replybuf[3];
if ((iolen == 0) || (replybuf[1] != 2)) { if ((iolen == 0) || (replybuf[1] != 2)) {
@ -136,16 +135,15 @@ if ((iolen == 0) || (replybuf[1] != 2)) {
return true; return true;
} }
//*************************************************** //***************************************************
// Завершение записи раздела // End partition recording
// //
// code - код раздела // code - partition code
// size - размер раздела // size - size of partition
// //
//* результат: //* result:
// false - ошибка // false - error
// true - команда принята модемом // true - command was accepted by modem
//*************************************************** //***************************************************
int dload_end(uint32_t code, uint32_t size) { int dload_end(uint32_t code, uint32_t size) {
@ -177,51 +175,51 @@ errcode=replybuf[3];
if ((iolen == 0) || (replybuf[1] != 2)) { if ((iolen == 0) || (replybuf[1] != 2)) {
if (iolen == 0) errcode=-1; if (iolen == 0) errcode=-1;
return false; return false;
} }
return true; return true;
} }
//*************************************************** //***************************************************
//* Запись в модем всех разделов из таблицы //* Writing all partitions from table to the modem
//*************************************************** //***************************************************
void flash_all() { void flash_all() {
int32_t part; int32_t part;
uint32_t blk,maxblock; uint32_t blk,maxblock;
printf("\n## ---- Имя раздела ---- записано"); printf("\n## ---- Partition name ---- Progress");
// Главный цикл записи разделов // main partition recording loop
for(part=0;part<npart;part++) { for(part=0;part<npart;part++) {
printf("\n"); printf("\n");
// printf("\n02i %s)",part,ptable[part].pname); // printf("\n02i %s)",part,ptable[part].pname);
// команда начала раздела // command to start partitioning
if (!dload_start(ptable[part].hd.code,ptable[part].hd.psize)) { if (!dload_start(ptable[part].hd.code,ptable[part].hd.psize)) {
printf("\r! Отвергнут заголовок раздела %i (%s)",part,ptable[part].pname); printf("\r! Rejected partition %i (%s)",part,ptable[part].pname);
printerr(); printerr();
exit(-2); exit(-2);
} }
maxblock=(ptable[part].hd.psize+(fblock-1))/fblock; // число блоков в разделе maxblock=(ptable[part].hd.psize+(fblock-1))/fblock; // number of blocks in the partition
// Поблочный цикл передачи образа раздела // block cycle of partition image transfer
for(blk=0;blk<maxblock;blk++) { for(blk=0;blk<maxblock;blk++) {
// Вывод процента записанного // output written percentage
printf("\r%02i %-20s %i%%",part,ptable[part].pname,(blk+1)*100/maxblock); printf("\r%02i %-20s %i%%",part,ptable[part].pname,(blk+1)*100/maxblock);
// Отсылаем очередной блок // send next block
if (!dload_block(part,blk,ptable[part].pimage)) { if (!dload_block(part,blk,ptable[part].pimage)) {
printf("\n! Отвергнут блок %i раздела %i (%s)",blk,part,ptable[part].pname); printf("\n! Block %i of partition %i rejected (%s)",blk,part,ptable[part].pname);
printerr(); printerr();
exit(-2); exit(-2);
} }
} }
// закрываем раздел // finalizing partition
if (!dload_end(ptable[part].hd.code,ptable[part].hd.psize)) { if (!dload_end(ptable[part].hd.code,ptable[part].hd.psize)) {
printf("\n! Ошибка закрытия раздела %i (%s)",part,ptable[part].pname); printf("\n! Finalizing partition %i failed (%s)",part,ptable[part].pname);
printerr(); printerr();
exit(-2); exit(-2);
} }
} // конец цикла по разделам } // end of partition cycle
} }

@ -1,4 +1,4 @@
// размер блока данных, передаваемый модему за одну команду // size of the block of data transmitted to the modem per command
#define fblock 4096 #define fblock 4096
//#define fblock 2048 //#define fblock 2048

@ -1,4 +1,4 @@
extern int siofd; // fd для работы с Последовательным портом extern int siofd; // fd to work with the serial port
int send_cmd(unsigned char* incmdbuf, int blen, unsigned char* iobuf); int send_cmd(unsigned char* incmdbuf, int blen, unsigned char* iobuf);
int open_port(char* devname); int open_port(char* devname);

@ -1,4 +1,4 @@
// Низкоуровневые процедуры работы с последовательным портом и HDLC // Low-level serial port and HDLC procedures
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -18,41 +18,41 @@ unsigned int nand_cmd=0x1b400000;
unsigned int spp=0; unsigned int spp=0;
unsigned int pagesize=0; unsigned int pagesize=0;
unsigned int sectorsize=512; unsigned int sectorsize=512;
unsigned int maxblock=0; // Общее число блоков флешки unsigned int maxblock=0; // total number of flash blocks
char flash_mfr[30]={0}; char flash_mfr[30]={0};
char flash_descr[30]={0}; char flash_descr[30]={0};
unsigned int oobsize=0; unsigned int oobsize=0;
static char pdev[500]; // имя последовательного порта static char pdev[500]; // serial port name
int siofd; // fd для работы с Последовательным портом int siofd; // fd to work with the serial port
struct termios sioparm; struct termios sioparm;
//int siofd; // fd для работы с Последовательным портом //int siofd; // fd for serial port operation
//************************************************* //*************************************************
//* отсылка буфера в модем //* Send buffer to modem
//************************************************* //*************************************************
unsigned int send_unframed_buf(char* outcmdbuf, unsigned int outlen) { unsigned int send_unframed_buf(char* outcmdbuf, unsigned int outlen) {
tcflush(siofd,TCIOFLUSH); // сбрасываем недочитанный буфер ввода tcflush(siofd,TCIOFLUSH); // reset unread input buffer
write(siofd,"\x7e",1); // отсылаем префикс write(siofd,"\x7e",1); // send prefix
if (write(siofd,outcmdbuf,outlen) == 0) { printf("\n Ошибка записи команды");return 0; } if (write(siofd,outcmdbuf,outlen) == 0) { printf("\n Command writing error");return 0; }
tcdrain(siofd); // ждем окончания вывода блока tcdrain(siofd); // waiting for the end of the block output
return 1; return 1;
} }
//****************************************************************************************** //******************************************************************************************
//* Прием буфера с ответом из модема //* Receiving buffer with response from modem
//* //*
//* masslen - число байтов, принимаемых единым блоком без анализа признака конца 7F //* masslen is the number of bytes received in a single block without analysis of 7F end sign
//****************************************************************************************** //******************************************************************************************
unsigned int receive_reply(char* iobuf, int masslen) { unsigned int receive_reply(char* iobuf, int masslen) {
int i,iolen,escflag,incount; int i,iolen,escflag,incount;
unsigned char c; unsigned char c;
unsigned int res; unsigned int res;
@ -60,60 +60,60 @@ unsigned char replybuf[14000];
incount=0; incount=0;
if (read(siofd,&c,1) != 1) { if (read(siofd,&c,1) != 1) {
// printf("\n Нет ответа от модема"); // printf("\n No response from modem");
return 0; // модем не ответил или ответил неправильно return 0; // modem didn't answer or answered incorrectly
} }
//if (c != 0x7e) { //if (c != 0x7e) {
// printf("\n Первый байт ответа - не 7e: %02x",c); // printf("\n First byte of the answer is not 7e: %02x",c);
// return 0; // модем не ответил или ответил неправильно // return 0; // modem didn't answer or answered incorrectly
//} //}
replybuf[incount++]=c; replybuf[incount++]=c;
// чтение массива данных единым блоком при обработке команды 03 // read an array of data in a single block when processing command 03
if (masslen != 0) { if (masslen != 0) {
res=read(siofd,replybuf+1,masslen-1); res=read(siofd,replybuf+1,masslen-1);
if (res != (masslen-1)) { if (res != (masslen-1)) {
printf("\nСлишком короткий ответ от модема: %i байт, ожидалось %i байт\n",res+1,masslen); printf("\nResponse from the modem is too short: %i bytes, expected %i bytes\n",res+1,masslen);
dump(replybuf,res+1,0); dump(replybuf,res+1,0);
return 0; return 0;
} }
incount+=masslen-1; // у нас в буфере уже есть masslen байт incount+=masslen-1; // we already have a masslen byte in the buffer
// printf("\n ------ it mass --------"); // printf("\n ------ it mass --------");
// dump(replybuf,incount,0); // dump(replybuf,incount,0);
} }
// принимаем оставшийся хвост буфера // take the remaining tail of the buffer
while (read(siofd,&c,1) == 1) { while (read(siofd,&c,1) == 1) {
replybuf[incount++]=c; replybuf[incount++]=c;
// printf("\n-- %02x",c); // printf("\n-- %02x",c);
if (c == 0x7e) break; if (c == 0x7e) break;
} }
// Преобразование принятого буфера для удаления ESC-знаков // conversion of the received buffer to remove ESC characters
escflag=0; escflag=0;
iolen=0; iolen=0;
for (i=0;i<incount;i++) { for (i=0;i<incount;i++) {
c=replybuf[i]; c=replybuf[i];
if ((c == 0x7e)&&(iolen != 0)) { if ((c == 0x7e)&&(iolen != 0)) {
iobuf[iolen++]=0x7e; iobuf[iolen++]=0x7e;
break; break;
} }
if (c == 0x7d) { if (c == 0x7d) {
escflag=1; escflag=1;
continue; continue;
} }
if (escflag == 1) { if (escflag == 1) {
c|=0x20; c|=0x20;
escflag=0; escflag=0;
} }
iobuf[iolen++]=c; iobuf[iolen++]=c;
} }
return iolen; return iolen;
} }
//*********************************************************** //***********************************************************
//* Преобразование командного буфера с Escape-подстановкой //* Command buffer conversion with Escape-substitution
//*********************************************************** //***********************************************************
unsigned int convert_cmdbuf(char* incmdbuf, int blen, char* outcmdbuf) { unsigned int convert_cmdbuf(char* incmdbuf, int blen, char* outcmdbuf) {
@ -122,49 +122,49 @@ unsigned char cmdbuf[14096];
bcnt=blen; bcnt=blen;
memcpy(cmdbuf,incmdbuf,blen); memcpy(cmdbuf,incmdbuf,blen);
// Вписываем CRC в конец буфера // write the CRC at the end of the buffer
*((unsigned short*)(cmdbuf+bcnt))=crc16(cmdbuf,bcnt); *((unsigned short*)(cmdbuf+bcnt))=crc16(cmdbuf,bcnt);
bcnt+=2; bcnt+=2;
// Пребразование данных с экранированием ESC-последовательностей // data preprocessing with escaping of ESC-sequences
iolen=0; iolen=0;
outcmdbuf[iolen++]=cmdbuf[0]; // первый байт копируем без модификаций outcmdbuf[iolen++]=cmdbuf[0]; // first byte is copied without modification
for(i=1;i<bcnt;i++) { for(i=1;i<bcnt;i++) {
switch (cmdbuf[i]) { switch (cmdbuf[i]) {
case 0x7e: case 0x7e:
outcmdbuf[iolen++]=0x7d; outcmdbuf[iolen++]=0x7d;
outcmdbuf[iolen++]=0x5e; outcmdbuf[iolen++]=0x5e;
break; break;
case 0x7d: case 0x7d:
outcmdbuf[iolen++]=0x7d; outcmdbuf[iolen++]=0x7d;
outcmdbuf[iolen++]=0x5d; outcmdbuf[iolen++]=0x5d;
break; break;
default: default:
outcmdbuf[iolen++]=cmdbuf[i]; outcmdbuf[iolen++]=cmdbuf[i];
} }
} }
outcmdbuf[iolen++]=0x7e; // завершающий байт outcmdbuf[iolen++]=0x7e; // end byte
outcmdbuf[iolen]=0; outcmdbuf[iolen]=0;
return iolen; return iolen;
} }
//*************************************************** //***************************************************
//* Отсылка команды в порт и получение результата * //* Send a command to a port and receive the result
//*************************************************** //***************************************************
int send_cmd(unsigned char* incmdbuf, int blen, unsigned char* iobuf) { int send_cmd(unsigned char* incmdbuf, int blen, unsigned char* iobuf) {
unsigned char outcmdbuf[14096]; unsigned char outcmdbuf[14096];
unsigned int iolen; unsigned int iolen;
iolen=convert_cmdbuf(incmdbuf,blen,outcmdbuf); iolen=convert_cmdbuf(incmdbuf,blen,outcmdbuf);
if (!send_unframed_buf(outcmdbuf,iolen)) return 0; // ошибка передачи команды if (!send_unframed_buf(outcmdbuf,iolen)) return 0; // command transmission error
return receive_reply(iobuf,0); return receive_reply(iobuf,0);
} }
//*************************************************** //***************************************************
// Открытие и настройка последовательного порта // Opening and configuring the serial port
//*************************************************** //***************************************************
int open_port(char* devname) { int open_port(char* devname) {
@ -174,67 +174,68 @@ int i,dflag=1;
char devstr[200]={0}; char devstr[200]={0};
if (strlen(devname) != 0) strcpy(pdev,devname); // сохраняем имя порта if (strlen(devname) != 0) strcpy(pdev,devname); // save port name
else strcpy(devname,"/dev/ttyUSB0"); // если имя порта не было задано else strcpy(devname,"/dev/ttyUSB0"); // if the port name is not set
// Вместо полного имени устройства разрешается передавать только номер ttyUSB-порта // only the ttyUSB port number can be transmitted instead of the full device name
// Проверяем имя устройства на наличие нецифровых символов // check the device name for the presence of nonnumeric characters
for(i=0;i<strlen(devname);i++) { for(i=0;i<strlen(devname);i++) {
if ((devname[i]<'0') || (devname[i]>'9')) dflag=0; if ((devname[i]<'0') || (devname[i]>'9')) dflag=0;
} }
// Если в строке - только цифры, добавляем префикс /dev/ttyUSB // if there are only digits in the string, add the prefix /dev/ttyUSB
if (dflag) strcpy(devstr,"/dev/ttyUSB"); if (dflag) strcpy(devstr,"/dev/ttyUSB");
// копируем имя устройства // copy the device name
strcat(devstr,devname); strcat(devstr,devname);
siofd = open(devstr, O_RDWR | O_NOCTTY |O_SYNC); siofd = open(devstr, O_RDWR | O_NOCTTY |O_SYNC);
if (siofd == -1) { if (siofd == -1) {
printf("\n! - Последовательный порт %s не открывается\n", devname); printf("\n! - Can't open serial port %s\n", devname);
exit(0); exit(0);
} }
bzero(&sioparm, sizeof(sioparm)); // готовим блок атрибутов termios bzero(&sioparm, sizeof(sioparm)); // prepare the attribute block termios
sioparm.c_cflag = B115200 | CS8 | CLOCAL | CREAD ; sioparm.c_cflag = B115200 | CS8 | CLOCAL | CREAD ;
sioparm.c_iflag = 0; // INPCK; sioparm.c_iflag = 0; // INPCK;
sioparm.c_oflag = 0; sioparm.c_oflag = 0;
sioparm.c_lflag = 0; sioparm.c_lflag = 0;
sioparm.c_cc[VTIME]=30; // timeout sioparm.c_cc[VTIME]=30; // timeout
sioparm.c_cc[VMIN]=0; sioparm.c_cc[VMIN]=0;
tcsetattr(siofd, TCSANOW, &sioparm); tcsetattr(siofd, TCSANOW, &sioparm);
tcflush(siofd,TCIOFLUSH); // очистка выходного буфера tcflush(siofd,TCIOFLUSH); // cleaning output buffer
return 1; return 1;
} }
//************************************* //*************************************
// Настройка времени ожидания порта // set the timeout time of the port
//************************************* //*************************************
void port_timeout(int timeout) { void port_timeout(int timeout) {
bzero(&sioparm, sizeof(sioparm)); // готовим блок атрибутов termios bzero(&sioparm, sizeof(sioparm)); // prepare the attribute block termios
sioparm.c_cflag = B115200 | CS8 | CLOCAL | CREAD ; sioparm.c_cflag = B115200 | CS8 | CLOCAL | CREAD ;
sioparm.c_iflag = 0; // INPCK; sioparm.c_iflag = 0; // INPCK;
sioparm.c_oflag = 0; sioparm.c_oflag = 0;
sioparm.c_lflag = 0; sioparm.c_lflag = 0;
sioparm.c_cc[VTIME]=timeout; // timeout sioparm.c_cc[VTIME]=timeout; // timeout
sioparm.c_cc[VMIN]=0; sioparm.c_cc[VMIN]=0;
tcsetattr(siofd, TCSANOW, &sioparm); tcsetattr(siofd, TCSANOW, &sioparm);
} }
//************************************************* //*************************************************
//* Поиск файла по номеру в указанном каталоге //* Search for a file by its number in the specified directory
//* //*
//* num - # файла //* num - # of file
//* filename - буфер для полного имени файла //* filename - buffer for full file name
//* id - переменная, в которую будет записан идентификатор раздела //* id - variable, where the partition identifier will be written
//* //*
//* return 0 - не найдено //* return
//* 1 - найдено //* 0 - not found
//* 1 - found
//************************************************* //*************************************************
int find_file(int num, char* dirname, char* filename,unsigned int* id, unsigned int* size) { int find_file(int num, char* dirname, char* filename,unsigned int* id, unsigned int* size) {
@ -244,62 +245,61 @@ unsigned int pt;
struct dirent* dentry; struct dirent* dentry;
char fpattern[5]; char fpattern[5];
sprintf(fpattern,"%02i",num); // образец для поиска файла по 3 цифрам номера sprintf(fpattern,"%02i",num); // sample file search by 3 digits of the number
fdir=opendir(dirname); fdir=opendir(dirname);
if (fdir == 0) { if (fdir == 0) {
printf("\n Каталог %s не открывается\n",dirname); printf("\n Can't open directory %s\n",dirname);
exit(1); exit(1);
} }
// главный цикл - поиск нужного нам файла // main loop - search for the file we need
while ((dentry=readdir(fdir)) != 0) { while ((dentry=readdir(fdir)) != 0) {
if (dentry->d_type != DT_REG) continue; // пропускаем все кроме регулярных файлов if (dentry->d_type != DT_REG) continue; // skip everything except regular files
if (strncmp(dentry->d_name,fpattern,2) == 0) break; // нашли нужный файл. Точнее, файл с нужными 3 цифрами в начале имени. if (strncmp(dentry->d_name,fpattern,2) == 0) break; // we have found the file we need. More precisely, the file with the required 3 digits in the beginning of its name.
} }
closedir(fdir); closedir(fdir);
// формируем полное имя файла в буфере результата // create a full filename in the result buffer
if (dentry == 0) return 0; // не нашли if (dentry == 0) return 0; // not found
strcpy(filename,dirname); strcpy(filename,dirname);
strcat(filename,"/"); strcat(filename,"/");
// копируем имя файла в буфер результата // copy the file name into the result buffer
strcat(filename,dentry->d_name); strcat(filename,dentry->d_name);
// 00-00000200-M3Boot.bin // 00-00000200-M3Boot.bin
//проверяем имя файла на наличие знаков '-' // check the file name for '-' signs
if ((dentry->d_name[2] != '-') || (dentry->d_name[11] != '-')) { if ((dentry->d_name[2] != '-') || (dentry->d_name[11] != '-')) {
printf("\n Неправильный формат имени файла - %s\n",dentry->d_name); printf("\n Incorrect format of file - %s\n",dentry->d_name);
exit(1); exit(1);
} }
// проверяем цифровое поле ID раздела // check the numeric partition ID field
if (strspn(dentry->d_name+3,"0123456789AaBbCcDdEeFf") != 8) { if (strspn(dentry->d_name+3,"0123456789AaBbCcDdEeFf") != 8) {
printf("\n Ошибка в идентификаторе раздела - нецифровой знак - %s\n",filename); printf("\n Partition ID error - non-digit character - %s\n",filename);
exit(1); exit(1);
} }
sscanf(dentry->d_name+3,"%8x",id); sscanf(dentry->d_name+3,"%8x",id);
// Проверяем доступность и читаемость файла // check file availability and readability
in=fopen(filename,"r"); in=fopen(filename,"r");
if (in == 0) { if (in == 0) {
printf("\n Ошибка открытия файла %s\n",filename); printf("\n Can't open file %s\n",filename);
exit(1); exit(1);
} }
if (fread(&pt,1,4,in) != 4) { if (fread(&pt,1,4,in) != 4) {
printf("\n Ошибка чтения файла %s\n",filename); printf("\n Can't read file %s\n",filename);
exit(1); exit(1);
} }
// проверяем, что файл - сырой образ, без заголовка // check that the file is a raw image, without a header
if (pt == 0xa55aaa55) { if (pt == 0xa55aaa55) {
printf("\n Файл %s имеет заголовок - для прошивки не подходит\n",filename); printf("\n File %s has a header - not suitable for flashing\n",filename);
exit(1); exit(1);
} }
// What else can I check? I haven't figured it out yet.
// Что еще можно проверить? Пока не придумал. // get the file size
// Получаем размер файла
fseek(in,0,SEEK_END); fseek(in,0,SEEK_END);
*size=ftell(in); *size=ftell(in);
fclose(in); fclose(in);
@ -308,12 +308,12 @@ return 1;
} }
//**************************************************** //****************************************************
//* Отсылка модему АТ-команды //* Send AT command to modem
//* //*
//* cmd - буфер с командой //* cmd - command buffer
//* rbuf - буфер для записи ответа //* rbuf - response buffer
//* //*
//* Возвращает длину ответа //* Returns the length of answer
//**************************************************** //****************************************************
int atcmd(char* cmd, char* rbuf) { int atcmd(char* cmd, char* rbuf) {
@ -325,15 +325,14 @@ strcat(cbuf,cmd);
strcat(cbuf,"\r"); strcat(cbuf,"\r");
port_timeout(100); port_timeout(100);
// Вычищаем буфер приемника и передатчика // clean up the receiver and transmitter buffer
tcflush(siofd,TCIOFLUSH); tcflush(siofd,TCIOFLUSH);
// отправка команды // send command
write(siofd,cbuf,strlen(cbuf)); write(siofd,cbuf,strlen(cbuf));
usleep(100000); usleep(100000);
// чтение результата // read result
res=read(siofd,rbuf,200); res=read(siofd,rbuf,200);
return res; return res;
} }

@ -1,4 +1,4 @@
// Процедуры работы с таблицей разделов // Partition table procedures
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
@ -20,7 +20,7 @@
int32_t lzma_decode(uint8_t* inbuf,uint32_t fsize,uint8_t* outbuf); int32_t lzma_decode(uint8_t* inbuf,uint32_t fsize,uint8_t* outbuf);
//****************************************************** //******************************************************
//* поиск символического имени раздела по его коду //* Search for a symbolic partition name by its code
//****************************************************** //******************************************************
void find_pname(unsigned int id,unsigned char* pname) { void find_pname(unsigned int id,unsigned char* pname) {
@ -29,10 +29,10 @@ unsigned int j;
struct { struct {
char name[20]; char name[20];
int code; int code;
} pcodes[]={ } pcodes[]={
{"M3Boot",0x20000}, {"M3Boot",0x20000},
{"M3Boot-ptable",0x10000}, {"M3Boot-ptable",0x10000},
{"M3Boot_R11",0x200000}, {"M3Boot_R11",0x200000},
{"Ptable",0x10000}, {"Ptable",0x10000},
{"Ptable_ext_A",0x480000}, {"Ptable_ext_A",0x480000},
{"Ptable_ext_B",0x490000}, {"Ptable_ext_B",0x490000},
@ -52,9 +52,9 @@ struct {
{"Nvimg",0x80000}, {"Nvimg",0x80000},
{"System",0x590000}, {"System",0x590000},
{"System",0x100000}, {"System",0x100000},
{"APP",0x570000}, {"APP",0x570000},
{"APP",0x5a0000}, {"APP",0x5a0000},
{"APP_EXT_A",0x450000}, {"APP_EXT_A",0x450000},
{"APP_EXT_B",0x460000}, {"APP_EXT_B",0x460000},
{"Oeminfo",0xa0000}, {"Oeminfo",0xa0000},
{"CDROMISO",0xb0000}, {"CDROMISO",0xb0000},
@ -88,74 +88,71 @@ struct {
for(j=0;pcodes[j].code != 0;j++) { for(j=0;pcodes[j].code != 0;j++) {
if(pcodes[j].code == id) break; if(pcodes[j].code == id) break;
} }
if (pcodes[j].code != 0) strcpy(pname,pcodes[j].name); // имя найдено - копируем его в структуру if (pcodes[j].code != 0) strcpy(pname,pcodes[j].name); // name is found - copy it into the structure
else sprintf(pname,"U%08x",id); // имя не найдено - подставляем псевдоимя Uxxxxxxxx в тупоконечном формате else sprintf(pname,"U%08x",id); // name not found - substitute the pseudo name Uxxxxxxxxxx in blunt-end format
} }
//******************************************************************* //*******************************************************************
// Вычисление размера блока контрольных сумм раздела // Calculation of partition checksum block size
//******************************************************************* //*******************************************************************
uint32_t crcsize(int n) { uint32_t crcsize(int n) {
return ptable[n].hd.hdsize-sizeof(struct pheader); return ptable[n].hd.hdsize-sizeof(struct pheader);
} }
//******************************************************************* //*******************************************************************
// получение размера образа раздела // Obtaining partition image size
//******************************************************************* //*******************************************************************
uint32_t psize(int n) { uint32_t psize(int n) {
return ptable[n].hd.psize; return ptable[n].hd.psize;
} }
//******************************************************* //*******************************************************
//* Вычисление блочной контрольной суммы заголовка //* Header block checksum calculation
//******************************************************* //*******************************************************
void calc_hd_crc16(int n) { void calc_hd_crc16(int n) {
ptable[n].hd.crc=0; // очищаем старую CRC-сумму ptable[n].hd.crc=0; // clear old CRC sum
ptable[n].hd.crc=crc16((uint8_t*)&ptable[n].hd,sizeof(struct pheader)); ptable[n].hd.crc=crc16((uint8_t*)&ptable[n].hd,sizeof(struct pheader));
} }
//******************************************************* //*******************************************************
//* Вычисление блочной контрольной суммы раздела //* Calculating the block checksum of a partition
//******************************************************* //*******************************************************
void calc_crc16(int n) { void calc_crc16(int n) {
uint32_t csize; // размер блока сумм в 16-битных словах uint32_t csize; // block size sum in 16-bit words
uint16_t* csblock; // указатель на создаваемый блок uint16_t* csblock; // pointer to created block
uint32_t off,len; uint32_t off,len;
uint32_t i; uint32_t i;
uint32_t blocksize=ptable[n].hd.blocksize; // размер блока, охватываемого суммой uint32_t blocksize=ptable[n].hd.blocksize; // size of the block covered by the sum
// определяем размер и создаем блок // determine the size and create the block
csize=psize(n)/blocksize; csize=psize(n)/blocksize;
if (psize(n)%blocksize != 0) csize++; // Это если размер образа не кратен blocksize if (psize(n)%blocksize != 0) csize++; // this is if the image size is not a multiple of blocksize
csblock=(uint16_t*)malloc(csize*2); csblock=(uint16_t*)malloc(csize*2);
// цикл вычисления сумм // loop for sum calculation
for (i=0;i<csize;i++) { for (i=0;i<csize;i++) {
off=i*blocksize; // смещение до текущего блока off=i*blocksize; // shift to the current block
len=blocksize; len=blocksize;
if ((ptable[n].hd.psize-off)<blocksize) len=ptable[n].hd.psize-off; // для последнего неполного блока if ((ptable[n].hd.psize-off)<blocksize) len=ptable[n].hd.psize-off; // for the last incomplete block
csblock[i]=crc16(ptable[n].pimage+off,len); csblock[i]=crc16(ptable[n].pimage+off,len);
} }
// вписываем параметры в заголовок // enter the parameters into the header
if (ptable[n].csumblock != 0) free(ptable[n].csumblock); // уничтожаем старый блок, если он был if (ptable[n].csumblock != 0) free(ptable[n].csumblock); // we destroy the old block if there was one
ptable[n].csumblock=csblock; ptable[n].csumblock=csblock;
ptable[n].hd.hdsize=csize*2+sizeof(struct pheader); ptable[n].hd.hdsize=csize*2+sizeof(struct pheader);
// перевычисляем CRC заголовка // recalculate CRC header
calc_hd_crc16(n); calc_hd_crc16(n);
} }
//******************************************************************* //*******************************************************************
//* Извлечение раздела из файла и добавление его в таблицу разделов //* Extract partition from file and add it to partition table
//* //*
// in - входной файл прошивки //* "in" is the input firmware file
// Позиция в файле соответствует началу заголовка раздела //* position in file corresponds to the beginning of partition header
//******************************************************************* //*******************************************************************
void extract(FILE* in) { void extract(FILE* in) {
@ -166,219 +163,210 @@ uint8_t* zbuf;
long int zlen; long int zlen;
int res; int res;
ptable[npart].zflag=0; ptable[npart].zflag=0;
// читаем заголовок в структуру // read the header into the structure
ptable[npart].offset=ftell(in); ptable[npart].offset=ftell(in);
fread(&ptable[npart].hd,1,sizeof(struct pheader),in); // заголовок fread(&ptable[npart].hd,1,sizeof(struct pheader),in); // header
// Ищем символическое имя раздела по таблице // look up the symbolic name of the partition in the table
find_pname(ptable[npart].hd.code,ptable[npart].pname); find_pname(ptable[npart].hd.code,ptable[npart].pname);
// загружаем блок контрольных сумм // load the checksum block
ptable[npart].csumblock=0; // пока блок не создан ptable[npart].csumblock=0; // until the block is created
crcblock=(uint16_t*)malloc(crcsize(npart)); // выделяем временную память под загружаемый блок crcblock=(uint16_t*)malloc(crcsize(npart)); // allot temporary memory for the loaded block
crcblocksize=crcsize(npart); crcblocksize=crcsize(npart);
fread(crcblock,1,crcblocksize,in); fread(crcblock,1,crcblocksize,in);
// загружаем образ раздела // load a partition image
ptable[npart].pimage=(uint8_t*)malloc(psize(npart)); ptable[npart].pimage=(uint8_t*)malloc(psize(npart));
fread(ptable[npart].pimage,1,psize(npart),in); fread(ptable[npart].pimage,1,psize(npart),in);
// проверяем CRC заголовка // check the CRC of the header
hcrc=ptable[npart].hd.crc; hcrc=ptable[npart].hd.crc;
ptable[npart].hd.crc=0; // старая CRC в рассчете не учитывается ptable[npart].hd.crc=0; // check the CRC of the header
crc=crc16((uint8_t*)&ptable[npart].hd,sizeof(struct pheader)); crc=crc16((uint8_t*)&ptable[npart].hd,sizeof(struct pheader));
if (crc != hcrc) { if (crc != hcrc) {
printf("\n! Раздел %s (%02x) - ошибка контрольной суммы заголовка",ptable[npart].pname,ptable[npart].hd.code>>16); printf("\n! Partition %s (%02x) - header checksum error",ptable[npart].pname,ptable[npart].hd.code>>16);
errflag=1; errflag=1;
} }
ptable[npart].hd.crc=crc; // восстанавливаем CRC ptable[npart].hd.crc=crc; // recover CRC
// вычисляем и проверяем CRC раздела // calculate and check the CRC of the partition
calc_crc16(npart); calc_crc16(npart);
if (crcblocksize != crcsize(npart)) { if (crcblocksize != crcsize(npart)) {
printf("\n! Раздел %s (%02x) - неправильный размер блока контрольных сумм",ptable[npart].pname,ptable[npart].hd.code>>16); printf("\n! Partition %s (%02x) - Incorrect checksum block size",ptable[npart].pname,ptable[npart].hd.code>>16);
errflag=1; errflag=1;
} }
else if (memcmp(crcblock,ptable[npart].csumblock,crcblocksize) != 0) { else if (memcmp(crcblock,ptable[npart].csumblock,crcblocksize) != 0) {
printf("\n! Раздел %s (%02x) - неправильная блочная контрольная сумма",ptable[npart].pname,ptable[npart].hd.code>>16); printf("\n! Partition %s (%02x) - incorrect block checksum",ptable[npart].pname,ptable[npart].hd.code>>16);
errflag=1; errflag=1;
} }
free(crcblock);
free(crcblock);
ptable[npart].ztype=' '; ptable[npart].ztype=' ';
// Определение zlib-сжатия // definition of zlib-compression
if ((*(uint16_t*)ptable[npart].pimage) == 0xda78) { if ((*(uint16_t*)ptable[npart].pimage) == 0xda78) {
ptable[npart].zflag=ptable[npart].hd.psize; // сохраняем сжатый размер ptable[npart].zflag=ptable[npart].hd.psize; // keep the compressed size
zlen=52428800; zlen=52428800;
zbuf=malloc(zlen); // буфер в 50М zbuf=malloc(zlen); // buffer of 50М
// распаковываем образ раздела // unpack the partition image
res=uncompress (zbuf, &zlen, ptable[npart].pimage, ptable[npart].hd.psize); res=uncompress (zbuf, &zlen, ptable[npart].pimage, ptable[npart].hd.psize);
if (res != Z_OK) { if (res != Z_OK) {
printf("\n! Ошибка распаковки раздела %s (%02x)\n",ptable[npart].pname,ptable[npart].hd.code>>16); printf("\n! Error unpacking partition %s (%02x)\n",ptable[npart].pname,ptable[npart].hd.code>>16);
errflag=1; errflag=1;
} }
// создаем новый буфер образа раздела и копируем в него рапаковынные данные // create a new partition image buffer and copy the unpacked data into it
free(ptable[npart].pimage); free(ptable[npart].pimage);
ptable[npart].pimage=malloc(zlen); ptable[npart].pimage=malloc(zlen);
memcpy(ptable[npart].pimage,zbuf,zlen); memcpy(ptable[npart].pimage,zbuf,zlen);
ptable[npart].hd.psize=zlen; ptable[npart].hd.psize=zlen;
free(zbuf); free(zbuf);
// перерассчитываем контрольные суммы // recalculate the checksums
calc_crc16(npart); calc_crc16(npart);
ptable[npart].hd.crc=crc16((uint8_t*)&ptable[npart].hd,sizeof(struct pheader)); ptable[npart].hd.crc=crc16((uint8_t*)&ptable[npart].hd,sizeof(struct pheader));
ptable[npart].ztype='Z'; ptable[npart].ztype='Z';
} }
// Определение lzma-сжатия // lzma compression detection
if ((ptable[npart].pimage[0] == 0x5d) && (*(uint64_t*)(ptable[npart].pimage+5) == 0xffffffffffffffff)) { if ((ptable[npart].pimage[0] == 0x5d) && (*(uint64_t*)(ptable[npart].pimage+5) == 0xffffffffffffffff)) {
ptable[npart].zflag=ptable[npart].hd.psize; // сохраняем сжатый размер ptable[npart].zflag=ptable[npart].hd.psize; // keep the compressed size
zlen=100 * 1024 * 1024; zlen=100 * 1024 * 1024;
zbuf=malloc(zlen); // буфер в 100М zbuf=malloc(zlen); // buffer of 100М
// распаковываем образ раздела // unpack the partition image
zlen=lzma_decode(ptable[npart].pimage, ptable[npart].hd.psize, zbuf); zlen=lzma_decode(ptable[npart].pimage, ptable[npart].hd.psize, zbuf);
if (zlen>100 * 1024 * 1024) { if (zlen>100 * 1024 * 1024) {
printf("\n Превышен размер буфера\n"); printf("\n Buffer size exceeded\n");
exit(1); exit(1);
} }
if (res == -1) { if (res == -1) {
printf("\n! Ошибка распаковки раздела %s (%02x)\n",ptable[npart].pname,ptable[npart].hd.code>>16); printf("\n! Error unpacking partition %s (%02x)\n",ptable[npart].pname,ptable[npart].hd.code>>16);
errflag=1; errflag=1;
} }
// создаем новый буфер образа раздела и копируем в него рапаковынные данные // create a new partition image buffer and copy the unpacked data into it
free(ptable[npart].pimage); free(ptable[npart].pimage);
ptable[npart].pimage=malloc(zlen); ptable[npart].pimage=malloc(zlen);
memcpy(ptable[npart].pimage,zbuf,zlen); memcpy(ptable[npart].pimage,zbuf,zlen);
ptable[npart].hd.psize=zlen; ptable[npart].hd.psize=zlen;
free(zbuf); free(zbuf);
// перерассчитываем контрольные суммы // recalculate the checksums
calc_crc16(npart); calc_crc16(npart);
ptable[npart].hd.crc=crc16((uint8_t*)&ptable[npart].hd,sizeof(struct pheader)); ptable[npart].hd.crc=crc16((uint8_t*)&ptable[npart].hd,sizeof(struct pheader));
ptable[npart].ztype='L'; ptable[npart].ztype='L';
} }
// advance the partition counter
// продвигаем счетчик разделов
npart++; npart++;
// отъезжаем, если надо, вперед на границу слова // move forward to the word boundary if necessary
res=ftell(in); res=ftell(in);
if ((res&3) != 0) fseek(in,(res+4)&(~3),SEEK_SET); if ((res&3) != 0) fseek(in,(res+4)&(~3),SEEK_SET);
} }
//******************************************************* //*******************************************************
//* Поиск разделов в файле прошивки //* Search for partitions in firmware file
//* //*
//* возвращает число найденных разделов //* returns number of found partitions
//******************************************************* //*******************************************************
int findparts(FILE* in) { int findparts(FILE* in) {
// буфер префикса BIN-файла // BIN file prefix buffer
uint8_t prefix[0x5c]; uint8_t prefix[0x5c];
int32_t signsize; int32_t signsize;
int32_t hd_dload_id; int32_t hd_dload_id;
// Маркер начала заголовка раздела // partition header start marker
const unsigned int dpattern=0xa55aaa55; const unsigned int dpattern=0xa55aaa55;
unsigned int i; unsigned int i;
// поиск начала цепочки разделов в файле // search for the beginning of the partition chain in the file
while (fread(&i,1,4,in) == 4) { while (fread(&i,1,4,in) == 4) {
if (i == dpattern) break; if (i == dpattern) break;
} }
if (feof(in)) { if (feof(in)) {
printf("\n В файле не найдены разделы - файл не содержит образа прошивки\n"); printf("\n No partitions found in file - the file does not contain a firmware image\n");
exit(0); exit(0);
} }
// текущая позиция в файле должна быть не ближе 0x60 от начала - размер заголовка всего файла // the current position in the file should be no closer than 0x60 from the beginning - the header size of the whole file
if (ftell(in)<0x60) { if (ftell(in)<0x60) {
printf("\n Заголовок файла имеет неправильный размер\n"); printf("\n Wrong file header size\n");
exit(0); exit(0);
} }
fseek(in,-0x60,SEEK_CUR); // отъезжаем на начало BIN-файла fseek(in,-0x60,SEEK_CUR); // move to the beginning of the BIN-file
// вынимаем префикс // take out the prefix
fread(prefix,0x5c,1,in); fread(prefix,0x5c,1,in);
hd_dload_id=prefix[0]; hd_dload_id=prefix[0];
// если принудительно dload_id не установлен - выбираем его из заголовка // if dload_id is not set forcibly - select it from the header
if (dload_id == -1) dload_id=hd_dload_id; if (dload_id == -1) dload_id=hd_dload_id;
if (dload_id > 0xf) { if (dload_id > 0xf) {
printf("\n Неверный код типа прошивки (dload_id) в заголовке - %x",dload_id); printf("\n Incorrect firmware type code (dload_id) in header - %x",dload_id);
exit(0); exit(0);
} }
printf("\n Код файла прошивки: %x (%s)\n",hd_dload_id,fw_description(hd_dload_id)); printf("\n Firmware file code: %x (%s)\n",hd_dload_id,fw_description(hd_dload_id));
// поиск остальных разделов // search for other partitions
do { do {
printf("\r Поиск раздела # %i",npart); fflush(stdout); printf("\r Searching for partition # %i",npart); fflush(stdout);
if (fread(&i,1,4,in) != 4) break; // конец файла if (fread(&i,1,4,in) != 4) break; // end of file
if (i != dpattern) break; // образец не найден - конец цепочки разделов if (i != dpattern) break; // sample not found - end of partition chain
fseek(in,-4,SEEK_CUR); // отъезжаем назад, на начало заголовка fseek(in,-4,SEEK_CUR); // move back to the beginning of header
extract(in); // извлекаем раздел extract(in); // extract partition
} while(1); } while(1);
printf("\r \r"); printf("\r \r");
// ищем цифровую подпись // look for a digital signature
signsize=serach_sign(); signsize=serach_sign();
if (signsize == -1) printf("\n Цифровая подпись: не найдена"); if (signsize == -1) printf("\n Digital Signature: Not found");
else { else {
printf("\n Цифровая подпись: %i байт",signsize); printf("\n Digital Signature: %i bytes",signsize);
printf("\n Хеш открытого ключа: %s",signver_hash); printf("\n Public Key Hash: %s",signver_hash);
} }
if (((signsize == -1) && (dload_id>7)) || if (((signsize == -1) && (dload_id>7)) ||
((signsize != -1) && (dload_id<8))) ((signsize != -1) && (dload_id<8)))
printf("\n ! ВНИМАНИЕ: Наличие цифровой подписи не соответствует коду типа прошивки: %02x",dload_id); printf("\n ! WARNING: The present of a digital signature does not match the firmware type code: %02x",dload_id);
return npart; return npart;
} }
//******************************************************* //*******************************************************
//* Поиск разделов в многофайловом режиме //* Partition search in multi-file procedure
//******************************************************* //*******************************************************
void findfiles (char* fdir) { void findfiles (char* fdir) {
char filename[200]; char filename[200];
FILE* in; FILE* in;
printf("\n Поиск файлов-образов разделов...\n\n ## Размер ID Имя Файл\n-----------------------------------------------------------------\n"); printf("\n Searching for partition image files...\n\n ## Size ID Name File\n-----------------------------------------------------------------\n");
for (npart=0;npart<30;npart++) { for (npart=0;npart<30;npart++) {
if (find_file(npart, fdir, filename, &ptable[npart].hd.code, &ptable[npart].hd.psize) == 0) break; // конец поиска - раздела с таким ID не нашли if (find_file(npart, fdir, filename, &ptable[npart].hd.code, &ptable[npart].hd.psize) == 0) break; // end of search - no partition with this ID was found
// получаем символическое имя раздела // get the symbolic name of the partition
find_pname(ptable[npart].hd.code,ptable[npart].pname); find_pname(ptable[npart].hd.code,ptable[npart].pname);
printf("\n %02i %8i %08x %-14.14s %s",npart,ptable[npart].hd.psize,ptable[npart].hd.code,ptable[npart].pname,filename);fflush(stdout); printf("\n %02i %8i %08x %-14.14s %s",npart,ptable[npart].hd.psize,ptable[npart].hd.code,ptable[npart].pname,filename);fflush(stdout);
// распределяем память под образ раздела // allocate memory for the partition image
ptable[npart].pimage=malloc(ptable[npart].hd.psize); ptable[npart].pimage=malloc(ptable[npart].hd.psize);
if (ptable[npart].pimage == 0) { if (ptable[npart].pimage == 0) {
printf("\n! Ошибка распределения памяти, раздел #%i, размер = %i байт\n",npart,ptable[npart].hd.psize); printf("\n! Memory allocation error, partition #%i, size = %i bytes\n",npart,ptable[npart].hd.psize);
exit(0); exit(0);
} }
// читаем образ в буфер // read image to buffer
in=fopen(filename,"rb"); in=fopen(filename,"rb");
if (in == 0) { if (in == 0) {
printf("\n Ошибка открытия файла %s",filename); printf("\n Can't open file %s",filename);
return; return;
} }
fread(ptable[npart].pimage,ptable[npart].hd.psize,1,in); fread(ptable[npart].pimage,ptable[npart].hd.psize,1,in);
fclose(in); fclose(in);
} }
if (npart == 0) { if (npart == 0) {
printf("\n! Не найдено ни одного файла с образом раздела в каталоге %s",fdir); printf("\n! No partition image files were found in directory %s",fdir);
exit(0); exit(0);
}
} }
}

@ -1,46 +1,43 @@
// partition header structure description
// структура описания заголовка раздела
#ifndef WIN32 #ifndef WIN32
struct __attribute__ ((__packed__)) pheader { struct __attribute__ ((__packed__)) pheader {
#else #else
#pragma pack(push,1) #pragma pack(push,1)
struct pheader { struct pheader {
#endif #endif
int32_t magic; // 0xa55aaa55 int32_t magic; // 0xa55aaa55
uint32_t hdsize; // размер заголовка uint32_t hdsize; // header size
uint32_t hdversion; uint32_t hdversion;
uint8_t unlock[8]; uint8_t unlock[8];
uint32_t code; // тип раздела uint32_t code; // partition type
uint32_t psize; // разме поля данных uint32_t psize; // data field size
uint8_t date[16]; uint8_t date[16];
uint8_t time[16]; // дата-время сборки прошивки uint8_t time[16]; // date of firmware build
uint8_t version[32]; // версия пршоивки uint8_t version[32]; // firmware version
uint16_t crc; // CRC заголовка uint16_t crc; // CRC header
uint32_t blocksize; // размер блока CRC образа прошивки uint32_t blocksize; // size of CRC block of firmware image
}; };
#ifdef WIN32 #ifdef WIN32
#pragma pack(pop) #pragma pack(pop)
#endif #endif
// partition table structure description
// Структура описания таблицы разделов
struct ptb_t{ struct ptb_t{
unsigned char pname[20]; // буквенное имя раздела unsigned char pname[20]; // alphabetic name of the partition
struct pheader hd; // образ заголовка struct pheader hd; // header image
uint16_t* csumblock; // блок контрольных сумм uint16_t* csumblock; // checksum block
uint8_t* pimage; // образ раздела uint8_t* pimage; // partition image
uint32_t offset; // смещение в файле до начала раздела uint32_t offset; // offset in file before start of partition
uint32_t zflag; // признак сжатого раздела uint32_t zflag; // flag of a compressed partition
uint8_t ztype; // тип сжатия uint8_t ztype; // compression type
}; };
//****************************************************** //******************************************************
//* Внешние массивы для хранения таблицы разделов //* External arrays to store the partition table
//****************************************************** //******************************************************
extern struct ptb_t ptable[]; extern struct ptb_t ptable[];
extern int npart; // число разделов в таблице extern int npart; // number of partitions in table
extern uint32_t errflag; extern uint32_t errflag;

@ -1,7 +1,5 @@
// // Procedures for digital signature processing
// Процедуры обработки цифровых подписей
//
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#ifndef WIN32 #ifndef WIN32
@ -27,24 +25,23 @@
#include "util.h" #include "util.h"
#include "zlib.h" #include "zlib.h"
// таблица параметров ключа -g // table of key parameters -g
struct { struct {
uint8_t type; uint8_t type;
uint32_t len; uint32_t len;
char* descr; char* descr;
} signbase[] = { } signbase[] = {
{1,2958,"Основная прошивка"}, {1,2958,"Basic Firmware"},
{1,2694,"Прошивка E3372s-stick"}, {1,2694,"E3372s-Stick Firmware"},
{2,1110,"Вебинтерфейс+ISO для HLINK-модема"}, {2,1110,"Web-Interface + ISO for HiLink-Modem"},
{6,1110,"Вебинтерфейс+ISO для HLINK-модема"}, {6,1110,"Web-Interface + ISO for HiLink-Modem"},
{2,846,"ISO (dashboard) для stick-модема"}, {2,846,"ISO (Dashboard) for Stick-Modem"},
{7,3750,"Прошивка+ISO+вебинтерфейс"}, {7,3750,"Firmware + ISO + Web-Interface"},
}; };
#define signbaselen 6 #define signbaselen 6
// таблица типов подписей // table of signature types
char* fwtypes[]={ char* fwtypes[]={
"UNKNOWN", // 0 "UNKNOWN", // 0
"ONLY_FW", // 1 "ONLY_FW", // 1
@ -54,43 +51,40 @@ char* fwtypes[]={
"FW_WEBUI", // 5 "FW_WEBUI", // 5
"ISO_WEBUI", // 6 "ISO_WEBUI", // 6
"FW_ISO_WEBUI" // 7 "FW_ISO_WEBUI" // 7
}; };
// результирующая строка ^signver-команды // result string ^signver-command
uint8_t signver[200]; uint8_t signver[200];
// Флаг режима цифровой подписи // digital type signature flag
extern int gflag; extern int gflag;
// Флаг типа прошивки // firmware type flag
extern int dflag; extern int dflag;
// Параметры текущей цифровой подписи // parameters of the current digital signature
uint32_t signtype; // тип прошивки uint32_t signtype; // firmware type
uint32_t signlen; // длина подписи uint32_t signlen; // signature length
int32_t serach_sign(); int32_t serach_sign();
// Хеш открытого ключа для ^signver // public key hash for ^signver
char signver_hash[100]="778A8D175E602B7B779D9E05C330B5279B0661BF2EED99A20445B366D63DD697"; char signver_hash[100]="778A8D175E602B7B779D9E05C330B5279B0661BF2EED99A20445B366D63DD697";
//**************************************************** //****************************************************
//* Получение описания типа прошивки по коду //* Receiving of firmware type description by code
//**************************************************** //****************************************************
char* fw_description(uint8_t code) { char* fw_description(uint8_t code) {
return fwtypes[code&0x7];
return fwtypes[code&0x7];
} }
//**************************************************** //****************************************************
//* Получение списка типов прошивок //* Receiving of firmware type list
//**************************************************** //****************************************************
void dlist() { void dlist() {
int i; int i;
printf("\n # Описание\n--------------------------------------"); printf("\n # Description\n--------------------------------------");
for(i=1;i<8;i++) { for(i=1;i<8;i++) {
printf("\n %i %s",i,fw_description(i)); printf("\n %i %s",i,fw_description(i));
} }
@ -99,87 +93,85 @@ exit(0);
} }
//*************************************************** //***************************************************
//* Обработка параметров ключа -d //* Processing of key parameters -d
//*************************************************** //***************************************************
void dparm(char* sparm) { void dparm(char* sparm) {
if (dflag != 0) { if (dflag != 0) {
printf("\n Дублирующийся ключ -d\n\n"); printf("\n Duplicate option -d\n\n");
exit(-1); exit(-1);
} }
if (sparm[0] == 'l') { if (sparm[0] == 'l') {
dlist(); dlist();
exit(0); exit(0);
} }
sscanf(sparm,"%x",&dload_id); sscanf(sparm,"%x",&dload_id);
if ((dload_id == 0) || (dload_id >7)) { if ((dload_id == 0) || (dload_id >7)) {
printf("\n Неправильное значение ключа -d\n\n"); printf("\n Incorrect value for option -d\n\n");
exit(-1); exit(-1);
} }
dflag=1; dflag=1;
} }
//**************************************************** //****************************************************
//* Получение списка параметров ключа -g //* Get a list of -g key parameters
//**************************************************** //****************************************************
void glist() { void glist() {
int i; int i;
printf("\n # длина тип описание \n--------------------------------------"); printf("\n # Length Type Description \n--------------------------------------");
for (i=0; i<signbaselen; i++) { for (i=0; i<signbaselen; i++) {
printf("\n%1i %5i %2i %s",i,signbase[i].len,signbase[i].type,signbase[i].descr); printf("\n%1i %5i %2i %s",i,signbase[i].len,signbase[i].type,signbase[i].descr);
} }
printf("\n\n Также можно указать произвольные параметры подписи в формате:\n -g *,type,len\n\n"); printf("\n\n You can also specify arbitrary signature parameters in the format:\n -g *,type,len\n\n");
exit(0); exit(0);
} }
//*************************************************** //***************************************************
//* Обработка параметров ключа -g //* Processing -g option parameters
//*************************************************** //***************************************************
void gparm(char* sparm) { void gparm(char* sparm) {
int index; int index;
char* sptr; char* sptr;
char parm[100]; char parm[100];
if (gflag != 0) { if (gflag != 0) {
printf("\n Дублирующийся ключ -g\n\n"); printf("\n Duplicate option -g\n\n");
exit(-1); exit(-1);
} }
strcpy(parm,sparm); // локальная копия параметров strcpy(parm,sparm); // local copy of parameters
if (parm[0] == 'l') { if (parm[0] == 'l') {
glist(); glist();
exit(0); exit(0);
} }
if (parm[0] == 'd') { if (parm[0] == 'd') {
// запрет автоопределения подписи // disable signature auto-detection
gflag = -1; gflag = -1;
return; return;
} }
if (strncmp(parm,"*,",2) == 0) { if (strncmp(parm,"*,",2) == 0) {
// произвольные параметры // arbitrary parameters
// выделяем длину // select length
sptr=strrchr(parm,','); sptr=strrchr(parm,',');
if (sptr == 0) goto perror; if (sptr == 0) goto perror;
signlen=atoi(sptr+1); signlen=atoi(sptr+1);
*sptr=0; *sptr=0;
// выделяем тип раздела // select partition type
sptr=strrchr(parm,','); sptr=strrchr(parm,',');
if (sptr == 0) goto perror; if (sptr == 0) goto perror;
signtype=atoi(sptr+1); signtype=atoi(sptr+1);
if (fw_description(signtype) == 0) { if (fw_description(signtype) == 0) {
printf("\n Ключ -g: неизвестный тип прошивки - %i\n",signtype); printf("\n Option -g: Unknown firmware type - %i\n",signtype);
exit(-1); exit(-1);
} }
} }
else { else {
index=atoi(parm); index=atoi(parm);
if (index >= signbaselen) goto perror; if (index >= signbaselen) goto perror;
signlen=signbase[index].len; signlen=signbase[index].len;
@ -191,39 +183,38 @@ gflag=1;
return; return;
perror: perror:
printf("\n Ошибка в параметрах ключа -g\n"); printf("\n Incorrect value in option -g\n");
exit(-1); exit(-1);
} }
//*************************************************** //***************************************************
//* Отправка цифровой подписи //* Sending digital signature
//*************************************************** //***************************************************
void send_signver() { void send_signver() {
uint32_t res; uint32_t res;
// ответ на ^signver // response to ^signver
unsigned char SVrsp[]={0x0d, 0x0a, 0x30, 0x0d, 0x0a, 0x0d, 0x0a, 0x4f, 0x4b, 0x0d, 0x0a}; unsigned char SVrsp[]={0x0d, 0x0a, 0x30, 0x0d, 0x0a, 0x0d, 0x0a, 0x4f, 0x4b, 0x0d, 0x0a};
uint8_t replybuf[200]; uint8_t replybuf[200];
if (gflag == 0) { if (gflag == 0) {
// автоопределение цифровой подписи // auto-detect digital signature
signtype=dload_id&0x7; signtype=dload_id&0x7;
signlen=serach_sign(); signlen=serach_sign();
if (signlen == -1) return; // подпись в файле не найдена if (signlen == -1) return; // no signature found in the file
} }
printf("\n Режим цифровой подписи: %s (%i байт)",fw_description(signtype),signlen); printf("\n Digital Signature Type: %s (%i bytes)",fw_description(signtype),signlen);
sprintf(signver,"^SIGNVER=%i,0,%s,%i",signtype,signver_hash,signlen); sprintf(signver,"^SIGNVER=%i,0,%s,%i",signtype,signver_hash,signlen);
res=atcmd(signver,replybuf); res=atcmd(signver,replybuf);
if ( (res<sizeof(SVrsp)) || (memcmp(replybuf,SVrsp,sizeof(SVrsp)) != 0) ) { if ( (res<sizeof(SVrsp)) || (memcmp(replybuf,SVrsp,sizeof(SVrsp)) != 0) ) {
printf("\n ! Ошибка проверки цифровой сигнатуры - %02x\n",replybuf[2]); printf("\n ! Error checking digital signature - %02x\n",replybuf[2]);
exit(-2); exit(-2);
} }
} }
//*************************************************** //***************************************************
//* Поиск цифровой подписи в прошивке //* Search for digital signature in firmware
//*************************************************** //***************************************************
int32_t serach_sign() { int32_t serach_sign() {
@ -234,16 +225,16 @@ uint32_t signsize;
for (i=0;i<2;i++) { for (i=0;i<2;i++) {
if (i == npart) break; if (i == npart) break;
pt=*((uint32_t*)&ptable[i].pimage[ptable[i].hd.psize-4]); pt=*((uint32_t*)&ptable[i].pimage[ptable[i].hd.psize-4]);
if (pt == 0xffaaaffa) { if (pt == 0xffaaaffa) {
// подпись найдена // signature found
signsize=*((uint32_t*)&ptable[i].pimage[ptable[i].hd.psize-12]); signsize=*((uint32_t*)&ptable[i].pimage[ptable[i].hd.psize-12]);
// выделяем хеш открытого ключа // select public key hash
for(j=0;j<32;j++) { for(j=0;j<32;j++) {
sprintf(signver_hash+2*j,"%02X",ptable[i].pimage[ptable[i].hd.psize-signsize+6+j]); sprintf(signver_hash+2*j,"%02X",ptable[i].pimage[ptable[i].hd.psize-signsize+6+j]);
} }
return signsize; return signsize;
} }
} }
// не найдена // not found
return -1; return -1;
} }

@ -1,6 +1,5 @@
extern char signver_hash[100]; extern char signver_hash[100];
void glist(); void glist();
void gparm(char* sparm); void gparm(char* sparm);
void dparm(char* sparm); void dparm(char* sparm);
@ -8,5 +7,4 @@ void send_signver();
char* fw_description(uint8_t code); char* fw_description(uint8_t code);
int32_t serach_sign(); int32_t serach_sign();
extern char* fwtypes[];
extern char* fwtypes[];

186
util.c

@ -1,6 +1,5 @@
// // Supporting routines of balong_flash
// Вспомогательные процедуры проекта balong_flash
//
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#ifndef WIN32 #ifndef WIN32
@ -25,10 +24,8 @@
#include "flasher.h" #include "flasher.h"
#include "util.h" #include "util.h"
//*********************** //***********************
//* Дамп области памяти * //* Memory area dump *
//*********************** //***********************
void dump(char buffer[],int len,long base) { void dump(char buffer[],int len,long base) {
@ -54,9 +51,8 @@ for (i=0;i<len;i+=16) {
} }
} }
//************************************************* //*************************************************
//* Вычисление CRC-16 //* Calculate CRC-16
//************************************************* //*************************************************
unsigned short crc16(char* buf, int len) { unsigned short crc16(char* buf, int len) {
@ -95,23 +91,23 @@ unsigned short crctab[] = {
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
}; };
int i; int i;
unsigned short crc=0xffff; unsigned short crc=0xffff;
for(i=0;i<len;i++) crc=crctab[(buf[i]^crc)&0xff]^((crc>>8)&0xff); for(i=0;i<len;i++) crc=crctab[(buf[i]^crc)&0xff]^((crc>>8)&0xff);
return (~crc)&0xffff; return (~crc)&0xffff;
} }
//**************************************************** //****************************************************
//* Определение версии прошивальщика //* Firmware Version Detection
//* //*
//* 0 - нет ответа на команду //* 0 - No response to command
//* 1 - версия 2.0 //* 1 - Version 2.0
//* -1 - версия не 2.0 //* -1 - Version not 2.0
//**************************************************** //****************************************************
int dloadversion() { int dloadversion() {
int res; int res;
int i; int i;
uint8_t replybuf[4096]; uint8_t replybuf[4096];
res=atcmd("^DLOADVER?",replybuf); res=atcmd("^DLOADVER?",replybuf);
@ -119,34 +115,34 @@ if (res == 0) return 0;
if (strncmp(replybuf+2,"2.0",3) == 0) return 1; if (strncmp(replybuf+2,"2.0",3) == 0) return 1;
for (i=2;i<res;i++) { for (i=2;i<res;i++) {
if (replybuf[i] == 0x0d) replybuf[i]=0; if (replybuf[i] == 0x0d) replybuf[i]=0;
} }
printf("\n! Неправильная версия монитора прошивки - [%i]%s\n",res,replybuf+2); printf("\n! Incorrect version of the firmware viewer - [%i]%s\n",res,replybuf+2);
// dump(replybuf,res,0); // dump(replybuf,res,0);
return -1; return -1;
} }
//**************************************************** //****************************************************
//*------- Режим разрезания файла прошивки //* Splitting firmware file
//**************************************************** //****************************************************
void fwsplit(uint32_t sflag) { void fwsplit(uint32_t sflag) {
uint32_t i; uint32_t i;
FILE* out; FILE* out;
uint8_t filename[200]; uint8_t filename[200];
printf("\n Выделение разделов из файла прошивки:\n\n ## Смещение Размер Имя\n-------------------------------------"); printf("\n Partitioning of the firmware file:\n\n ## Offset Size Name\n-------------------------------------");
for (i=0;i<npart;i++) { for (i=0;i<npart;i++) {
printf("\n %02i %08x %8i %s",i,ptable[i].offset,ptable[i].hd.psize,ptable[i].pname); printf("\n %02i %08x %8i %s",i,ptable[i].offset,ptable[i].hd.psize,ptable[i].pname);
// формируем имя файла // from file
sprintf(filename,"%02i-%08x-%s.%s",i,ptable[i].hd.code,ptable[i].pname,(sflag?"fw":"bin")); sprintf(filename,"%02i-%08x-%s.%s",i,ptable[i].hd.code,ptable[i].pname,(sflag?"fw":"bin"));
out=fopen(filename,"wb"); out=fopen(filename,"wb");
if(sflag) { if(sflag) {
// запись заголовка // record header
fwrite(&ptable[i].hd,1,sizeof(struct pheader),out); // фиксированный заголовок fwrite(&ptable[i].hd,1,sizeof(struct pheader),out); // fixed header
fwrite((void*)ptable[i].csumblock,1,ptable[i].hd.hdsize-sizeof(struct pheader),out); // блок контрольных сумм fwrite((void*)ptable[i].csumblock,1,ptable[i].hd.hdsize-sizeof(struct pheader),out); // block checksum
} }
// запись тела // body record
fwrite(ptable[i].pimage,ptable[i].hd.psize,1,out); fwrite(ptable[i].pimage,ptable[i].hd.psize,1,out);
fclose(out); fclose(out);
} }
@ -154,155 +150,145 @@ printf("\n");
return; return;
} }
//**************************************************** //****************************************************
//* Вход в HDLC-режим //* Entering HDLC-Mode
//**************************************************** //****************************************************
void enter_hdlc() { void enter_hdlc() {
uint32_t res; uint32_t res;
unsigned char OKrsp[]={0x0d, 0x0a, 0x4f, 0x4b, 0x0d, 0x0a}; unsigned char OKrsp[]={0x0d, 0x0a, 0x4f, 0x4b, 0x0d, 0x0a};
uint8_t replybuf[100]; uint8_t replybuf[100];
usleep(100000); usleep(100000);
res=atcmd("^DATAMODE",replybuf); res=atcmd("^DATAMODE",replybuf);
if (res != 6) { if (res != 6) {
printf("\n Неправильная длина ответа на ^DATAMODE"); printf("\n Incorrect response length to ^DATAMODE");
exit(-2); exit(-2);
} }
if (memcmp(replybuf,OKrsp,6) != 0) { if (memcmp(replybuf,OKrsp,6) != 0) {
printf("\n Команда ^DATAMODE отвергнута, возможно требуется режим цифровой подписи\n"); printf("\n Command ^DATAMODE rejected, possibly requires digital signature mode\n");
exit(-2); exit(-2);
} }
} }
//**************************************************** //****************************************************
//* Выход из HDLC-режима //* Leaving HDLC-Mode
//**************************************************** //****************************************************
void leave_hdlc() { void leave_hdlc() {
uint8_t replybuf[100]; uint8_t replybuf[100];
unsigned char cmddone[7]={0x1}; // команда выхода из HDLC unsigned char cmddone[7]={0x1}; // HDLC quit command
send_cmd(cmddone,1,replybuf); send_cmd(cmddone,1,replybuf);
} }
//**************************************************** //****************************************************
//* Получение версии протокол прошивки //* Get Firmware Version
//**************************************************** //****************************************************
void protocol_version() { void protocol_version() {
uint8_t replybuf[100]; uint8_t replybuf[100];
uint32_t iolen,i; uint32_t iolen,i;
unsigned char cmdver[7]={0x0c}; // команда запроса версии протокола unsigned char cmdver[7]={0x0c}; // request the protocol version
iolen=send_cmd(cmdver,1,replybuf); iolen=send_cmd(cmdver,1,replybuf);
if (iolen == 0) { if (iolen == 0) {
printf("\n Нет ответа от модема в HDLC-режиме\n"); printf("\n No response from modem in HDLC-Mode\n");
exit(-2); exit(-2);
} }
if (replybuf[0] == 0x7e) memcpy(replybuf,replybuf+1,iolen-1); if (replybuf[0] == 0x7e) memcpy(replybuf,replybuf+1,iolen-1);
if (replybuf[0] != 0x0d) { if (replybuf[0] != 0x0d) {
printf("\n Ошибка получения версии протокола\n"); printf("\n Failed to get protocol version\n");
exit(-2); exit(-2);
} }
i=replybuf[1]; i=replybuf[1];
replybuf[2+i]=0; replybuf[2+i]=0;
printf("\n Версия протокола: %s",replybuf+2); printf("\n Protocol Version: %s",replybuf+2);
} }
//**************************************************** //****************************************************
//* Перезагрузка модема //* Reboot Modem
//**************************************************** //****************************************************
void restart_modem() { void restart_modem() {
unsigned char cmd_reset[7]={0xa}; // команда выхода из HDLC unsigned char cmd_reset[7]={0xa}; // HDLC exit command
uint8_t replybuf[100]; uint8_t replybuf[100];
printf("\n Перезагрузка модема...\n"); printf("\n Rebooting modem...\n");
send_cmd(cmd_reset,1,replybuf); send_cmd(cmd_reset,1,replybuf);
atcmd("^RESET",replybuf); atcmd("^RESET",replybuf);
} }
//**************************************************** //****************************************************
//* Получение идентификатора устройства //* Receiving Device ID
//**************************************************** //****************************************************
void dev_ident() { void dev_ident() {
uint8_t replybuf[100]; uint8_t replybuf[100];
uint32_t iolen; uint32_t iolen;
unsigned char cmd_getproduct[30]={0x45}; unsigned char cmd_getproduct[30]={0x45};
iolen=send_cmd(cmd_getproduct,1,replybuf); iolen=send_cmd(cmd_getproduct,1,replybuf);
if (iolen>2) printf("\n Идентификатор устройства: %s",replybuf+2); if (iolen>2) printf("\n Device Identifier: %s",replybuf+2);
} }
//**************************************************** //****************************************************
//* Вывод карты файла прошивки //* Firmware File Map Output
//**************************************************** //****************************************************
void show_file_map() { void show_file_map() {
int i; int i;
printf("\n\n ## Смещение Размер Сжатие Имя\n-----------------------------------------------"); printf("\n\n ## Offset Size Compression Name\n-----------------------------------------------");
for (i=0;i<npart;i++) { for (i=0;i<npart;i++) {
printf("\n %02i %08x %8i ",i,ptable[i].offset,ptable[i].hd.psize); printf("\n %02i %08x %8i ",i,ptable[i].offset,ptable[i].hd.psize);
if (ptable[i].zflag == 0) if (ptable[i].zflag == 0)
// несжатый раздел // compressed partition
printf(" "); printf(" ");
else { else {
// сжатый раздел // shrunken partition
switch(ptable[i].ztype) { switch(ptable[i].ztype) {
case 'L': case 'L':
printf("Lzma"); printf("LZMA");
break; break;
case 'Z': case 'Z':
printf("Gzip"); printf("gzip");
break; break;
} }
printf(" %3i%% ",(ptable[i].hd.psize-ptable[i].zflag)*100/ptable[i].hd.psize); printf(" %3i%% ",(ptable[i].hd.psize-ptable[i].zflag)*100/ptable[i].hd.psize);
} }
printf(" %s",ptable[i].pname); printf(" %s",ptable[i].pname);
} }
printf("\n"); printf("\n");
exit(0); exit(0);
} }
//**************************************************** //****************************************************
//* Вывод информации о файле прошивки //* Firmware File Info Output
//**************************************************** //****************************************************
void show_fw_info() { void show_fw_info() {
uint8_t* sptr; uint8_t* sptr;
char ver[36]; char ver[36];
if (ptable[0].hd.version[0] != ':') printf("\n Версия прошивки: %s",ptable[0].hd.version); // нестандартная строка версии if (ptable[0].hd.version[0] != ':') printf("\n Firmware Version: %s",ptable[0].hd.version); // non-standard version string
else { else {
// стандартная строка версии // standard version string
memset(ver,0,sizeof(ver)); memset(ver,0,sizeof(ver));
strncpy(ver,ptable[0].hd.version,32); strncpy(ver,ptable[0].hd.version,32);
sptr=strrchr(ver+1,':'); // ищем разделитель-двоеточие sptr=strrchr(ver+1,':'); // search for delimiter colon
if (sptr == 0) printf("\n Версия прошивки: %s",ver); // не найдено - несоответствие стандарту if (sptr == 0) printf("\n Firmware Version: %s",ver); // not found - non-compliant with standard
else { else {
*sptr=0; *sptr=0;
printf("\n Версия прошивки: %s",sptr+1); printf("\n Firmware Version: %s",sptr+1);
printf("\n Платформа: %s",ver+1); printf("\n Platform: %s",ver+1);
} }
}
printf("\n Дата сборки: %s %s",ptable[0].hd.date,ptable[0].hd.time);
printf("\n Заголовок: версия %i, код соответствия: %8.8s",ptable[0].hd.hdversion,ptable[0].hd.unlock);
} }
printf("\n Build Date: %s %s",ptable[0].hd.date,ptable[0].hd.time);
printf("\n Title: %i Version, Conformity Code: %8.8s",ptable[0].hd.hdversion,ptable[0].hd.unlock);
}

@ -1,4 +1,5 @@
#include <stdint.h> #include <stdint.h>
void dump(char buffer[],int len,long base); void dump(char buffer[],int len,long base);
unsigned short crc16(char* buf, int len); unsigned short crc16(char* buf, int len);
int dloadversion(); int dloadversion();

Loading…
Cancel
Save