您的位置:首页 > 移动开发 > Android开发

ARM Tiny210v2开发板Android系统读写串口设备

2013-10-03 10:11 537 查看
之前买了块Tiny210v2开发板,需要在Android系统下读写串口,于是自己在JNI层封装了下串口读写,PS:友善官方也提供了底层硬件的读写库,这个纯粹是自己写了玩的。

代码主要分为5个部分,ReadWriteSerialPortLib.c+stty.h+Android.mk+accessarmborddevlib.java+MainActivity.java

stty.h主要是对于串口设备/dev/s3c2410_serial3的读写,参考常见的linux系统串口读写代码编写

ReadWriteSerialPortLib.c是JNI的C语言层封装代码

Android.mk是Android NDK编译脚本

accessarmborddevlib.java是JNI的Java语言层封装代码

MainActivity.java是Android最上层的调用代码

stty.h代码如下:

//filename:stty.h
#ifndef __STTY_H__
#define __STTY_H__

//包含头文件
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include<string.h>
#include<time.h>

#define DEVPATHLEN 40
// 串口设备信息结构
typedef struct tty_info_t
{
int fd; // 串口设备ID
pthread_mutex_t mt; // 线程同步互斥对象
char name[DEVPATHLEN]; // 串口设备名称,例:"/dev/ttyS0"
struct termios ntm; // 新的串口设备选项
struct termios otm; // 旧的串口设备选项
} TTY_INFO;

// 串口操作函数
TTY_INFO *readyTTY(char* devname);
int setTTYSpeed(TTY_INFO *ptty, int speed);
int setTTYParity(TTY_INFO *ptty,int databits,char parity,int stopbits);
int cleanTTY(TTY_INFO *ptty);
int sendnTTY(TTY_INFO *ptty,char *pbuf,int size);
int recvnTTY(TTY_INFO *ptty,char *pbuf,int size);
int lockTTY(TTY_INFO *ptty);
int unlockTTY(TTY_INFO *ptty);
void thread_receive(TTY_INFO *ptty);
void thread_send(TTY_INFO *ptty);

#endif

/*
从头文件中的函数定义不难看出,函数的功能,使用过程如下:
(1) 打开串口设备,调用函数setTTYSpeed();
(2) 设置串口读写的波特率,调用函数setTTYSpeed();
(3) 设置串口的属性,包括停止位、校验位、数据位等,调用函数setTTYParity();
(4) 向串口写入数据,调用函数sendnTTY();
(5) 从串口读出数据,调用函数recvnTTY();
(6) 操作完成后,需要调用函数cleanTTY()来释放申请的串口信息接口;
其中,lockTTY()和unlockTTY()是为了能够在多线程中使用。在读写操作的前后,需要锁定和释放串口资源。
具体的使用方法,在代码实现的原文件中,main()函数中进行了演示。下面就是源代码文件:
*/

// 初始化串口设备并进行原有设置的保存
TTY_INFO *readyTTY(char* DevName)
{
TTY_INFO *ptty;

ptty = (TTY_INFO *)malloc(sizeof(TTY_INFO));
if(ptty == NULL)
return NULL;
memset(ptty,0,sizeof(TTY_INFO));
pthread_mutex_init(&ptty->mt,NULL);
memset(ptty->name,0,DEVPATHLEN);
strcat(ptty->name,"/dev/");
strcat(ptty->name,DevName); //填充字符串数组内存

// 打开并且设置串口
ptty->fd = open(ptty->name, O_RDWR | O_NOCTTY |O_NDELAY);
if (ptty->fd <0)
{
free(ptty);
return NULL;
}

// 取得并且保存原来的设置
tcgetattr(ptty->fd,&ptty->otm);
return ptty;
}

// 清理串口设备资源
int cleanTTY(TTY_INFO *ptty)
{
//
// 关闭打开的串口设备
if(ptty->fd>0)
{
tcsetattr(ptty->fd,TCSANOW,&ptty->otm);
close(ptty->fd);
ptty->fd = -1;
free(ptty);
ptty = NULL;
}

return 0;
}

