首先给出原始代码的分析,我使用的是Ubuntu的代码,打算在Linux和Cygwin下都能用。
Gkermit代码分析
前言
Cygwin串口设备映射
linux下的/dev/ttyS[n]在cygwin会映射到Windows串口设备 //./COM[n + 1]
例如 /dev/ttyS0 等价于 COM1
一、代码组织结构
++- .
+- gkermit.h 程序公共头文件
+- gkermit.c 程序入口、字符编解码、打包解包、有效性验证 (main入口)
+- gcmdline.c 命令行分析相关的代码
+- gunixio.c Unix IO 相关的操作
+- gproto.w 状态机源代码
gproto.c 自动生成的代码
+- gwart.c 简易的lex分析器,用于处理.w代码,生成.c的文件
二、基本函数列表
------ 字符接口 ------
gkermit.h ---------------------------------------------------------------------------------
#define tochar(ch) ((ch) + SP ) 转换整型到可打印字符,参见标准P13页
#define xunchar(ch) ((ch) - SP ) tochar的反向操作
#define ctl(ch) ((ch) ^ 64 ) 控制字符和可打印字符的转换
#define zgetc(a) (((--zincnt)>=0) ? 如果缓冲为空则实际读取文件
((int)(*zinptr++) & 0xff) :
zfillbuf(a))
------ 函数原型 ------
gunixio.c ---------------------------------------------------------------------------------
SIGTYP doexit (int) 结束程序:正常或异常退出
VOID sysinit (void) 系统初始化:
char dopar (char) Parity奇偶校验
VOID tmsg (char *) 将参数指向的字符串输出到终端
VOID tmsgl (char *) 将参数指向的字符串输出到终端(带换行)
int ttopen (char *) 打开设备
int ttpkt (int) 设置通信设备工作在RAW模式
int ttres (void) 复位通信设备
int ttinl (char *, 读取一个包:以EOL结尾,包含超时机制
int,
int,
char,
char,
int)
int ttol (char *, 发送一个包:原样发送上层提供的包
int)
int ttchk (void) 查看输入是否正常
int ttflui (void) 同步缓冲到设备
long zchki (char *) 查看文件是否可被读取
int zchko (char *) 查看文件是否可被写入
int zopeni (char *) 打开现存的文件:就是用于发送的文件
int zopeno (char *) 新建一个输出文件:就是用于存放接收到的文件
int zclosi (void) 关闭输入文件句柄
int zcloso (int) 关闭输出文件句柄
int zfillbuf (int) 从文件读取到缓冲
VOID zltor (char *, 本地到远程的文件名转换,同时处理文件名中的特殊字符:local to remote
char *,
int)
int zrtol (char *, 远程到本地的文件名转换,同时处理文件名中的特殊字符:remote to local
char *,
int,
int)
int zbackup (char *) 备份已有的文件:在文件名后加上“.~数字~”
gkermit.c ---------------------------------------------------------------------------------
int input (void) 被状态机调用:获取输入文件的包
VOID nxtpkt (void) 初始化下一个包的序列号
int ack (void) 发送DATA是空的ACK回复包:调用 spacket 函数
int ack1 (char *) 发送含有特定串的ACK回复包
int nak (void) 发送拒绝包
VOID tinit (void) “发送”传输回话初始化
VOID errpkt (char *) 发送ERROR包
int sinit (char) 发送 S(Init packet)
int sfile (void) 发送 F(File header packet)
int sdata (void) 发送 Send Data packet
int seof (char *) 发送 Send EOF packet
int seot (void) 发送 Send EOT packet
int resend (void) 包的重发
int decode (int) 解析包的 data field
int encstr (char *) 从字符串编码生成数据包:调用 getpkt 函数
int gattr (char *) 接收文件属性包
int sattr (void) 发送文件属性包
VOID ginit (void) “接收”传输会话初始化
int scmd (char, char *) 发送kermit命令到server
VOID rinit (void) 接收 Init 包
int gnfile (void) 获取下一个发送的文件名
int rcvfil (void) 接收文件
VOID spar (char *) 设置kermit运行参数:从收到的数据中获得参数
char *rpar (void) 回复kermit运行参数:本地使用的参数
VOID usage (void) 输出帮助信息
------ 只在 gkermic.c 中使用的函数:非全局使用的函数 ------
int spacket (char,int,int,char *) 构建一个包并发送:调用 ttol 函数发送
int rpacket (void) 读取一个包并解析:调用 ttinl 函数读取
unsigned int chk1 (char *,int) 12bit 块 校验:调用了chksum函数
unsigned int chk3 (char *,int) 16bit CRC校验
unsigned int chksum (char *,int) 算数校验
int getpkt (int) 从文件读取数据并构建包
VOID encode (int,int) 将一个字符编码进包
VOID decstr (char *) 解包并存到字符串缓冲之中:调用 decode 函数
gcmdline.c --------------------------------------------------------------------------------
int cmdlin (void) 命令行Parser,只是处理命令行参数,并
用提取的参数更新全局参数变量。
gproto.c ----------------------------------------------------------------------------------
int gwart (void) 状态机调度表
三、函数调用关系
由于大部分系统相关的操作都在gunixio.c,于是下面的分析都是对gunixio的调用的分析。
为了使用windows的本地的函数进行替换。只要移植gunixio.c里的函数就可以了,其他的代码在mingw和vc中都可编译通过
以下是在gunixio的所有函数执行的时候加入输出语句。
ttopen --打开串口
ttpkt --设置串口工作在raw模式
G-Kermit CU-1.00, Columbia University, 1999-12-25
* Open device /dev/ttyS0
* Escape back to your local Kermit and give a SEND command.
* KERMIT READY TO RECEIVE...
ttinl --读取包:所有串口的读取read都是通过这个函数,gwart调用input->rpacket->ttinl->read
ttflui --清空串口缓冲:丢弃输入,发送输出,结束之后进行状态处理(状态调度表)
* recv INIT
ttol --写入包:所有串口的写入write都是通过这个函数
ttinl --读取包
ttflui --......
* recv HEADER
zrtol --将远程的文件名转换为本地的
zbackup --判断本地是否有同名的文件,并处理备份
zchko --检查输出的文件是否可写
zchki --检查输出的文件是否可读
zopeno --打开输出文件的句柄
ttol --送出包
ttinl --读取包
ttflui --......
* recv ATTRIBUTES
* will RECEIVE 1 byte
ttol --送出包
ttinl --读取包
ttflui --......
* recv DATA [complete]
ttol --送出包
ttinl --读取包
ttflui --......
* recv EOF
zcloso
ttol --送出包
ttinl --读取包
ttflui --......
* recv EOT
ttol --读取包
* exchange filesize 0x1 [1] bytes
END
ttres
详细输出模式
G-Kermit CU-1.00, Columbia University, 1999-12-25: POSIX
MAXPATHLEN = 1024
cmdlin action = v
ttopen
ttopen __STDC__
ttopen SIG_V
ttopen nonblocking read/write
ttopen TINBUFSIZ = 4080
ttopen xonxoff = 0
ttopen noxonxoff = 0
ttopen ttflags -1
ttopen nomodes 0
ttopen nonblock = 0
ttpkt
input[v]
G-Kermit CU-1.00, Columbia University, 1999-12-25
* Open device /dev/ttyS0
* Escape back to your local Kermit and give a SEND command.
* KERMIT READY TO RECEIVE...
ttinl
ttinl read timo = 9
ttinl length = 25
PKT<-[^A9 S~' @-#Y3~*!J*0+++B"U1@G](27) rc=0
rpacket type=S, seq=00, len=22
chksum=1445
ttflui
ttflui = 0, errno = 0
input[S]
* recv INIT
spar attributes=1 longpackets=1
spar whatami = 0x22
spar streamok = -1
spar sysid [U1]
spar recognizes peer
rpar streamok=-1 whatami=38
chksum=1455
ttol
PKT->[^A9 Y~' @-#Y3~*!J*0+++F"U1@Q](28)
ttinl
ttinl read timo = 7
ttinl length = 13
PKT<-[^A-!Ftest.txt&4;](15) rc=0
rpacket type=F, seq=01, len=8
crc=25883
ttflui
ttflui = 0, errno = 0
input[F]
* recv HEADER
zrtol
zbackup
zbackup A test.txt: 8
zbackup B test.txt
zbackup test.txt.~2~: OK
rcvfil filename [test.txt]
zchko
zchki
zchko(.) x = 0 errno = 0
zopeno
zopeno test.txt: 0
crc=3239
ttol
PKT->[^A-!Ytest.txt RG](16)
ttinl
ttinl read timo = 7
ttinl length = 12
PKT<-[^A,"A""B81!1)R0](14) rc=0
rpacket type=A, seq=02, len=7
crc=40080
ttflui
ttflui = 0, errno = 0
input[A]
* recv ATTRIBUTES
* will RECEIVE 1 byte
crc=58689
ttol
PKT->[^A%"Y.5!](8)
ttinl
ttinl read timo = 7
ttinl length = 7
PKT<-[^A'#D#J'O!](9) rc=0
rpacket type=D, seq=03, len=2
crc=31681
ttflui
ttflui = 0, errno = 0
input[D]
* recv DATA [complete]
crc=64665
ttol
PKT->[^A%#Y/R9](8)
ttinl
ttinl read timo = 7
ttinl length = 5
PKT<-[^A%$Z(,*](7) rc=0
rpacket type=Z, seq=04, len=0
crc=33546
ttflui
ttflui = 0, errno = 0
input[Z]
* recv EOF
zcloso
zcloso(test.txt) cx = 0 keep = 0
crc=45457
ttol
PKT->[^A%$Y+&1](8)
ttinl
ttinl read timo = 7
ttinl length = 5
PKT<-[^A%%B 8;](7) rc=0
rpacket type=B, seq=05, len=0
crc=1563
ttflui
ttflui = 0, errno = 0
input[B]
* recv EOT
crc=43081
ttol
PKT->[^A%%Y*A)](8)
* exchange filesize 0x1 [1] bytes
END
ttres
exit 0