rk3288Android点亮LED

jni设备树点亮LED

一、只做自己的备忘,所以只有代码没有讲解。实验环境是firefly-android5.1-20180126的代码

二、如果open打开设备失败,要做如下操作:

    需要通过串口修改 /dev/300ask_led0 的权限为 777.(chmod 777 /dev/300ask_led0),否则leddrv.c中的open(“/dev/300ask_led0”, o_RDWR)会失败

三、首先JAVA应用层,是做其它实验用的,是点亮4个灯的,本次实验只点亮一个,我没去做更改,因为以后还会用到。

.1.XML文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.MainActivity"
android:orientation="vertical">

<Button
android:id="@+id/button"
android:layout_marginTop="30dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ALL ON"/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="vertical">
<CheckBox
android:id="@+id/checkbox_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LED1"/>

<CheckBox
android:id="@+id/checkbox_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LED2"/>

<CheckBox
android:id="@+id/checkbox_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LED3"/>

<CheckBox
android:id="@+id/checkbox_4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LED4"/>
</LinearLayout>

</LinearLayout>

2. Java 代码
2.1 public class HardControl {

static {
try {
System.loadLibrary("hardcontrol");
} catch (Exception e) {
e.printStackTrace();
}
}

public static native int ledCtrl(int which, int status);
public static native int ledOpen();
public static native void ledClose();
}

2.2 import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;

import cn.rk.R;
import cn.rk.hardlibrary.HardControl;


public class MainActivity extends AppCompatActivity implements View.OnClickListener {


private Button button;
private boolean ledon = false;
private int[] checkIds = {R.id.checkbox_1, R.id.checkbox_2, R.id.checkbox_3, R.id.checkbox_4};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

HardControl.ledOpen();

button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ledon = !ledon;
if (ledon) {
button.setText("ALL OFF");
}else {
button.setText("ALL ON");
}
setAllChecked(!ledon);
}
});

setAllChecked(ledon);
}

private void setAllChecked(boolean checked) {
for (int i=0; i < checkIds.length; i++){
CheckBox checkBox = findViewById(checkIds[i]);
if(!checked) {
checkBox.setOnClickListener(this);
}
checkBox.setChecked(checked);
if(checked){
HardControl.ledCtrl(i, 1);
}else {
HardControl.ledCtrl(i, 0);
}
}
}

@Override
protected void onPause() {
super.onPause();
HardControl.ledClose();
}

@Override
public void onClick(View v) {
for (int i=0; i < checkIds.length; i++){
CheckBox checkBox = findViewById(checkIds[i]);
checkBox.setChecked(false);
if(checkIds[i] == v.getId()){
checkBox.setChecked(true);
Toast.makeText(getApplicationContext(), "LED " + (++i), Toast.LENGTH_SHORT).show();
HardControl.ledCtrl(i, 1);
}else {
HardControl.ledCtrl(i, 0);
}
}
}
}

3. C库代码

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#include <unistd.h>

#include <string.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;
#endif

static jint fd;

jint ledOpen(JNIEnv *env, jobject cls)
{
fd = open("/dev/300ask_led0", O_RDWR);
__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "===native ledOpen : %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);
int ret = write(fd, &status, status);
__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "====native ledCtrl : %d, %d, %d", which, status, ret);
//__android_log_print(ANDROID_LOG_DEBUG, "LEDDemo", "native ledCtrl : %d, %d", which, status);
return ret;
//return 0;
}


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, "cn/rk/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;
}


4. 在设备树中添加和修改代码
leds {
// status = "disabled";
compatible = "gpio-leds";
power {
label = "firefly:blue:power";
linux,default-trigger = "ir-power-click";
default-state = "on";
gpios = <&gpio8 GPIO_A1 GPIO_ACTIVE_LOW>;
};
#if 0
user {
label = "firefly:yellow:user";
linux,default-trigger = "ir-user-click";
default-state = "off";
gpios = <&gpio8 GPIO_A2 GPIO_ACTIVE_LOW>;
};
#endif
};


hello-led{
compatible = "hello,leddrv";
led-gpios= <&gpio8 GPIO_A2 GPIO_ACTIVE_LOW>;
status = "okay";
};

5. 驱动代码
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/miscdevice.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
//#include <linux/gpio/consumer.h>
//#include <linux/of_platform.h>
#include <linux/platform_device.h>

