该作者通过复原传真整个过程,分析mgetty-1.1.36源码得到的分析结果,具有参考意义。
http://hi.baidu.com/kkernel/blog/item/c331c0291b7bdef999250aa0.html
Auther: Guo Wenxue Data: 2008.11.20
参考3类传真机收发传真的过程: http://hi.baidu.com/kkernel/blog/item/05ffd52e87e9b9574ec22663.html 参考mgetty-1.1.36的源代码分析:
PHASE A Modem发送命令: Ate0; At+fclass=1; Atdt628; //我们的传真分机号码
Modem返回: ======================Part1 : modem echo ======================== Rev 9: 0x61 0x74 0x64 0x74 0x36 0x32 0x38 0x0d 0x0a a t d t 6 2 8 /r /n
======================Part2: Fax return “Connect” ==================== Rev 11: 0x0d 0x0a 0x43 0x4f 0x4e 0x4e 0x45 0x43 0x54 0x0d 0x0a /r /n C O N N E C T /r /n
======================Part3: NSF Frame =========================== Rev 24: 0xff 0x03 0x20 0x00 0x00 0x56 0x55 0x55 0x00 0x8c 0x90 0x80 0x34 0x0c 0x94 0x37
0x10 0x03 0x0d 0x0a 0x4f 0x4b 0x0d 0x0a DLE ETX /r /n O K /r /n 注: 在class1.c的int fax1_dial_and_phase_AB _P2( (dial_cmd,fd), char * dial_cmd, int fd )函数中: 0x03 à0x10这一部分为NSF Frame,他由0x20这个值标志。
代码:
if ( (len = fax1_receive_frame( fd, first? 0:3, 30, framebuf ) ) //读Modem的返回到framebuf中 switch ( framebuf[1] ) { case T30_CSI: fax1_copy_id( framebuf ); break; case T30_NSF: fax1_incoming_nsf( framebuf+2, len-2 ); break; //如果是NSF case T30_DIS: fax1_parse_dis( framebuf ); break; //如果是DIS,下面介绍 case T30_DCN: fax1_send_dcn( fd, 20 ); return ERROR; default: lprintf( L_WARN, "unexpected frame type 0x%02x", framebuf[1] ); }
fax1_incoming_nsf定义在faxlib.c中; fax1_parse_dis定义在class1lib.c中;
======================Part4: Remote传真的相关信息======================== Rev 16: 0xff 0x03 0x40 0x32 0x30 0x37 0x30 0x33 0x37 0x39 0x35 0x37 0x32 0x30 0x20 0x20 ETX @ 2 0 7 0 3 7 9 5 7 2 0 SPACE SPACE //这是我们的传真号码
Rev 17: 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0xbd 0x64 0x10 0x03 0x0d 0x0a 0x4f 0x4b 0x0d 0x0a SPACE ---------------------------------> SPACE DLE ETX /r /n O K /r /n
==================Part5: DIS Frame Remote传真机的capability==================
Rev 19: 0xff 0x13 0x80 0x00 0xee 0xa8 0xc4 0x80 0x11 0xe7 0xb3 0x10 0x03 0x0d 0x0a 0x4f 0x4b 0x0d 0x0a 注:0x80标志这是DIS frame,参考上面的代码。 在class1lib.c的void fax1_parse_dis _P1((frame), uch * frame )函数中: 首先将frame知道0x00 (FIF), 这样frame[1]=0xee frame[2]=0xa8,下面按源代码的注释对这两个字节进行分析:0xee= 1110 1110 0xa8=1010 1000 BIT9是从0x00(FIF)这个位置开始偏移,即frame[1]的bit0,依次类推: BIT 9: 0->fax_to_poll=FALSE BIT 10: 1->Can receive //receiving capabilities BIT 11-14: 1110 1110(0xee)&0011 1100 (0x3c) = 0x2c 所以:case 0x2c: remote_cap.br = V17 | V29 | V27ter=ffe BIT 15: 1->remote_cap.vr = 1; BIT 16: 1->remote_cap.df = 1;
BIT 17-18: remote_cap.wd = frame[2] & 0x03; 页面宽度valid: 0/1/2 = 215/255/303 mm: 00->215mm BIT 19-20: remote_cap.ln = ( frame[2] >> 2 ) & 0x03; 页面长度valid: 0/1/2 = A4/B4/unlimited: 10->unlimited
BIT 21-23: remote_cap.st = fax1_st_table[ (frame[2] >> 4) & 0x07 ].st; (Frame[2]>>4)&0x07=0x0010=2 查表得:fax1_st_table[2].st = { 3, 10, 10, " 10ms" } /* 2 = 010 */ struct fax1_st_table { int st; int ms_n; int ms_f; char * txt; }; 所以remote_cap.st=3. BIT 24: extend bit if ( frame[2] & 0x80 ) /* extend bit */ 最高位为1,故为真 { /* bit 27: ECM */ if ( frame[3] & 0x04 ) // 0xc4 &0x80 = 0, 不带ECM remote_cap.ec = 1; }
PHASE B: 文件Class1lib.c的int fax1_send_dcs _P2((fd, s_time), int fd, int s_time )函数是modem向Remote FAX 发送DCS Frame: while( dcs_btp->speed > 2400 && ( dcs_btp->speed > fax1_max || ( dcs_btp->flag & fax1_ftm & remote_cap.br ) == 0 ) ) dcs_btp++; 其中: fax1_max初始化为最大速率14400,即V17_14400; fax1_ftm是由at+ftm=?命令获取的modem支持的速率,我们的modem返回是: 3,24,48,72,73,74,96,97,98,121,122,145,146, 所以该modem支持class1lib.c中结构体struct fax1_btable fax1_btable[]定义的全部速率; remote_cap.br为上PHASE A获取的remote_cap.br = V17 | V29 | V27ter=ffe 这样Local Modem与remote FAX协商的速率应该为V29_9600, 即dcs_btp= fax1_btable[3];
此时,发送的DCS Frame为: framebuf[0] = 0x03 | T30_FINAL = 0x03 | 0x10 = 0x13; framebuf[1] = fax1_dis | T30_DCS = 0x0 | 0x82 = 0x82; //fax1_dump_frame() will set last bit to 0 framebuf[2] = 0; framebuf[3] = 0x02 | dcs_btp->dcs_bits | ((fax1_res&remote_cap.vr)<<6) | 0x00 = 0x02 | 0x04 | ( (1 &1) <<6) | 00 = 0100 0010 = 0x46;
framebuf[4] = 0x00 // 00-> 215 mm width | 0x04 // B4 length | 0x00 // scan time: 00->? | 0x00; // No extend bit = 0x04;
|