// 设置串口通信速率
// ptty 参数类型(TTY_INFO *),已经初始化的串口设备信息结构指针
// speed 参数类型(int),用来设置串口的波特率
// return 返回值类型(int),函数执行成功返回零值,否则返回大于零的值
int setTTYSpeed(TTY_INFO *ptty, int speed)
{
int i;
//
// 进行新的串口设置,数据位为8位
bzero(&ptty->ntm, sizeof(ptty->ntm));
tcgetattr(ptty->fd,&ptty->ntm);
ptty->ntm.c_cflag = /*CS8 |*/ CLOCAL | CREAD;

switch(speed)
{
case 300:
ptty->ntm.c_cflag |= B300;
break;
case 1200:
ptty->ntm.c_cflag |= B1200;
break;
case 2400:
ptty->ntm.c_cflag |= B2400;
break;
case 4800:
ptty->ntm.c_cflag |= B4800;
break;
case 9600:
ptty->ntm.c_cflag |= B9600;
break;
case 19200:
ptty->ntm.c_cflag |= B19200;
break;
case 38400:
ptty->ntm.c_cflag |= B38400;
break;
case 115200:
ptty->ntm.c_cflag |= B115200;
break;
}
ptty->ntm.c_iflag = IGNPAR;
ptty->ntm.c_oflag = 0;

tcflush(ptty->fd, TCIFLUSH);
tcsetattr(ptty->fd,TCSANOW,&ptty->ntm);
return 0;
}

// 设置串口数据位,停止位和效验位
// ptty 参数类型(TTY_INFO *),已经初始化的串口设备信息结构指针
// databits 参数类型(int), 数据位,取值为7或者8
// stopbits 参数类型(int),停止位,取值为1或者2
// parity 参数类型(int),效验类型 取值为N,E,O,,S
// return 返回值类型(int),函数执行成功返回零值,否则返回大于零的值
int setTTYParity(TTY_INFO *ptty,int databits,char parity,int stopbits)
{
// 取得串口设置
if( tcgetattr(ptty->fd,&ptty->ntm) != 0)
{
printf("SetupSerial [%s]\n",ptty->name);
return 1;
}

bzero(&ptty->ntm, sizeof(ptty->ntm));
ptty->ntm.c_cflag = CS8 | CLOCAL | CREAD;
ptty->ntm.c_iflag = IGNPAR;
ptty->ntm.c_oflag = 0;

// 设置串口的各种参数
ptty->ntm.c_cflag &= ~CSIZE;
switch (databits)
{
//设置数据位数
case 7:
ptty->ntm.c_cflag |= CS7;
break;
case 8:
ptty->ntm.c_cflag |= CS8;
break;
default:
printf("Unsupported data size\n");
return 5;
}

switch (parity)
{
// 设置奇偶校验位数
case 'n':
case 'N':
ptty->ntm.c_cflag &= ~PARENB; /* Clear parity enable */
ptty->ntm.c_iflag &= ~INPCK; /* Enable parity checking */
break;
case 'o':
case 'O':
ptty->ntm.c_cflag |= (PARODD|PARENB); /* 设置为奇效验*/
ptty->ntm.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'e':
case 'E':
ptty->ntm.c_cflag |= PARENB; /* Enable parity */
ptty->ntm.c_cflag &= ~PARODD; /* 转换为偶效验*/
ptty->ntm.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'S':
case 's': /*as no parity*/
ptty->ntm.c_cflag &= ~PARENB;
ptty->ntm.c_cflag &= ~CSTOPB;
break;
default:
printf("Unsupported parity\n");
return 2;
}

// 设置停止位
switch (stopbits)
{
case 1:
ptty->ntm.c_cflag &= ~CSTOPB;
break;
case 2:
ptty->ntm.c_cflag |= CSTOPB;
break;
default:
printf("Unsupported stop bits\n");
return 3;
}

ptty->ntm.c_lflag = 0;
ptty->ntm.c_cc[VTIME] = 0; // inter-character timer unused
ptty->ntm.c_cc[VMIN] = 1; // blocking read until 1 chars received
tcflush(ptty->fd, TCIFLUSH);
if (tcsetattr(ptty->fd,TCSANOW,&ptty->ntm) != 0)
{
printf("SetupSerial \n");
return 4;
}

return 0;
}

int recvnTTY(TTY_INFO *ptty,char *pbuf,int size)
{
int ret,left,bytes;

left = size;

while(left>0)
{
ret = 0;
bytes = 0;

pthread_mutex_lock(&ptty->mt);
ioctl(ptty->fd, FIONREAD, &bytes);
if(bytes>0)
{
ret = read(ptty->fd,pbuf,left);
}
pthread_mutex_unlock(&ptty->mt);
if(ret >0)
{
left -= ret;
pbuf += ret;
}
usleep(100);
}

return size - left;
}

