本篇是继上篇的jni层后的app应用层。

由于app相对比较大,说起来也比较麻烦,这里就用一个串口来说明即可,实际上也就串口最具代表性,这个明白了,其他都不是问题。

串口涉及的java文件如下图红色圈所示:

具体的代码下面一一贴出来,捡重要的说明:

MainActivity.java:

package com.example.realarmapp;import realarm.can.RealarmCanActivity;
import realarm.serial.RealarmUartActivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;public class MainActivity extends Activity implements OnClickListener {private Button btnLED, btnUART, btnRS485, btnCAN;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btnLED = (Button) findViewById(R.id.btnLED);btnUART = (Button) findViewById(R.id.btnUART);btnRS485 = (Button) findViewById(R.id.btnRS485);btnCAN = (Button) findViewById(R.id.btnCAN);btnLED.setOnClickListener(this);btnUART.setOnClickListener(this);btnRS485.setOnClickListener(this);btnCAN.setOnClickListener(this);}@Overridepublic void onClick(View v) {if(v.equals(btnLED)){Intent i = new Intent(MainActivity.this, RealarmLedActivity.class);startActivity(i);}else if(v.equals(btnUART)) {Intent i = new Intent(MainActivity.this, RealarmUartActivity.class);startActivity(i);}else if(v.equals(btnRS485)) {Intent i = new Intent(MainActivity.this, RealarmUartActivity.class);startActivity(i);}else if(v.equals(btnCAN)) {Intent i = new Intent(MainActivity.this, RealarmCanActivity.class);startActivity(i);}}}

这个文件是主activity文件,没什么好说的,就是四个按钮执行不同的功能。

HardwareControl.java:

package realarm.hardware;

package realarm.hardware;import java.io.FileDescriptor;public class HardwareControl {public native int LedSetState(int ledNum,int ledState);public native static FileDescriptor OpenSerialPort(String path, int baudrate,int flags);public native static void CloseSerialPort();public native static  void InitCan(int baudrate);public native static  int OpenCan();public native static  int CanWrite(int canId,String data);public native static  CanFrame CanRead(CanFrame mcanFrame, int time);public native static   void CloseCan();static {System.loadLibrary("RealarmHardwareJni");}}

该文件是声明native接口,并加载libRealarmHardwareJNI.so库。

MyApplication.java:

package realarm.serial;import java.io.File;
import java.io.IOException;
import java.security.InvalidParameterException;import realarm.serial.utils.SerialPort;
import realarm.serial.utils.SerialPortFinder;import android.app.Application;
import android.content.SharedPreferences;
import realarm.hardware.HardwareControl;
public class MyApplication extends Application {public SerialPortFinder mSerialPortFinder = new SerialPortFinder();private SerialPort mSerialPort = null;public SerialPort getSerialPort() throws SecurityException, IOException, InvalidParameterException {if (mSerialPort == null) {/* Read serial port parameters */SharedPreferences sp = getSharedPreferences("android_serialport_api.sample_preferences", MODE_PRIVATE);String path = sp.getString("DEVICE", "/dev/ttyAMA4");int baudrate = Integer.decode(sp.getString("BAUDRATE", "115200"));/* Check parameters */if ( (path.length() == 0) || (baudrate == -1)) {throw new InvalidParameterException();}/* Open the serial port */mSerialPort = new SerialPort(new File(path), baudrate, 0);}return mSerialPort;}public SerialPort getSerialPort(String path, String baudrate, int flag) throws NumberFormatException, SecurityException, IOException{if (mSerialPort == null) {/* Open the serial port */mSerialPort = new SerialPort(new File(path), Integer.decode(baudrate), flag);}        return mSerialPort;}public void closeSerialPort() {if (mSerialPort != null) {HardwareControl.CloseSerialPort();mSerialPort = null;}}
}

该文件实现串口的创建和关闭方法。
SerialPort.java:

