1、问题综述
在一款车载记录仪中,车载仪需要将以下数据输出:a)记录仪的时钟;b)车辆的VIN号、车牌号码、车牌分类;c)车辆最近360小时内的速度数据;d)最近的10次的停车前20秒内的速度、刹车数据等。输出设备包括:1)U盘;2)打印机;3)手提设备(电脑串口)。如果采用传统的嵌入式系统,要对不同的设备分别编程、调试,然后再把它们integrate在一起,这样不但编程、调试工作量大,而且不利于软件的维护和重复使用。
使用ZRTOS的驱动器理念,只须对上述的a)-d)的功能/features进行编程,使用写/write()而无需考虑是什么设备。这样就大大地减少了编程、调试的工作量,同时也大大地有利于软件的维护和重复使用。
以下是原代码:
A)功能/Features
//get 车辆的VIN号、车牌号码、车牌分类;
void get_VIN_plate(RTOS_FD_TYPE gb_fd) //RTOS_FD_TYPE - file descriptor
{
char data[44];
U8 sum;
_mycpy((U8*)data, (U8*)&vehicle_driver.v_info,41);//复制车辆的VIN号、
//车牌号码、车牌分类;
sign_header[2]=GET_VIN_PLATE;//国标GB/T19056数据格式
sign_header[3]=0;//国标GB/T19056数据格式
sign_header[4]=41;//国标GB/T19056数据格式
write(gb_fd,sign_header,6);//输出到驱动器
sum = checksumByte((U8*)sign_header,6);//国标GB/T19056数据格式
sum += checksumByte((U8*)data,41);//check sum
data[41] = sum;//国标GB/T19056数据格式
write(gb_fd,data,42);//输出到驱动器
}
...
//other features here
...
B) USB驱动器和interface
void usb_host_init(void) //USB initialization
{
usbData.sem = rtos_semBCreate(0, SEM_EMPTY);
rtos_taskSpawn(RTOS_DEFAULT_PRIORITY-2, (RTOS_FUNCPTR) usb_host_tsk,
(long) 0 ); //spawn a task to handle USB interface
file_dev.fp = rtos_iosDrvInstall((RTOS_FUNCPTR) NULL, (RTOS_FUNCPTR)
usb_file_write);//install read() and write() into device driver,
//here, read() is NULL or unused
// write() is subroutine usb_file_write()
rtos_iosDrvAdd((RTOS_FD_TYPE) &file_dev, FILE_IO_0_DEV, file_dev.fp);//add
//the device driver into device-driver-table
//...
//other initialization here
//...
}
static RTOS_FD_TYPE usb_file_write(RTOS_FD_TYPE devs, char * buf, size_t num)
{ //write data into USB disk
int n;
FILE_DEV * dev = (FILE_DEV *) devs;
U32 sect;
for(n = 0; n < num; n++) {
dev->buffer[dev->size++] = buf[n];//move the data into a buffer
if (dev->size == _SIZE_2_WRITE) { //buffer is full, move data into USB disk's
//sector
dev->size = 0;
sect = (file_dev.fat.cluster[file_dev.fat.cluster_num]-2
*usbData.BPB_SecPerClus + file_dev.fat.sector + usbData.sectRoot;
//caculate USB disk's sector number
if (mWriteSector(sect,_NUMBER_SECTORS,dev->buffer)) //do sector write
return 0; //failed
file_dev.fat.sector += _NUMBER_SECTORS; //for new FAT in FAT32
if (file_dev.fat.sector == usbData.BPB_SecPerClus) {//for new FAT
file_dev.fat.sector = 0; //for new FAT
file_dev.fat.cluster_num++;//for new FAT
}
}
}
file_dev.fdts.size += num; //for FDT in FAT32
return num; //return with successful num bytes writing
}
void usb_host_start(void)//this function is called as a USB disk is inserted
{
CH375_POWER_ON(1); //power on
usbData.command = 0; //zero command step; the command step is used to return
//the correct process step as the USB
//interface handler (task) may have to give up the CPU, the user
//may find more info later in the "usb_host_tsk()"
usbData.fd_usb = open(USB_SER_DRV); //open device driver's file descriptor
rtos_semGive(usbData.sem); //wake up the USB interface handle task
}
static void usb_host_tsk(void) //the USB interface handle task
{
rtos_semTake(usbData.sem, WAIT_FOREVER);//may pended here
rtos_semGive(usbData.sem);//give the semaphone to itself so that the task
//will continue
usbData.command++; //incremental the command step
if(usbData.command==1) { //the command step is equal to 1
CH375_RST(0);//USB chip hardware reset
rtos_taskDelay(10);//delay 10 tick or 100ms, the task will give up the CPU
} else if(usbData.command==2) {
CH375_WR_CMD_PORT(CMD_RESET_ALL);//USB chip software reset
rtos_taskDelay(10);
} else if (usbData.command == 3) {
if (mCH375Init( )) { //initialize the USB chip
usb_out();//failed, get out
}
rtos_taskDelay(2);
} else if (usbData.command == 4) {
if (mInitDisk()) { //initialize the USB disk
usb_out();
}
rtos_taskDelay(5);
} else if (usbData.command == 5) {
displayShortMsg((char *) insert_usb); //show "please wait..." on
//LCD screen
rtos_taskDelay(250);//200);
} else if (usbData.command == 6) {
//...
//find DBR and MBR of the USB disck
//...
} else if (usbData.command == 7) {
get_VIN_plate(file_dev.fp);//get 车辆的VIN号、车牌号码、车牌分类
get_vehicle_character(file_dev.fp);//get 车辆特征
get_real_time_clock(file_dev.fp);//get 记录仪的时钟
cmd_counter = 0;//a command counter used by get_last360hour_speed() and
//get_suspect_acct_data()
//in case the task is delay() or pended
} else if (usbData.command == 8) {
usbData.command--;
get_last360hour_speed(file_dev.fp,&cmd_counter);//get 车辆最近360小时内的速度数据
//the task may give up the CPU
cmd_counter = 0;//a command counter used by get_last360hour_speed() and
//get_suspect_acct_data()
//in case the task is delay() or pended
usbData.command++;
} else if (usbData.command == 9) {
usbData.command--;
get_suspect_acct_data(file_dev.fp,&cmd_counter);// get 最近的10次的停车前
//20秒内的速度、刹车数据等 the task may give up the CPU
usbData.command++;
} else if (usbData.command == 10) {
if (!getFat32()) { //finalize the FAT32, FAT, FDT etc.
usb_return(FALSE);//failed;
} else
usb_return(TRUE);//successful
}
}
C) 串口interface
//国标GB/T 19056 interface initialization code here
GB_data.timeout = WAIT_FOREVER;//never time out or task read_GB_tsk() shall
//pended util other release the semaphone
...
//other initialization here
//
当车载仪收到国标GB/T 19056的指令时,
GB_data.command = 国标GB/T 19056的指令;
GB_data.timeout = 4;//wait for 4 tick or 40 ms
GB_data.fp = open(SCI_IO_DEV1);//open 国标GB/T 19056 or 串口 device driver's file
//descriptor
rtos_semGive(GB_data.sem); //wake up read_GB_tsk()
...
(略)
...
//
//
static void read_GB_tsk(void)//task to handle GB/T 19056 commands
{
long result = rtos_semTake(GB_data.sem, GB_data.timeout);
if (result == (long) OK) return;//it is not timeout
switch (GB_data.command) {
case GET_DRIVER_ID_LICENSE:
get_driver_id_lisence(GB_data.fp);
break;
case GET_REAL_TIME_CLOCK:
get_real_time_clock(GB_data.fp);
break;
case GET_LAST360HOUR_MILES:
get_last360hour_miles(GB_data.fp,&GB_data.cnt);
break;
case GET_VEHICLE_CHARACTER:
get_vehicle_character(GB_data.fp);
break;
case GET_LAST360HOUR_SPEED:
get_last360hour_speed(GB_data.fp,&GB_data.cnt);
break;
case GET_VIN_PLATE:
get_VIN_plate(GB_data.fp);
break;
case GET_SUSPECT_ACCNT_DATA:
get_suspect_acct_data(GB_data.fp,&GB_data.cnt);
break;
//
//(略)
//
default:
break;
}
//no problem, out here
GB_data.timeout = WAIT_FOREVER;
GB_data.cmd = GB_data.current = 0;
}
2、结论
使用驱动器理念,可以清晰地定义功能和设备以及它们之间的联系,可以大大地减少了编程、调试的工作量,比如在本例中,串口的驱动器 is well defined, thus the programmers call easily start from GB/T 19056 protocol and get those features (such as get_last360hour_speed(), etc.) done/搞定 first. The group who process USB interface shall focus on their attention to the USB hardware interface (they may also get a short cut by using other project's device driver codes). 同时使用驱动器理念也大大地有利于软件的维护和重复使用。
另外,ZRTOS中的驱动器的使用方式和效果与vxWorks基本相同。
用户461316 2008-9-7 00:54