android4.0下serial port给应用操作完成特殊定制

简介: android4.0下serial port给应用操作完成特殊定制        我们在开发中,串口也就是serialport或者叫uart用的是相当频繁的,很普通的接口了,今天为什么在这提出来呢?笔者前年完成了一款android4.0平台的车载平板产品,客户外接了一个DTV,我们在android这边通过GPIO模拟IR来控制DTV盒子的。

android4.0下serial port给应用操作完成特殊定制

        我们在开发中,串口也就是serialport或者叫uart用的是相当频繁的,很普通的接口了,今天为什么在这提出来呢?笔者前年完成了一款android4.0平台的车载平板产品,客户外接了一个DTV,我们在android这边通过GPIO模拟IR来控制DTV盒子的。客户前面也做了特殊的一些应用,可以通过wifi跟服务器连。服务器通过wifi网络发送控制命令给车载平板机器,但是客户反馈在wifi 在heavy WiFi trafic / interferences时,丢包率很高,达到50%以上,造成很多控制命令丢失。

/*****************************************************************************************************/
声明:本博内容均由http://blog.csdn.net/edsam49原创,转载请注明出处,谢谢!
/*****************************************************************************************************/

        其实通过网络传输,在网络堵塞的时候,丢包率高这是很正常的问题,怎么不能通过控制好发送命令再确认ack,如果约定时间内没收到就继续重发呢?不知道老外怎么想的。由于给他做的控制DTV的GPIO模拟IR接口很好用,很稳定,因此客户想通过串口去控制DTV,同时有些控制信息就走DVB网络,应该没那么堵塞,再通过DTV盒子通过串口回传给android车载平台机器,这样也确实是可行。由于目前产品早已经成形,客户也不想把通过串口的数据让我们来解析,所以我们就只要提供一条操作串口的库给上层就可以了,这样相对对我们来说也简单了,只要打通串口,上层能收发串口数据就可以了。

        从android4.1起,android系统提供了操作串口的service,但是笔者以前是基于android4.0的,怎么办呢?参考android4.1以后的系统操作控制方式,主要思路还是提供一个操作串口的文件句柄给应用上层使用。但是笔者觉得不大好的,android提供的serial service没有提供关闭串口的接口,这样如果频繁关闭打开的话会存在很多句柄没关闭的情况。当然,如果只在service里面打开的话也没问题,如果在上层打开的话可能就会存在问题。下面笔者就带你一起游历这个过程吧!

       第一步,肯定是要搞定驱动。串口驱动目前来说,每个平台基本都是做好了,直接做好配置打开就可以了,笔者使用的全志平台,配置如下:

;----------------------------------------------------------------------------------
;uart configuration
;uart_type ---  2 (2 wire), 4 (4 wire), 8 (8 wire, full function)
;----------------------------------------------------------------------------------
[uart_para0]
uart_used                = 1
uart_port                = 0
uart_type                = 2
uart_tx                  =port:PB22<2><1><default><default>
uart_rx                  =port:PB23<2><1><default><default>

     第二步,确认串口设备文件的权限,需要有system的权限,所以笔者把它配置成666了。笔者使用的是打印串口做的测试,因此是ttyS0设备文件。

 

     第三步,写一个JNI文件,提供一个库给应用调用了,因为我们不可能给他做一个系统service来使用了,以最小的代价来搞定,这样的话使用NDK也好,可以直接用一个apk就可以完成了。在这个JNI文件里,笔者提供了两个接口,一个open,一个close,刚好形成最小闭环循环。代码也不难,涉及一点JNI基本知识,如下:

