/* by kh0723 */
#include "common.h"
#include "ymodem.h"
#include "string.h"
#include <stdio.h>
#include "vxWorks.h"
#include "crc.h"
/* 初始化输入输出接口 */
FUNCPTR ymodem_putc_fun = NULL;
FUNCPTR ymodem_getc_fun = NULL;
void ymodem_io_init(FUNCPTR putc, FUNCPTR getc)
{
ymodem_putc_fun = putc;
ymodem_getc_fun = getc;
}
/* 输出字符 */
int ymodem_debug = 0;
void ymodem_putc(char c)
{
if(ymodem_putc_fun)
ymodem_putc_fun(c);
else
printf("\r\n Need: ymodem_io_init()");
if((ymodem_debug & 0x1) == 0x1)
printf("t: %02x ", c);
}
/* 输入字符 */
char ymodem_getc()
{
char c = 0xff;
if(ymodem_getc_fun)
c = ymodem_getc_fun();
else
printf("\r\n Need: ymodem_io_init()");
if((ymodem_debug & 0x2) == 0x2)
printf("\r\nr: %02x \r\n", c);
return c;
}
/* 延时 */
void ymodem_delay(int ticks)
{
taskDelay(ticks);
}
/* 报文填充 */
int ymodem_pkt_fill(int pkt_mode, int pkt_id, char* a_data_ptr, int a_data_len, YMODEM_PKT* pkt)
{
int pkt_data_len = PKT_MODE_2_DATA_LEN(pkt_mode);
if((pkt_id < 0) || (NULL == a_data_ptr) || (a_data_len <= 0) || (NULL == pkt))
return -1;
//头: 发送模式、报文id、报文id补码
pkt->mode = pkt_mode;
if(EOT != pkt_mode)
{
pkt->id = pkt_id;
pkt->id2 = ~pkt_id;
//数据
memset(pkt->data_buf, 0, sizeof(pkt->data_buf));
memcpy(pkt->data_buf, a_data_ptr, a_data_len);
pkt->data_len = pkt_data_len;
//crc
pkt->crc16 = (int)cyg_crc16((unsigned char*)(pkt->data_buf), pkt->data_len);
}
return 0;
}
/* 报文发送 */
void ymodem_pkt_tx(YMODEM_PKT pkt)
{
int i;
ymodem_putc(pkt.mode);
//非eot
if(EOT != pkt.mode)
{
//printf("\r\n pkt_mode %d, pkt_id %d, pkt_data_len %d, pkt.crc16 %x\r\n", pkt.mode, pkt.id, pkt.data_len, pkt.crc16);
ymodem_putc(pkt.id);
ymodem_putc(pkt.id2);
for(i = 0; i < pkt.data_len; i++)
{
ymodem_putc(pkt.data_buf[i]);
}
ymodem_putc(pkt.crc16 >> 8);
ymodem_putc(pkt.crc16 & 0xFF);
}
//发送等待
ymodem_delay(1);
}
/* 报文回应确认: 返回是否ok */
int ymodem_pkt_ack(YMODEM_PKT pkt)
{
int pkt_first = 0;
int pkt_end = 0;
char pkt_ack, ack_crc16;
//判断pkt标记
if((0 == pkt.id) && (0 != pkt.data_buf[0]))
pkt_first = 1;
else if(EOT == pkt.mode)
pkt_end = 1;
//接收等待, 对端处理能力有限
if(pkt_first)
ymodem_delay(20);
else
ymodem_delay(1);
//接收
pkt_ack = ymodem_getc();
if(ACK != pkt_ack)
return 0;
//开始和结束会返回crc
if(pkt_first || pkt_end)
{
ack_crc16 = ymodem_getc();
}
return 1;
}
/* 报文传输 */
int ymodem_pkt_transfer(int pkt_mode, int pkt_id, char* a_data_ptr, int a_data_len)
{
YMODEM_PKT pkt;
int i;
if((pkt_id < 0) || (NULL == a_data_ptr) || (a_data_len <= 0))
return -1;
//填充
if(0 != ymodem_pkt_fill(pkt_mode, pkt_id, a_data_ptr, a_data_len, &pkt))
return -2;
//传输
for(i = 0; i <= PKT_TRY_TIMES; i++)
{
//发送
ymodem_pkt_tx(pkt);
//应答确认
if(ymodem_pkt_ack(pkt))
break;
}
//传输失败
if(i > PKT_TRY_TIMES)
return -3;
//重传次数
return i;
}
/* 数据分片报文传输 */
int ymodem_pkts_transfer(int pkt_mode, int pkt_id_base, char* data_ptr, int data_len)
{
int rc, data_offset, remain_len;
int pkt_data_len;
int pkt_id;
char* a_data_ptr;
int a_data_len;
if((pkt_id_base < 0) || (NULL == data_ptr) || (data_len <= 0))
return -1;
pkt_id = pkt_id_base;
pkt_data_len = PKT_MODE_2_DATA_LEN(pkt_mode);
for(data_offset = 0; data_offset < data_len; )
{
remain_len = data_len - data_offset;
#if 0
//如果1k模式不够1k,更改报文数据长度为128
if((STX == pkt_mode) && (remain_len < PKT_DATA_1K))
{
pkt_data_len = PKT_DATA_128;
}
printf("\r\n pkt_id %d, pkt_data_len %d, data_offset %d\r\n", pkt_id, pkt_data_len, data_offset);
#endif
//传输一个
a_data_ptr = data_ptr + data_offset;
a_data_len = (remain_len > pkt_data_len) ? pkt_data_len : remain_len;
rc = ymodem_pkt_transfer(pkt_mode, pkt_id, a_data_ptr, a_data_len);
if(rc < 0)
return rc;
//下一个报文
pkt_id++;
data_offset += pkt_data_len;
}
return 0;
}
/*
传输文件
注意: 控制报文和信息报文采用soh(128字节), 数据报文采用stx(1k字节)
*/
int ymodem_file_transfer(char* file_name, char* file_ptr, int file_len)
{
char data_buf[PKT_DATA_128];
int rc;
if((sizeof(data_buf) <= strlen(file_name)) || (NULL == file_ptr) || (file_len <= 0))
return -1;
//传输文件名和长度
memset(data_buf, 0, sizeof(data_buf));
sprintf(data_buf, "%s %d", file_name, file_len);
data_buf[strlen(file_name)] = 0;
rc = ymodem_pkt_transfer(SOH, 0, data_buf, sizeof(data_buf));
if(rc < 0)
return rc;
//传输文件内容
rc = ymodem_pkts_transfer(STX, 1, file_ptr, file_len);
if(rc < 0)
return rc;
//传输结束
memset(data_buf, 0, sizeof(data_buf));
rc = ymodem_pkt_transfer(EOT, 0, data_buf, sizeof(data_buf));
if(rc < 0)
return rc;
//传输结束确认
memset(data_buf, 0, sizeof(data_buf));
rc = ymodem_pkt_transfer(SOH, 0, data_buf, sizeof(data_buf));
if(rc < 0)
return rc;
return 0;
}