package realarm.serial.utils;import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;import android.util.Log;
import realarm.hardware.HardwareControl;
public class SerialPort {private static final String TAG = "SerialPort";/** Do not remove or rename the field mFd: it is used by native method* close();*/private FileDescriptor mFd;private FileInputStream mFileInputStream;private FileOutputStream mFileOutputStream;public SerialPort(File device, int baudrate, int flags)throws SecurityException, IOException {/* Check access permission */if (!device.canRead() || !device.canWrite()) {try {/* Missing read/write permission, trying to chmod the file */Process su;su = Runtime.getRuntime().exec("/system/xbin/su");String cmd = "chmod 666 " + device.getAbsolutePath() + "\n"+ "exit\n";su.getOutputStream().write(cmd.getBytes());if ((su.waitFor() != 0) || !device.canRead()|| !device.canWrite()) {throw new SecurityException();}} catch (Exception e) {e.printStackTrace();throw new SecurityException();}}mFd = HardwareControl.OpenSerialPort(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 setterspublic InputStream getInputStream() {return mFileInputStream;}public OutputStream getOutputStream() {return mFileOutputStream;}
}

该文件实现串口的打开、数据输入、数据输出的方法。

SerialPortFinder.java:

package realarm.serial.utils;import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.Iterator;
import java.util.Vector;import android.util.Log;public class SerialPortFinder {private static final String TAG = "SerialPort";private Vector<Driver> mDrivers = null;public class Driver {public Driver(String name, String root) {mDriverName = name;mDeviceRoot = root;}private String mDriverName;private String mDeviceRoot;Vector<File> mDevices = null;public Vector<File> getDevices() {if (mDevices == null) {mDevices = new Vector<File>();File dev = new File("/dev");File[] files = dev.listFiles();int i;for (i = 0; i < files.length; i++) {if (files[i].getAbsolutePath().startsWith(mDeviceRoot)) {Log.d(TAG, "Found new device: " + files[i]);mDevices.add(files[i]);}}}return mDevices;}public String getName() {return mDriverName;}}Vector<Driver> getDrivers() throws IOException {if (mDrivers == null) {mDrivers = new Vector<Driver>();LineNumberReader r = new LineNumberReader(new FileReader("/proc/tty/drivers"));String l;while ((l = r.readLine()) != null) {// Issue 3:// Since driver name may contain spaces, we do not extract// driver name with split()String drivername = l.substring(0, 0x15).trim();String[] w = l.split(" +");if ((w.length >= 5) && (w[w.length - 1].equals("serial"))) {Log.d(TAG, "Found new driver " + drivername + " on "+ w[w.length - 4]);mDrivers.add(new Driver(drivername, w[w.length - 4]));}}r.close();}return mDrivers;}public String[] getAllDevices() {Vector<String> devices = new Vector<String>();// Parse each driverIterator<Driver> itdriv;try {itdriv = getDrivers().iterator();while (itdriv.hasNext()) {Driver driver = itdriv.next();Iterator<File> itdev = driver.getDevices().iterator();while (itdev.hasNext()) {String device = itdev.next().getName();String value = String.format("%s (%s)", device,driver.getName());devices.add(value);}}} catch (IOException e) {e.printStackTrace();}return devices.toArray(new String[devices.size()]);}public String[] getAllDevicesPath() {Vector<String> devices = new Vector<String>();// Parse each driverIterator<Driver> itdriv;try {itdriv = getDrivers().iterator();while (itdriv.hasNext()) {Driver driver = itdriv.next();Iterator<File> itdev = driver.getDevices().iterator();while (itdev.hasNext()) {String device = itdev.next().getAbsolutePath();devices.add(device);}}} catch (IOException e) {e.printStackTrace();}return devices.toArray(new String[devices.size()]);}
}

该文件实现应用程序在/dev目录下检索tty*节点的方法。

RealarmUartActivity.java:

package realarm.serial;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;import com.example.realarmapp.R;import realarm.serial.utils.SerialPort;
import realarm.serial.utils.SerialPortFinder;import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.ToggleButton;public class RealarmUartActivity extends Activity {protected MyApplication mApplication;protected SerialPort mSerialPort;protected OutputStream mOutputStream;private InputStream mInputStream;private ReadThread mReadThread;EditText EditTextEmission, EditTextReception;SerialPortFinder mSerialPortFinder;// 串口设备搜索Spinner spinnerCOM;Spinner spinnerBaudRateCOM;CheckBox checkBoxAutoCOM;ToggleButton toggleButtonCOM;Button buttonSendCOM, buttonClean;private class ReadThread extends Thread {@Overridepublic void run() {super.run();while (!isInterrupted()) {int size;try {byte[] buffer = new byte[64];if (mInputStream == null)return;/*** 这里的read要尤其注意,它会一直等待数据,等到天荒地老,海枯石烂。如果要判断是否接受完成,只有设置结束标识,* 或作其他特殊的处理。*/size = mInputStream.read(buffer);if (size > 0) {onDataReceived(buffer, size);}} catch (IOException e) {e.printStackTrace();return;}}}}protected void onDataReceived(final byte[] buffer, final int size) {runOnUiThread(new Runnable() {public void run() {if (EditTextReception != null) {EditTextReception.append(new String(buffer, 0, size));}}});}private void DisplayError(int resourceId) {AlertDialog.Builder b = new AlertDialog.Builder(this);b.setTitle("Error");b.setMessage(resourceId);b.setPositiveButton("OK", new OnClickListener() {public void onClick(DialogInterface dialog, int which) {RealarmUartActivity.this.finish();}});b.show();}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.uart);<span style="color:#ff0000;">mApplication = (MyApplication) getApplication();</span>mSerialPortFinder = new SerialPortFinder();EditTextReception = (EditText) findViewById(R.id.EditTextReception);EditTextEmission = (EditText) findViewById(R.id.EditTextEmission);buttonClean = (Button) findViewById(R.id.buttonClean);buttonSendCOM = (Button) findViewById(R.id.buttonSendCOM);spinnerCOM = (Spinner) findViewById(R.id.spinnerCOM);spinnerBaudRateCOM = (Spinner) findViewById(R.id.spinnerBaudRateCOM);checkBoxAutoCOM = (CheckBox) findViewById(R.id.checkBoxAutoCOM);toggleButtonCOM = (ToggleButton) findViewById(R.id.toggleButtonCOM);ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.baudrates_value,android.R.layout.simple_spinner_item);adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);spinnerBaudRateCOM.setAdapter(adapter);spinnerBaudRateCOM.setSelection(16);String[] entryValues = mSerialPortFinder.getAllDevicesPath();List<String> allDevices = new ArrayList<String>();for (int i = 0; i < entryValues.length; i++) {allDevices.add(entryValues[i]);}ArrayAdapter<String> aspnDevices = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item, allDevices);aspnDevices.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);spinnerCOM.setAdapter(aspnDevices);if (allDevices.size() > 0) {spinnerCOM.setSelection(4);}buttonClean.setOnClickListener(new ButtonClickEvent());buttonSendCOM.setOnClickListener(new ButtonClickEvent());toggleButtonCOM.setOnCheckedChangeListener(new ToggleButtonCheckedChangeEvent()); spinnerCOM.setOnItemSelectedListener(new ItemSelectedEvent());spinnerBaudRateCOM.setOnItemSelectedListener(new ItemSelectedEvent());if (!toggleButtonCOM.isChecked()) {/*如果没有打开串口,那么发送按钮灰色不允许操作*/buttonSendCOM.setEnabled(false);}
//      try {
//          mSerialPort = mApplication.getSerialPort();
//          mOutputStream = mSerialPort.getOutputStream();
//          mInputStream = mSerialPort.getInputStream();
//
//          /* Create a receiving thread */
//          mReadThread = new ReadThread();
//          mReadThread.start();
//      } catch (SecurityException e) {
//          DisplayError(R.string.error_security);
//      } catch (IOException e) {
//          DisplayError(R.string.error_unknown);
//      } catch (InvalidParameterException e) {
//          DisplayError(R.string.error_configuration);
//      }}//    protected abstract void onDataReceived(final byte[] buffer, final int size);@Overrideprotected void onDestroy() {if (mReadThread != null)mReadThread.interrupt();mApplication.closeSerialPort();mSerialPort = null;super.onDestroy();}// ----------------------------------------------------串口号或波特率变化时,关闭打开的串口class ItemSelectedEvent implements Spinner.OnItemSelectedListener {public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,long arg3) {if ((arg0 == spinnerCOM) || (arg0 == spinnerBaudRateCOM)) {mApplication.closeSerialPort();checkBoxAutoCOM.setChecked(false);toggleButtonCOM.setChecked(false);}}public void onNothingSelected(AdapterView<?> arg0) {}}// ----------------------------------------------------清除按钮、发送按钮class ButtonClickEvent implements View.OnClickListener {public void onClick(View v) {if (v == buttonClean) {EditTextReception.setText("");}else if (v == buttonSendCOM) {if (toggleButtonCOM.isChecked()) {try {mOutputStream.write(EditTextEmission.getText().toString().getBytes());mOutputStream.write('\n');System.out.println("串口数据发送成功");} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}else{System.out.println("串口未打开");}}}}//----------------------------------------------------打开关闭串口class ToggleButtonCheckedChangeEvent implements ToggleButton.OnCheckedChangeListener{public void onCheckedChanged(CompoundButton buttonView, boolean isChecked){if (buttonView == toggleButtonCOM){if (isChecked){try {
//                      mSerialPort = new SerialPort(new File(spinnerCOM.getSelectedItem().toString()),
//                                                  Integer.decode(spinnerBaudRateCOM.getSelectedItem().toString()), 0);mSerialPort = mApplication.getSerialPort(spinnerCOM.getSelectedItem().toString(), spinnerBaudRateCOM.getSelectedItem().toString(), 0);mOutputStream = mSerialPort.getOutputStream();mInputStream = mSerialPort.getInputStream();/* Create a receiving thread */mReadThread = new ReadThread();mReadThread.start();buttonSendCOM.setEnabled(true);/*使能发送按钮,这时可以发送数据了*/System.out.println("打开串口"+spinnerCOM.getSelectedItem().toString()+"成功!");} catch (NumberFormatException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SecurityException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}else {mApplication.closeSerialPort();checkBoxAutoCOM.setChecked(false);buttonSendCOM.setEnabled(false);/*关闭发送按钮使能*/System.out.println("关闭串口"+spinnerCOM.getSelectedItem().toString()+"成功!");}}}}
}

该文件就是串口操作的主activity了,加载布局文件等。在该文件中,这里重要说明MyApplication这个类的调用。就是上面的红色代码。

也许有朋友在http://blog.csdn.net/tangcheng_ok/article/details/7021470这篇文章时,就遇到了这个问题,虽然编译通过,可是运行就会蹦掉。当然了,我也看了,而且遇到了。

那么这是怎么回事呢,通过报错提示“找不到资源”,可以知道当执行到红色部分时,应用程序无法找到资源。可是我们明明定义了MyApplication这个类,且继承与Application,为什么会找不到呢。代码定义当然没问题,实际上问题出在没有告诉app我定义了这个MyApplication。只需要在AndroidManifest.xml文件中添加下面红色的代码即可解决问题:

这句代码就是告诉app要使用MyApplication这个继承与Application的类。

下面贴出运行的界面,O(∩_∩)O。

主界面:

led操作界面:

串口操作界面:

485与串口区别就是打开的串口号不同:

can操作界面:

再来个竖屏的,在布局时考虑到了适应问题,所以没有采用绝对布局,可以适应各分辨率大小的屏幕,只要分辨率不要太小,完全显示都是没问题的。

源码下载地址:http://download.csdn.net/detail/u010406724/8539209

转载请注明出处:http://blog.csdn.net/wang_shuai_ww/article/details/44676937

s5p4418 android 驱动 hal 应用之led 串口 rs485 can总线应用(app 有源码)相关推荐

  1. Android 驱动CH340实现和单片机串口通信

    前言 最近项目中需要加一个体温检测的模块 需要用到android的串口通信知识点 遇到的问题 之前没有深入了解过 串口通信 在查询知识点的时候 查到了google的demo Google公司在2011 ...

  2. android调频收音机代码,android 收音机 FM 驱动 hal层 框架层以及应用层代码

    [实例简介] android 收音机 FM 驱动 hal层 框架层以及应用层代码 方法一 不需要framework部分 1.fm放到 \hardware\rk2x 2.FmRadio 放到 packa ...

  3. Android之 震动(Vibrator)如何贯通Android系统 (从硬件设计 -- 驱动 -- HAL -- JNI -- Framework -- Application)

        在Android 2.3(Gingerbread) 系统的时候,我写过一篇关于"Android 震动马达系统"的文章,当时的Linux内核还是2.6版本的.写那篇文章的目的 ...

  4. android驱动开发 老罗,在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序(老罗学习笔记3)...

    在Android硬件抽象层(HAL)概要介绍和学习计划一文中,我们简要介绍了在Android系统为为硬件编写驱动程序的方法.简单来说,硬件驱动程序一方面分布在Linux内核中,另一方面分布在用户空间的 ...

  5. 在Android开发板跑一个LED驱动的历程(个人笔记)

    [版权申明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) 在Android开发板跑一个LED驱动的历程(个人笔记) 1. 板子端, 放置驱动程序 1.1 编写一个驱动程序 驱动程序的编写上, ...

  6. 关于Android的HAL的一些理解

    之前一直在学习基于Linux内核的一些字符型驱动的编程,对Linux内核驱动也算有了一些基本的了解吧,后来也做过一些基于Linux内核的驱动开发,像基于Android的CC1101高频模块的驱动开发, ...

  7. 【Android】HAL层浅析

    一.HAL层的前世今生 二.HAL层的通用结构剖析 三.一个例子 四.击破Audio HAL Module 五.小的总结 一.HAL层的前世今生 HAL(Hardware Abstraction La ...

  8. [Android]Android 下实现点亮 Led

    Android 下的实现点亮 led 1 准备驱动 1.1 修改设备树 在设备树中添加节点,在 / 节点下添加 led_test 节点,在 &iomuxc 节点下添加 led_test 的 p ...

  9. 视频教程-Android驱动深度开发视频教程-驱动/内核开发

    Android驱动深度开发视频教程 2003 年毕业于中国科学技术大学,电子专业.软件专业双学位.近10年嵌入式开发经验,曾ZTE公司负责Linux底层系统开发. 近5年作为特聘讲师在若干个有名的培训 ...

最新文章

  1. 带有.rdlc报表的项目发布需要注意的问题
  2. 如何用python画数据图-用Python如何画出数据可视化图呢?本文详解
  3. SpringBoot: SpringBoot里面创建导出Excel的接口(亲测)
  4. java 图片请求_java请求C++客户端上传图片
  5. linux iptables 编译,Linux下编译安装iptables
  6. mysql数据变化通通知机制_深入理解Notification机制
  7. struts2 - ation 访问 Servlet api
  8. SpringBoot重复配置数据库导致Access denied for user ‘root‘@‘localhost‘ (using password: YES)
  9. thrift的lua实现
  10. Yii2.0修改默认控制器
  11. dedecms调用日期格式化形式大全
  12. freopen()函数
  13. ext3日志模式---文件系统
  14. 技术文化和惨淡命运 —— 怀念中国雅虎----转载
  15. 几款pdf转换成word转换器免费版软件
  16. 两只小企鹅(Python实现)
  17. 用vc++穷举windows应用程序密码(上)
  18. 李沐【实用机器学习】1.3网页数据抓取
  19. HyperMesh网格划分简要流程小试
  20. Python中的getattr()和__getattr__方法

热门文章

  1. 能表示分数的计算机,分数计算器的实现
  2. python qcut_Python之Pandas库学习(三):数据处理
  3. service能去调另外一个service吗_kubernetes的service和pod是如何关联的?
  4. play版 高德地图google_iOS 12 发布,苹果 CarPlay 终于开始支持谷歌、高德导航
  5. matlab全域基函数,多项式函数插值:全域多项式插值(一)单项式基插值、拉格朗日插值、牛顿插值 [MATLAB]...
  6. java system_java System类
  7. 华为看片牛?真香!那就送你一台试试,可折现!
  8. java bean工厂_java-将Service用作“工厂”以返回不同的Bean...
  9. 更新日志_Roam 更新日志:0.7.3 啦
  10. html中的特性是什么,数据库的四大特性是什么