犀渠玉剑良家子,白马金羁侠少年。这篇文章主要讲述android jni控制gpio (rk3288)相关的知识,希望能为你提供帮助。
1.添加驱动程序
2.编写jni c程序编译为库给java调用
3.app调用jni静态链接库操作底层驱动
1.添加驱动程序 修改/work/rk3288/firefly-rk3288_android5.1_git_20180126/kernel/drivers/Makefile
添加一行obj-y
+= carroll/
将carroll文件夹添加至此目录下/work/rk3288/firefly-rk3288_android5.1_git_20180126/kernel/drivers/
文件夹包含驱动源码及Makefile
# carroll
obj-y
= test_led.o
test_led.源码
#include < linux/kernel.h> #include < linux/init.h> #include < linux/module.h> #include < linux/delay.h> #include < linux/gpio.h> #ifdef CONFIG_OF #include < linux/of.h> #include < linux/of_gpio.h> #include < linux/of_platform.h> #endif#include < linux/fb.h> #include < linux/device.h> #include < linux/miscdevice.h> #define INVALID_GPIO -1 int led1_gpio = INVALID_GPIO; int led2_gpio = INVALID_GPIO; int led_gpio_active = 0; static int led_open(struct inode *inode, struct file *file) { printk("carroll led_open ok \\n"); return 0; }static int led_release(struct inode *inode, struct file *file) { printk("carroll led_close \\n"); return 0; }/* app : ioctl(fd, cmd, arg) */ static long led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { /* 根据传入的参数设置GPIO */ /* cmd : 0-off, 1-on */ /* arg : 0-1, which led */if ((cmd != 0) & & (cmd != 1)) return -EINVAL; if (arg > 4) return -EINVAL; if(arg == 0) { if(led1_gpio != INVALID_GPIO) gpio_set_value(led1_gpio, !cmd); } else if(arg == 1) { if(led2_gpio != INVALID_GPIO) gpio_set_value(led2_gpio, !cmd); }printk("carroll led_ioctl: %d \\n", cmd); return 0; }static struct file_operations led_fops = { .owner= THIS_MODULE, .open= led_open, .release= led_release, .unlocked_ioctl= led_ioctl, }; static struct miscdevice led_dev = { .minor = MISC_DYNAMIC_MINOR, .name = "test_led", .fops = & led_fops, }; static int firefly_led_probe(struct platform_device *pdev) { int ret = -1; enum of_gpio_flags flags; struct device_node *hello_node = pdev-> dev.of_node; printk("%s-%d: carroll \\n",__FUNCTION__,__LINE__); /* register test_led dev file */ ret = misc_register(& led_dev); if (ret < 0){ printk("carroll led register err!\\n"); return ret; }/* led1 init */ led1_gpio = of_get_named_gpio_flags(hello_node,"led1", 0,& flags); if (!gpio_is_valid(led1_gpio)){ printk("carroll: invalid gpio : %d\\n",led1_gpio); return -1; } ret = gpio_request(led1_gpio, "test_led"); if (ret != 0) { gpio_free(led1_gpio); printk("carroll: led1_gpio free\\n"); return -EIO; } gpio_direction_output(led1_gpio, !led_gpio_active); /* led2 init */ led2_gpio = of_get_named_gpio_flags(hello_node,"led2", 0,& flags); if (!gpio_is_valid(led2_gpio)){ printk("carroll: invalid gpio : %d\\n",led2_gpio); return -1; } ret = gpio_request(led2_gpio, "test_led"); if (ret != 0) { gpio_free(led2_gpio); printk("carroll: led2_gpio free\\n"); return -EIO; } gpio_direction_output(led2_gpio, !led_gpio_active); gpio_set_value(led1_gpio, led_gpio_active); gpio_set_value(led2_gpio, led_gpio_active); mdelay(500); gpio_set_value(led1_gpio, !led_gpio_active); gpio_set_value(led2_gpio, !led_gpio_active); return 0; //return Ok }static int firefly_led_remove(struct platform_device *pdev) { return 0; }#ifdef CONFIG_OF static const struct of_device_id of_firefly_led_match[] = { { .compatible = "firefly,test_led" }, { /* Sentinel */ } }; #endifstatic struct platform_driver firefly_led_driver = { .probe= firefly_led_probe, .remove= firefly_led_remove, .driver= { .name= "test_led", .owner= THIS_MODULE, #ifdef CONFIG_OF .of_match_table= of_firefly_led_match, #endif },}; static int major; static struct class *cls; static int __init led_init(void) { printk(KERN_INFO "carroll register led dev %s\\n", __FUNCTION__); return platform_driver_register(& firefly_led_driver); }static void __exit led_exit(void) { platform_driver_unregister(& firefly_led_driver); printk(KERN_INFO "carroll unregister led dev %s\\n", __FUNCTION__); }subsys_initcall(led_init); module_exit(led_exit); MODULE_AUTHOR("carroll < 1247627668@qq.com> "); MODULE_DESCRIPTION("carroll led driver"); MODULE_LICENSE("GPL");
修改/work/rk3288/firefly-rk3288_android5.1_git_20180126/kernel/arch/arm/boot/dts/firefly-rk3288.dts
firefly-led{
compatible = "firefly,led";
led-work = < & gpio8 GPIO_A2 GPIO_ACTIVE_LOW> ;
led-power = < & gpio8 GPIO_A1 GPIO_ACTIVE_LOW> ;
//carrol add start
status = "disabled";
};
test-led{
compatible = "firefly,test_led";
led1= < & gpio8 GPIO_A1 GPIO_ACTIVE_LOW> ;
led2= < & gpio8 GPIO_A2 GPIO_ACTIVE_LOW> ;
status = "okay";
};
//carrol add end
编译内核烧录即可
内核启动过程中闪烁一次,并产生/dev/test_led文件
添加可执行权限
su
chmod 777 /dev/test_led
2.编写jni c程序编译为库给java调用hardcontrol.c源码
#include < jni.h> /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */ #include < stdio.h> #include < stdlib.h> #include < sys/types.h> #include < sys/stat.h> #include < fcntl.h> #include < sys/ioctl.h> #include < android/log.h> /* liblog *///__android_log_print(ANDROID_LOG_DEBUG, "JNIDemo", "native add ..."); #if 0 typedef struct { char *name; /* Java里调用的函数名 */ char *signature; /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */ void *fnPtr; /* C语言实现的本地函数 */ } JNINativeMethod; #endifstatic jint fd; jint ledOpen(JNIEnv *env, jobject cls) { fd = open("/dev/test_led", O_RDWR); __android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledOpen /dev/test_led: %d", fd); if (fd > = 0) return 0; else return -1; }void ledClose(JNIEnv *env, jobject cls) { __android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledClose ..."); close(fd); }jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status) { int ret = ioctl(fd, status, which); __android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledCtrl : %d, %d, %d", which, status, ret); return ret; }static const JNINativeMethod methods[] = { {"ledOpen", "()I", (void *)ledOpen}, {"ledClose", "()V", (void *)ledClose}, {"ledCtrl", "(II)I", (void *)ledCtrl}, }; /* System.loadLibrary */ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { JNIEnv *env; jclass cls; if ((*jvm)-> GetEnv(jvm, (void **)& env, JNI_VERSION_1_4)) { return JNI_ERR; /* JNI version not supported */ } cls = (*env)-> FindClass(env, "com/thisway/hardlibrary/HardControl"); if (cls == NULL) { return JNI_ERR; }/* 2. map java hello < --> c c_hello */ if ((*env)-> RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0])) < 0) return JNI_ERR; return JNI_VERSION_1_4; }
根据rk3288 android5.1 linux3.1编译库,必须使用arm-linux-gcc库(也可采用android studio cmake或ndk编译)
arm-linux-gcc -fPIC -shared hardcontrol.c -o libhardcontrol.so -I /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/-nostdlib /work/rk3288/firefly-rk3288_android5.1_git_20180126/prebuilts/ndk/9/platforms/android-21/arch-arm/usr/lib/libc.so-I /work/rk3288/firefly-rk3288_android5.1_git_20180126/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/include/work/rk3288/firefly-rk3288_android5.1_git_20180126/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/liblog.so
没有安装arm-linux-gcc的可以按照以下方法
安装交叉编译工具sudo tar xvzf arm-linux-gcc-4.5.1-v6-vfp-20120301.tgz -C /注意: C 后面有个空格,并且 C 是大写的,它是英文单词“ Change”的第一个字母,在此 是改变目录的意思。 执行该命令,将把 arm-linux-gcc 安装到/opt/FriendlyARM/toolschain/4.5.1 目录。Step2:把编译器路径加入系统环境变量,运行命令 sudo gedit ~/.bashrc 编辑 /root/.bashrc 文件, 注意“bashrc”前面有一个“.”,修改最后一行为 export PATH=$PATH:/opt/FriendlyARM/toolschain/4.5.1/bin 注意路径一定要写对,否则将不会有效。 如图,保存退出
编译产生libhardcontrol.so库文件,app将会使用到
3.app调用jni静态链接库操作底层驱动android app包结构必须相同,上边jni程序已经指定class名为 "com/thisway/hardlibrary/HardControl",
在app/libs/armeabi/目录下添加编译好的库,没有目录自己新建目录
文章图片
MainActivity.java
package com.thisway.app_0001_leddemo; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.widget.Button; import android.view.View; import android.widget.CheckBox; import android.widget.Toast; import com.thisway.hardlibrary.*; public class MainActivity extends AppCompatActivity {private boolean ledon = false; private Button button = null; private CheckBox checkBoxLed1 = null; private CheckBox checkBoxLed2 = null; private CheckBox checkBoxLed3 = null; private CheckBox checkBoxLed4 = null; class MyButtonListener implements View.OnClickListener { @Override public void onClick(View v) { ledon = !ledon; if (ledon) { button.setText("ALL OFF"); checkBoxLed1.setChecked(true); checkBoxLed2.setChecked(true); checkBoxLed3.setChecked(true); checkBoxLed4.setChecked(true); for (int i = 0; i < 4; i++) HardControl.ledCtrl(i, 1); } else { button.setText("ALL ON"); checkBoxLed1.setChecked(false); checkBoxLed2.setChecked(false); checkBoxLed3.setChecked(false); checkBoxLed4.setChecked(false); for (int i = 0; i < 4; i++) HardControl.ledCtrl(i, 0); } } }public void onCheckboxClicked(View view) { // Is the view now checked? boolean checked = ((CheckBox) view).isChecked(); // Check which checkbox was clicked switch(view.getId()) { case R.id.LED1: if (checked) { // Put some meat on the sandwich Toast.makeText(getApplicationContext(), "LED1 on", Toast.LENGTH_SHORT).show(); HardControl.ledCtrl(0, 1); } else { // Remove the meat Toast.makeText(getApplicationContext(), "LED1 off", Toast.LENGTH_SHORT).show(); HardControl.ledCtrl(0, 0); } break; case R.id.LED2: if (checked) { // Put some meat on the sandwich Toast.makeText(getApplicationContext(), "LED2 on", Toast.LENGTH_SHORT).show(); HardControl.ledCtrl(1, 1); } else { // Remove the meat Toast.makeText(getApplicationContext(), "LED2 off", Toast.LENGTH_SHORT).show(); HardControl.ledCtrl(1, 0); } break; case R.id.LED3: if (checked) { // Put some meat on the sandwich Toast.makeText(getApplicationContext(), "LED3 on", Toast.LENGTH_SHORT).show(); HardControl.ledCtrl(2, 1); } else { // Remove the meat Toast.makeText(getApplicationContext(), "LED3 off", Toast.LENGTH_SHORT).show(); HardControl.ledCtrl(2, 0); } break; case R.id.LED4: if (checked) { // Put some meat on the sandwich Toast.makeText(getApplicationContext(), "LED4 on", Toast.LENGTH_SHORT).show(); HardControl.ledCtrl(3, 1); } else { // Remove the meat Toast.makeText(getApplicationContext(), "LED4 off", Toast.LENGTH_SHORT).show(); HardControl.ledCtrl(3, 0); } break; // TODO: Veggie sandwich } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.BUTTON); HardControl.ledOpen(); checkBoxLed1 = (CheckBox) findViewById(R.id.LED1); checkBoxLed2 = (CheckBox) findViewById(R.id.LED2); checkBoxLed3 = (CheckBox) findViewById(R.id.LED3); checkBoxLed4 = (CheckBox) findViewById(R.id.LED4); button.setOnClickListener(new MyButtonListener()); /* button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { // Perform action on click ledon = !ledon; if (ledon) button.setText("ALL OFF"); else button.setText("ALL ON"); } }); */ }@Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; }@Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; }return super.onOptionsItemSelected(item); } }
HardControl.java
package com.thisway.hardlibrary; public class HardControl { public static native int ledCtrl(int which, int status); public static native int ledOpen(); public static native void ledClose(); static { try { System.loadLibrary("hardcontrol"); } catch (Exception e) { e.printStackTrace(); } } }
然后就可通过app控制两个gpio
【android jni控制gpio (rk3288)】
推荐阅读
- 使用H5搭建webapp主页面
- [译]Android view 测量布局和绘制的流程
- eclipse java项目转idea java项目Invalid bound statement (not found): com.mapper 报错问题
- vsphere6.0故障(关于vCenter Appliance6.0磁盘爆满和WEB503错误问题)
- Django --- Django下载和APP创建ORM (大概步骤)
- react-native app集成阿里云推送
- Android工程内嵌Flutter
- Android下的几种时间格式转换
- spring-boot-2.0.3不一样系列之源码篇 - SpringApplication的run方法之SpringApplicationRunListener,绝对有值得你看的地方