extern "C" JNIEXPORT jobject JNICALL Java_com_jeavox_ttys_utils_SerialPort_open
  (JNIEnv *env, jobject thiz, jstring path, jint baudrate, jint flags)
{
        int fd;
        speed_t speed;
        jobject mFileDescriptor;

        /* Check arguments */
        {
                speed = getBaudrate(baudrate);
                if (speed == -1) {
                        /* TODO: throw an exception */
                        LOGE("Invalid baudrate");
                        return NULL;
                }
        }

        /* Opening device */
        {
                jboolean iscopy;
                const char *path_utf = env->GetStringUTFChars(path, NULL);
                LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
                fd = open(path_utf, O_RDWR | flags);
                env->ReleaseStringUTFChars(path, path_utf);
                if (fd == -1)
                {
                        /* Throw an exception */
                        LOGE("Cannot open port");
                        /* TODO: throw an exception */
                        return NULL;
                }
        }

        /* Configure device */
        {
                struct termios cfg;
                LOGD("Configuring serial port");
                if (tcgetattr(fd, &cfg))
                {
                        LOGE("tcgetattr() failed");
                        close(fd);
                        /* TODO: throw an exception */
                        return NULL;
                }

                cfmakeraw(&cfg);
                cfsetispeed(&cfg, speed);
                cfsetospeed(&cfg, speed);

                if (tcsetattr(fd, TCSANOW, &cfg))
                {
                        LOGE("tcsetattr() failed");
                        close(fd);
                        /* TODO: throw an exception */
                        return NULL;
                }
        }

        /* Create a corresponding file descriptor */
        {
                jclass cFileDescriptor = env->FindClass("java/io/FileDescriptor");
                jmethodID iFileDescriptor = env->GetMethodID( cFileDescriptor, "<init>", "()V");
                jfieldID descriptorID = env->GetFieldID( cFileDescriptor, "descriptor", "I");
                mFileDescriptor = env->NewObject( cFileDescriptor, iFileDescriptor);
                env->SetIntField( mFileDescriptor, descriptorID, (jint)fd);
        }

        return mFileDescriptor;
}
extern "C" JNIEXPORT void JNICALL Java_com_jeavox_ttys_utils_SerialPort_close
  (JNIEnv *env, jobject thiz)
{
        jclass SerialPortClass = env->GetObjectClass(thiz);
        jclass FileDescriptorClass = env->FindClass("java/io/FileDescriptor");

        jfieldID mFdID = env->GetFieldID( SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
        jfieldID descriptorID = env->GetFieldID( FileDescriptorClass, "descriptor", "I");

        jobject mFd = env->GetObjectField( thiz, mFdID);
        jint descriptor = env->GetIntField( mFd, descriptorID);

        close(descriptor);
}

     第四步,到应用层去接应JNI库,这里很重要的是使用了FileInputStream跟FileOutputStream。在FileOutputStream使用上有一点要注意,就是目前FileOutputStream提供的三个read接口都是阻塞的,会一直在那等数据,但是另外还提供了一个available接口,这个接口是用来提示有多少数据现在可以读取,这样我们去读的时候,就有目的性了,挺好的。

	private FileDescriptor mFd;
	private FileInputStream mFileInputStream;
	private FileOutputStream mFileOutputStream;

	public SerialPort(File device, int baudrate, int flags) throws SecurityException, IOException {
		mFd = open(device.getAbsolutePath(), baudrate, flags);
		if (mFd == null) {
			Log.e(TAG, "native open returns null");
			throw new IOException();
		}
		
		mFileInputStream = new FileInputStream(mFd);
		mFileOutputStream = new FileOutputStream(mFd);
	}

	// Getters and setters
	public InputStream getInputStream() {
		return mFileInputStream;
	}
    也是在一个thread里面去读数据的,

	private class ReadThread extends Thread {

		@Override
		public void run() {
			super.run();
			while (!isInterrupted()) {
				int size;
				try {
					byte[] buffer = new byte[64];
					if (mInputStream == null)
						return;
					if(mInputStream.available() > 0 ){
				    	size = mInputStream.read(buffer);
				    } else{
				    	continue;
				    }
					if (size > 0) {
						onDataReceived(buffer, size);
					}
				} catch (IOException e) {
					e.printStackTrace();
					return;
				}
			}
		}
	}

     第五步,当然是起应用去call相应接口了。

        mSerialPort = new SerialPort(new File("/dev/ttyS0"), 115200, 0);
             这边调用,也就是设置好设备文件已经波特率,其他flag先不传了。其他应用代码未贴,基本的界面都不难搞的。

     第六步,就看看应用的效果吧!我从串口输入了一些字符,在应用上读出来显示出来。

 

      整个过程还是不算难搞的,整个过程参考了网上一些大侠的代码,参考了android4.4的代码实现,同时得到了做应用的同事协助完成整个调试。在此看透这个问题,android4.1以后的serialservice只不过是把它写成一个系统service的形式供应用使用。总之,算交差了,通道建好了,客户自己爱怎么折腾就怎么折腾吧!

 

目录
相关文章
|
11月前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
1087 4
|
6月前
|
存储 Android开发
如何查看Flutter应用在Android设备上已被撤销的权限?
如何查看Flutter应用在Android设备上已被撤销的权限?
288 64
|
8月前
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
555 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
8月前
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
242 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
11月前
|
算法 Java 数据库
Android 应用的主线程在什么情况下会被阻塞?
【10月更文挑战第20天】为了避免主线程阻塞,我们需要合理地设计和优化应用的代码。将耗时操作移到后台线程执行,使用异步任务、线程池等技术来提高应用的并发处理能力。同时,要注意避免出现死循环、不合理的锁使用等问题。通过这些措施,可以确保主线程能够高效地运行,提供流畅的用户体验。
515 58
|
10月前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
277 14
|
10月前
|
Java Linux 数据库
探索安卓开发:打造你的第一款应用
在数字时代的浪潮中,每个人都有机会成为创意的实现者。本文将带你走进安卓开发的奇妙世界,通过浅显易懂的语言和实际代码示例,引导你从零开始构建自己的第一款安卓应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇门,让你的创意和技术一起飞扬。
197 13
|
10月前
|
搜索推荐 前端开发 测试技术
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。
|
11月前
|
JSON Java Android开发
探索安卓开发之旅:打造你的第一个天气应用
【10月更文挑战第30天】在这个数字时代,掌握移动应用开发技能无疑是进入IT行业的敲门砖。本文将引导你开启安卓开发的奇妙之旅,通过构建一个简易的天气应用来实践你的编程技能。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你宝贵的学习资源。我们将一步步地深入到安卓开发的世界中,从搭建开发环境到实现核心功能,每个环节都充满了发现和创造的乐趣。让我们开始吧,一起在代码的海洋中航行!
|
11月前
|
搜索推荐 开发工具 Android开发
打造个性化Android应用:从设计到实现的旅程
【10月更文挑战第26天】在这个数字时代,拥有一个能够脱颖而出的移动应用是成功的关键。本文将引导您了解如何从概念化阶段出发,通过设计、开发直至发布,一步步构建一个既美观又实用的Android应用。我们将探讨用户体验(UX)设计的重要性,介绍Android开发的核心组件,并通过实际案例展示如何克服开发中的挑战。无论您是初学者还是有经验的开发者,这篇文章都将为您提供宝贵的见解和实用的技巧,帮助您在竞争激烈的应用市场中脱颖而出。

热门文章

最新文章