/* 1. 确定主设备号 */
static int major = 0;
static struct class *led_class;
int gpio;

#define GPIO_LOW 0
#define GPIO_HIGH 1


/* 3. 实现对应的open/read/write等函数,填入file_operations结构体 */
static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}

/* write(fd, &val, 1); */
static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
int err;
char status;
//struct inode *inode = file_inode(file);
//int minor = iminor(inode);
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
err = copy_from_user(&status, buf, 1);
printk("%s %s line %d status=%d\n", __FILE__, __FUNCTION__, __LINE__,status);
/* 根据次设备号和status控制LED */
if (status)
gpio_set_value(gpio,GPIO_LOW);
else
gpio_set_value(gpio,GPIO_HIGH);
return 1;
}

static int led_drv_open (struct inode *node, struct file *file)
{
//int minor = iminor(node);
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
/* 根据次设备号初始化LED */
gpio_direction_output(gpio, GPIO_LOW);
return 0;
}

static int led_drv_close (struct inode *node, struct file *file)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}

/* 定义自己的file_operations结构体 */
static struct file_operations led_drv = {
.owner = THIS_MODULE,
.open = led_drv_open,
.read = led_drv_read,
.write = led_drv_write,
.release = led_drv_close,
};

static int firefly_hello_probe(struct platform_device *pdev)
{
int ret = -1;
int i;
enum of_gpio_flags flag;
struct device_node *hello_node = pdev->dev.of_node;

printk("==============%s-%d: enter\n",__FUNCTION__,__LINE__);

/* 4.1 设备树中定义有: led-gpios=<...>; */
gpio = of_get_named_gpio_flags(hello_node,"led-gpios", 0,&flag);
if (!gpio_is_valid(gpio)){
printk("============hello: invalid gpio : %d\n",gpio);
return -1;
}
ret = gpio_request(gpio, "leddrv");
if (ret != 0) {
gpio_free(gpio);
return -EIO;
}
/* 4.2 注册file_operations */
major = register_chrdev(0, "200ask_led", &led_drv); /* /dev/led */
led_class = class_create(THIS_MODULE, "200ask_led_class");
if (IS_ERR(led_class)) {
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
unregister_chrdev(major, "200ask_led");
gpio_free(gpio);
return PTR_ERR(led_class);
}

device_create(led_class, NULL, MKDEV(major, 0), NULL, "300ask_led%d", 0); /* /dev/100ask_led0 */



/*gpio_direction_output(gpio, GPIO_HIGH);

for(i=0; i < 10; i++)
{
gpio_set_value(gpio,GPIO_LOW);
mdelay(500);
gpio_set_value(gpio,GPIO_HIGH);
mdelay(500);
}*/
printk("===========%s-%d: exit\n",__FUNCTION__,__LINE__);
return 0; //return Ok
}


static int firefly_hello_remove(struct platform_device *pdev)
{
device_destroy(led_class, MKDEV(major, 0));
class_destroy(led_class);
unregister_chrdev(major, "200ask_led");
return 0;
}

static const struct of_device_id of_firefly_hello_match[] = {
{ .compatible = "hello,leddrv" },
{ /* Sentinel */ }
};


static struct platform_driver firefly_hello_driver = {
.probe = firefly_hello_probe,
.remove = firefly_hello_remove,
.driver = {
.name = "200ask_led",
//.owner = THIS_MODULE,
.of_match_table = of_firefly_hello_match,
},

};

static int __init hello_init(void)
{
printk(KERN_INFO "Enter %s\n", __FUNCTION__);
return platform_driver_register(&firefly_hello_driver);
return 0;
}

static void __exit hello_exit(void)
{
platform_driver_unregister(&firefly_hello_driver);
printk("============Exit Hello world\n");
}

subsys_initcall(hello_init);
module_exit(hello_exit);

MODULE_DESCRIPTION("Firefly hello driver");
MODULE_LICENSE("GPL");



0 条评论&回复

请先 登录 后评论
田旭
田旭

2 篇文章

作家榜 »

  1. 百问网-周老师 18 文章
  2. st_ashang 14 文章
  3. 渐进 12 文章
  4. zxq 11 文章
  5. helloworld 8 文章
  6. 谢工 5 文章
  7. Litchi_Zheng 5 文章
  8. 星星之火 5 文章