You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
339 lines
8.9 KiB
C
339 lines
8.9 KiB
C
// Low-level serial port and HDLC procedures
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <strings.h>
|
|
#include <termios.h>
|
|
#include <unistd.h>
|
|
#include <dirent.h>
|
|
|
|
#include "hdlcio.h"
|
|
#include "util.h"
|
|
|
|
unsigned int nand_cmd=0x1b400000;
|
|
unsigned int spp=0;
|
|
unsigned int pagesize=0;
|
|
unsigned int sectorsize=512;
|
|
unsigned int maxblock=0; // total number of flash blocks
|
|
char flash_mfr[30]={0};
|
|
char flash_descr[30]={0};
|
|
unsigned int oobsize=0;
|
|
|
|
static char pdev[500]; // serial port name
|
|
|
|
int siofd; // fd to work with the serial port
|
|
struct termios sioparm;
|
|
//int siofd; // fd for serial port operation
|
|
|
|
//*************************************************
|
|
//* Send buffer to modem
|
|
//*************************************************
|
|
unsigned int send_unframed_buf(char* outcmdbuf, unsigned int outlen) {
|
|
|
|
|
|
tcflush(siofd,TCIOFLUSH); // reset unread input buffer
|
|
|
|
write(siofd,"\x7e",1); // send prefix
|
|
|
|
if (write(siofd,outcmdbuf,outlen) == 0) { printf("\n Command writing error");return 0; }
|
|
tcdrain(siofd); // waiting for the end of the block output
|
|
|
|
return 1;
|
|
}
|
|
|
|
//******************************************************************************************
|
|
//* Receiving buffer with response from modem
|
|
//*
|
|
//* 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) {
|
|
|
|
int i,iolen,escflag,incount;
|
|
unsigned char c;
|
|
unsigned int res;
|
|
unsigned char replybuf[14000];
|
|
|
|
incount=0;
|
|
if (read(siofd,&c,1) != 1) {
|
|
// printf("\n No response from modem");
|
|
return 0; // modem didn't answer or answered incorrectly
|
|
}
|
|
//if (c != 0x7e) {
|
|
// printf("\n First byte of the answer is not 7e: %02x",c);
|
|
// return 0; // modem didn't answer or answered incorrectly
|
|
//}
|
|
replybuf[incount++]=c;
|
|
|
|
// read an array of data in a single block when processing command 03
|
|
if (masslen != 0) {
|
|
res=read(siofd,replybuf+1,masslen-1);
|
|
if (res != (masslen-1)) {
|
|
printf("\nResponse from the modem is too short: %i bytes, expected %i bytes\n",res+1,masslen);
|
|
dump(replybuf,res+1,0);
|
|
return 0;
|
|
}
|
|
incount+=masslen-1; // we already have a masslen byte in the buffer
|
|
// printf("\n ------ it mass --------");
|
|
// dump(replybuf,incount,0);
|
|
}
|
|
|
|
// take the remaining tail of the buffer
|
|
while (read(siofd,&c,1) == 1) {
|
|
replybuf[incount++]=c;
|
|
// printf("\n-- %02x",c);
|
|
if (c == 0x7e) break;
|
|
}
|
|
|
|
// conversion of the received buffer to remove ESC characters
|
|
escflag=0;
|
|
iolen=0;
|
|
for (i=0;i<incount;i++) {
|
|
c=replybuf[i];
|
|
if ((c == 0x7e)&&(iolen != 0)) {
|
|
iobuf[iolen++]=0x7e;
|
|
break;
|
|
}
|
|
if (c == 0x7d) {
|
|
escflag=1;
|
|
continue;
|
|
}
|
|
if (escflag == 1) {
|
|
c|=0x20;
|
|
escflag=0;
|
|
}
|
|
iobuf[iolen++]=c;
|
|
}
|
|
return iolen;
|
|
|
|
}
|
|
|
|
//***********************************************************
|
|
//* Command buffer conversion with Escape-substitution
|
|
//***********************************************************
|
|
unsigned int convert_cmdbuf(char* incmdbuf, int blen, char* outcmdbuf) {
|
|
|
|
int i,iolen,bcnt;
|
|
unsigned char cmdbuf[14096];
|
|
|
|
bcnt=blen;
|
|
memcpy(cmdbuf,incmdbuf,blen);
|
|
// write the CRC at the end of the buffer
|
|
*((unsigned short*)(cmdbuf+bcnt))=crc16(cmdbuf,bcnt);
|
|
bcnt+=2;
|
|
|
|
// data preprocessing with escaping of ESC-sequences
|
|
iolen=0;
|
|
outcmdbuf[iolen++]=cmdbuf[0]; // first byte is copied without modification
|
|
for(i=1;i<bcnt;i++) {
|
|
switch (cmdbuf[i]) {
|
|
case 0x7e:
|
|
outcmdbuf[iolen++]=0x7d;
|
|
outcmdbuf[iolen++]=0x5e;
|
|
break;
|
|
|
|
case 0x7d:
|
|
outcmdbuf[iolen++]=0x7d;
|
|
outcmdbuf[iolen++]=0x5d;
|
|
break;
|
|
|
|
default:
|
|
outcmdbuf[iolen++]=cmdbuf[i];
|
|
}
|
|
}
|
|
outcmdbuf[iolen++]=0x7e; // end byte
|
|
outcmdbuf[iolen]=0;
|
|
return iolen;
|
|
}
|
|
|
|
//***************************************************
|
|
//* Send a command to a port and receive the result
|
|
//***************************************************
|
|
int send_cmd(unsigned char* incmdbuf, int blen, unsigned char* iobuf) {
|
|
|
|
unsigned char outcmdbuf[14096];
|
|
unsigned int iolen;
|
|
|
|
iolen=convert_cmdbuf(incmdbuf,blen,outcmdbuf);
|
|
if (!send_unframed_buf(outcmdbuf,iolen)) return 0; // command transmission error
|
|
return receive_reply(iobuf,0);
|
|
}
|
|
|
|
//***************************************************
|
|
// Opening and configuring the serial port
|
|
//***************************************************
|
|
|
|
int open_port(char* devname) {
|
|
|
|
|
|
int i,dflag=1;
|
|
char devstr[200]={0};
|
|
|
|
|
|
if (strlen(devname) != 0) strcpy(pdev,devname); // save port name
|
|
else strcpy(devname,"/dev/ttyUSB0"); // if the port name is not set
|
|
|
|
// 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++) {
|
|
if ((devname[i]<'0') || (devname[i]>'9')) dflag=0;
|
|
}
|
|
// if there are only digits in the string, add the prefix /dev/ttyUSB
|
|
|
|
if (dflag) strcpy(devstr,"/dev/ttyUSB");
|
|
|
|
// copy the device name
|
|
strcat(devstr,devname);
|
|
|
|
siofd = open(devstr, O_RDWR | O_NOCTTY |O_SYNC);
|
|
if (siofd == -1) {
|
|
printf("\n! - Can't open serial port %s\n", devname);
|
|
exit(0);
|
|
}
|
|
bzero(&sioparm, sizeof(sioparm)); // prepare the attribute block termios
|
|
sioparm.c_cflag = B115200 | CS8 | CLOCAL | CREAD ;
|
|
sioparm.c_iflag = 0; // INPCK;
|
|
sioparm.c_oflag = 0;
|
|
sioparm.c_lflag = 0;
|
|
sioparm.c_cc[VTIME]=30; // timeout
|
|
sioparm.c_cc[VMIN]=0;
|
|
tcsetattr(siofd, TCSANOW, &sioparm);
|
|
|
|
tcflush(siofd,TCIOFLUSH); // cleaning output buffer
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
//*************************************
|
|
// set the timeout time of the port
|
|
//*************************************
|
|
|
|
void port_timeout(int timeout) {
|
|
|
|
bzero(&sioparm, sizeof(sioparm)); // prepare the attribute block termios
|
|
sioparm.c_cflag = B115200 | CS8 | CLOCAL | CREAD ;
|
|
sioparm.c_iflag = 0; // INPCK;
|
|
sioparm.c_oflag = 0;
|
|
sioparm.c_lflag = 0;
|
|
sioparm.c_cc[VTIME]=timeout; // timeout
|
|
sioparm.c_cc[VMIN]=0;
|
|
tcsetattr(siofd, TCSANOW, &sioparm);
|
|
}
|
|
|
|
//*************************************************
|
|
//* Search for a file by its number in the specified directory
|
|
//*
|
|
//* num - # of file
|
|
//* filename - buffer for full file name
|
|
//* id - variable, where the partition identifier will be written
|
|
//*
|
|
//* return
|
|
//* 0 - not found
|
|
//* 1 - found
|
|
//*************************************************
|
|
int find_file(int num, char* dirname, char* filename,unsigned int* id, unsigned int* size) {
|
|
|
|
DIR* fdir;
|
|
FILE* in;
|
|
unsigned int pt;
|
|
struct dirent* dentry;
|
|
char fpattern[5];
|
|
|
|
sprintf(fpattern,"%02i",num); // sample file search by 3 digits of the number
|
|
fdir=opendir(dirname);
|
|
if (fdir == 0) {
|
|
printf("\n Can't open directory %s\n",dirname);
|
|
exit(1);
|
|
}
|
|
|
|
// main loop - search for the file we need
|
|
while ((dentry=readdir(fdir)) != 0) {
|
|
if (dentry->d_type != DT_REG) continue; // skip everything except regular files
|
|
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);
|
|
// create a full filename in the result buffer
|
|
if (dentry == 0) return 0; // not found
|
|
strcpy(filename,dirname);
|
|
strcat(filename,"/");
|
|
// copy the file name into the result buffer
|
|
strcat(filename,dentry->d_name);
|
|
|
|
// 00-00000200-M3Boot.bin
|
|
// check the file name for '-' signs
|
|
if ((dentry->d_name[2] != '-') || (dentry->d_name[11] != '-')) {
|
|
printf("\n Incorrect format of file - %s\n",dentry->d_name);
|
|
exit(1);
|
|
}
|
|
|
|
// check the numeric partition ID field
|
|
if (strspn(dentry->d_name+3,"0123456789AaBbCcDdEeFf") != 8) {
|
|
printf("\n Partition ID error - non-digit character - %s\n",filename);
|
|
exit(1);
|
|
}
|
|
sscanf(dentry->d_name+3,"%8x",id);
|
|
|
|
// check file availability and readability
|
|
in=fopen(filename,"r");
|
|
if (in == 0) {
|
|
printf("\n Can't open file %s\n",filename);
|
|
exit(1);
|
|
}
|
|
if (fread(&pt,1,4,in) != 4) {
|
|
printf("\n Can't read file %s\n",filename);
|
|
exit(1);
|
|
}
|
|
|
|
// check that the file is a raw image, without a header
|
|
if (pt == 0xa55aaa55) {
|
|
printf("\n File %s has a header - not suitable for flashing\n",filename);
|
|
exit(1);
|
|
}
|
|
|
|
// What else can I check? I haven't figured it out yet.
|
|
|
|
// get the file size
|
|
fseek(in,0,SEEK_END);
|
|
*size=ftell(in);
|
|
fclose(in);
|
|
|
|
return 1;
|
|
}
|
|
|
|
//****************************************************
|
|
//* Send AT command to modem
|
|
//*
|
|
//* cmd - command buffer
|
|
//* rbuf - response buffer
|
|
//*
|
|
//* Returns the length of answer
|
|
//****************************************************
|
|
int atcmd(char* cmd, char* rbuf) {
|
|
|
|
int res;
|
|
char cbuf[128];
|
|
|
|
strcpy(cbuf,"AT");
|
|
strcat(cbuf,cmd);
|
|
strcat(cbuf,"\r");
|
|
|
|
port_timeout(100);
|
|
// clean up the receiver and transmitter buffer
|
|
tcflush(siofd,TCIOFLUSH);
|
|
|
|
// send command
|
|
write(siofd,cbuf,strlen(cbuf));
|
|
usleep(100000);
|
|
|
|
// read result
|
|
res=read(siofd,rbuf,200);
|
|
return res;
|
|
}
|