解决了gps的问题: 基本学会了init.rc中添加service 的用法! 以service启动的任何程序都被搞成daemon进程,所以不要在service中启动原本已经就是daemon的程序,在serive中启动的进程既然被daemon化了(你可以看到由service启动的程序他们的父进程都是init进程),那么该进程的log就出不来了,因为daemon进程一般会把stdin,stdout,stderr关掉,这时候可以像下边的例子一样,加一个/system/bin /logwrapper,logwrapper会将程序的输出重新定向到android的系统日志中,这样就可以通过logcat查看了。 service gps2 /system/bin/logwrapper /system/gps/OrionTest_daed_loop.elf -lport /dev/ttymxc2 -u0 /dev/ptyu0 -esp 0 -limage system/gps/OrionAuto.img -fsh system/gps/Orion.fsh -lupspd 921600 -mode GSM26 -d1 system/gps/UBPLog.ubp user root #change user when start this service group system #change group when start this service oneshot #this service will start only one time athores 截至目前一共提供了三个版本的OrionTest程序(V1:执行后开始向端口写入nmea数据,用户终端回车后该程序退出;V2:标准的daemon程序;V3:非daemon的一个dead loop,执行后只能kill掉。如上所述,最终采用的是V3,并通过service方式将其转化为daemon),该程序的功能是向gps芯片下载固件,以及启动gps并通过物理端口读取gps的输出,然后通过伪终端方式向外界应用提供操纵通路并向外界输出NMEA,该程序会向伪终端主口(pty**)写入NMEA,然后应用程序可以打开对应的伪终端从口(tty**)即可读到NMEA,应用程序也可以向从口写入控制命令,而该程序可以从主口读到用户写入的控制命令,这样的命令也是mnea格式的数据,常用的命令如下参见如下代码,这是向伪终端从口写入数据的函数 int write_cmd_to_port(int fd_port)//打开的伪终端从设备句柄 { char status_string[32]; int length_string; int ret =-1; int status; while(1) { printf("please input your choice: "); scanf("%d", &status); if (status == 1) { strcpy(status_string, "$PUNV,SLEEP*7E"); } else if (status == 2) { strcpy(status_string, "$PUNV,WAKEUP*2C"); } else if (status == 3) { strcpy(status_string, "$PUNV,START,COLD*59"); } else if (status == 4) { strcpy(status_string, "$PUNV,START,WARM*54"); } else if (status == 5) { strcpy(status_string, "$PUNV,STOP*29"); } length_string = strlen(status_string); status_string[length_string] = 0x0D; status_string[length_string + 1] = 0x0A; ret = write(fd_port, status_string, length_string+2); if(ret < 1){ printf("/nERROR: write charactor to <%d> error ret = %d/n", fd_port, ret); } } return 0; } 既然提到伪终端了,顺便总结下伪终端的使用,确切的说,伪终端真的是我的一场噩梦。。。还好这个噩梦让我学到的更多的东西,比如对进程fork操作的更深入的理解和熟练运用!创建daemon进程。。。 首先,伪终端是sun的那个叫做s什么的系统的一个产物,现在已经基本很少使用了,sun的创建伪终端的源代码中已经明确声明伪终端马上就要被废了!因为进程间的通讯现在有更多的方法。在网上搜的关于伪终端东西都TMD是同一份,真悲哀!同事建议搜英文的资料,可怜我英文太菜,这是我的悲哀! 伪终端的使用有两种,一种是动态的,一种是静态的,目前只有在嵌入式linux环境下还能看到静态方式的身影,在X86上我只看到了动态方式的。 先说说动态的:最简单的方式就是调用一个库函数: int main(int argc, char *argv[]) { int rtnVal=0; int mpty, spty, c=0, dev=0; char *pName=NULL; char ptyBuff[100] = {'/0'}; char sptyname[20] = {'/0'}; rtnVal = openpty(&mpty, &spty, sptyname, NULL, NULL);//就是这个函数!得到一组伪终端匹配对儿的fd ! // Check if Pseudo-Term pair was created if(rtnVal != -1) { pName = ptsname(mpty);//get slave device name, the arg is the master device fd printf("Name of slave side is <%s> fd = %d/n", pName, spty); strcpy(sptyname, pName); printf("my sptyname is %s/n",sptyname); 一般你会在一个程序中通过上述方法去创建一个匹配对并对外界公布你已经搞到的那个从设备的设备路径(由ptsname函数得到),以便和外部的应用程序去沟通,但是你不要试图得到主设备的路径,你只能在本程序中使用由mpty得到的那个fd !!!!!由此显而易见,由谁去调用openpty就很有讲究了。。。。。 如果你的嵌入式系统不支持openpty函数,这很正常,也很好解决,看下openpty的实现就好了,自己去搞下,其实很简单,我把代码列出来参考下: 以下是源码,来自/fsl_myandroid_r6/external/qemu/vl.c line 2545 r7里面都已经没有了!真快呀!哈哈 /* Once Solaris has openpty(), this is going to be removed. */ int openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize *winp) { const char *slave; int mfd = -1, sfd = -1; *amaster = *aslave = -1; mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY); if (mfd < 0) goto err; if (grantpt(mfd) == -1 || unlockpt(mfd) == -1) goto err; if ((slave = ptsname(mfd)) == NULL) goto err; if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1) goto err; if (ioctl(sfd, I_PUSH, "ptem") == -1 || (termp != NULL && tcgetattr(sfd, termp) < 0)) goto err; if (amaster) *amaster = mfd; if (aslave) *aslave = sfd; if (winp) ioctl(sfd, TIOCSWINSZ, winp); return 0; err: if (sfd != -1) close(sfd); close(mfd); return -1; } 你可以看到,每次打开"/dev/ptmx",你就有机会搞一个和他匹配的从设备! 静态伪终端: 有这个的话,用起来就很简单了。但是为了能用这个东西,我走了好多弯路。。。。。 ls /dev 你会看到一堆的,pty** 和tty** 这就是一组一组的伪终端匹配对儿,他们的数量可以在make config中设置,如果支持静态伪终端的话。 记住,先打开pty** , 再打开tty** 就可以使用了,知道发现这个特性让我费了多大神么,,,往事不堪回首。。。。 还有一条:tty**同一时间只能被打开一次!换句话说它的访问是独占的!这也是实验得出的结论!