int sendnTTY(TTY_INFO *ptty,char *pbuf,int size)
{
int ret,nleft;
char *ptmp;

ret = 0;
nleft = size;
ptmp = pbuf;

while(nleft>0)
{
pthread_mutex_lock(&ptty->mt);
ret = write(ptty->fd,ptmp,nleft);
pthread_mutex_unlock(&ptty->mt);

if(ret >0)
{
nleft -= ret;
ptmp += ret;
}
//usleep(100);
}

return size - nleft;
}

int lockTTY(TTY_INFO *ptty)
{
if(ptty->fd < 0)
{
return 1;
}

return flock(ptty->fd,LOCK_EX);
}
int unlockTTY(TTY_INFO *ptty)
{
if(ptty->fd < 0)
{
return 1;
}

return flock(ptty->fd,LOCK_UN);
}

//多线程读写相关函数
//ptty作为参数传入两个线程处理函数
//data->8 bits
void thread_receive(TTY_INFO *ptty)
{
int nbyte,idx=0;
unsigned char data[16];

while(1)
{
nbyte = recvnTTY(ptty,data,1);
printf("Receive Data %d:%02X\n",idx++,data[0]);
}

pthread_exit(0);
}

void thread_send(TTY_INFO *ptty)
{
unsigned char data;

while(1)
{
//printf("Please input the data(HEX:such as 0x00) you want to send:\n");
//scanf("%x",&data) ;
//sendnTTY(ptty,&data,1);
}

pthread_exit(0);
}


ReadWriteSerialPortLib.c代码如下:

// Serial Port接口
#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>

#include "stty.h"

#include <android/log.h>
#define TAG "ReadWriteSerialPortLib"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)

//#define DEVNAMELEN 35
TTY_INFO *ptty;

jint Java_org_echo_prox_accessarmborddevlib_openserialdev(JNIEnv* env, jobject thiz, jstring devname, jint baudrate)
{
const jbyte *DevNameStr;
char DevNameStrArray[DEVPATHLEN-5];

pthread_t id_rec,id_send;
int ret;

DevNameStr = (*env)->GetStringUTFChars(env, devname, NULL);
if (DevNameStr == NULL)
{
return -1;
}
memset(DevNameStrArray,0,DEVPATHLEN-5);
strcpy(DevNameStrArray,DevNameStr);

LOGE("devname:%s",DevNameStrArray);

ptty = readyTTY(DevNameStrArray);
if(ptty == NULL)
{
LOGE("readyTTY error");
return -1;
}

lockTTY(ptty);
if(setTTYSpeed(ptty,baudrate)>0)
{
LOGE("setTTYSpeed() error");
return -1;
}
if(setTTYParity(ptty,8,'N',1)>0)
{
LOGE("setTTYParity() error");
return -1;
}
LOGE("readyTTY OK");
return 0;
}

jint Java_org_echo_prox_accessarmborddevlib_writedata(JNIEnv* env, jobject thiz, jbyteArray dataarray, jint datalen)
{
jbyte * dataarraybuf = (jbyte*)(*env)->GetByteArrayElements(env, dataarray, 0);
int ret=-1;
ret=sendnTTY(ptty,dataarraybuf,datalen);
(*env)->ReleaseByteArrayElements(env, dataarray, dataarraybuf, 0);
return ret;
}

jint Java_org_echo_prox_accessarmborddevlib_closeserialdev(JNIEnv* env, jobject thiz)
{
unlockTTY(ptty);
cleanTTY(ptty);
LOGE("cleanTTY OK");
return 0;
}


Android.mk代码如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_LDLIBS += -llog

LOCAL_MODULE    := AccessARMBordDevLib
LOCAL_SRC_FILES := ReadWriteSerialPortLib.c

include $(BUILD_SHARED_LIBRARY)


accessarmborddevlib.java代码如下:

package org.echo.prox;

import android.util.Log;

public class accessarmborddevlib
{
static public native int openserialdev(String DevName,int BaudRate);
static public native int writedata(byte[] SendDataArray,int SendDataLen);
static public native int closeserialdev();

static {
try {
System.loadLibrary("AccessARMBordDevLib");
} catch (UnsatisfiedLinkError e) {
Log.d("readwriteserialportlib","ReadWriteSerialPortLib library not found!");
}
}
}


MainActivity.java核心代码如下:

org.echo.prox.accessarmborddevlib AccessDev =new org.echo.prox.accessarmborddevlib();
AccessDev.openserialdev("s3c2410_serial3", 9600);
byte[] data=new byte[4];
data[0]='p';
data[1]='r';
data[2]='o';
data[3]='x';
AccessDev.writedata(data, data.length);
AccessDev.closeserialdev();


要注意修改串口设备/dev/s3c2410_serial3的读写权限,至于如何修改可以参考这篇/article/9285337.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: