Auto start a java Swing GUI program when raspberry boots

I planed make an self-desgin photo or movie player base on Raspberry. Also I can use it as photo frame. If I need improve the performance of the PI, I need write it with Python, I think.

 

Part 1 – Build the Foundation

In this part, we will focus on preparing Raspbian Lite.

1. Download the latest Raspbian Lite image.
2. Format the SD / microSD card with Raspbian Lite (Plenty of guides out there on how to do this. For macOS, Linux, and Windows users, Etcher is an easy to use application that can help you do this.)
3. Insert the SD / microSD card into the Pi.
4. Connect the Pi to the Internet using an Ethernet cable. If you want to use Wi-Fi instead, you will have to read on how to configure your wireless receiver using the command line after your Pi has finished booting.
5. Connect your TV / Monitor and keyboard. (Mouse is optional at this time.) Turn on the Pi. The Pi should boot up successfully and a prompt to log in will appear.
6. Log into Raspbian. The username is pi and the password is raspberry.

 

7. We will install Xorg. To do this type in:

sudo apt-get install –no-install-recommends xserver-xorg

sudo apt-get install –no-install-recommends xinit

now, you can write you java program now. For example, I wrote a test program with a button in the center of screen. once I click the button, the window will change to the full size of the screen.

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class FullScreenTest {
public static void main(String[] args) {
final JFrame f = new JFrame(“FullScreenTest”);
final JButton btn = new JButton(“FullScreen”);
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (btn.getText().equals(“FullScreen”)) {
f.dispose();
f.setUndecorated(true);
f.getGraphicsConfiguration().getDevice().setFullScreenWindow(f);
f.setVisible(true);
btn.setText(“NormalMode”);
} else {
f.dispose();
f.setUndecorated(false);
f.getGraphicsConfiguration().getDevice().setFullScreenWindow(null);
f.setVisible(true);
btn.setText(“FullScreen”);
}
}
});

f.getContentPane().setLayout(new FlowLayout());
f.getContentPane().add(btn);
f.pack();
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}

 

Pack the file into a jar file like GUI.jar.

In order to have a command or program run when the Pi boots, you can add commands to the rc.local file. This is especially useful if you want to be able to plug your Pi in to power headless, and have it run a program without configuration or a manual start.

EDITING RC.LOCAL

On your Pi, edit the file /etc/rc.local using the editor of your choice. You must edit with root, for example:

sudo nano /etc/rc.local

Add commands below the comment, but leave the line exit 0 at the end, then save the file and exit.

sudo xinit /usr/local/jdk1.8.0_77/bin/java -jar /usr/local/mypi/GUI.jar — :1 &

 

 

Reboot your PI, then done!

基于树莓派Raspberry: 字符设备内核驱动程序框架编写[转]

之前写了一篇移植2.4寸TFT驱动到树莓派的文章,那篇博文中的驱动代码是国外大牛写的,看了一下,还是有很多地方没理解,是得好好再学习一下内核驱动的编写,这里就从字符设备驱动开始,采用最简单的LED驱动来建立内核驱动移植的驱动框架.

个人原创,转载请注明原文出处:

http://blog.csdn.net/embbnux/article/details/17712547

参考文章:

http://blog.csdn.net/hcx25909/article/details/16860725

内核驱动与普通单片机模块驱动的差别就是在于,写内核驱动的时候,要提供内核调用的接口,使内核能找到相应的驱动入口,用户通过告诉内核要干嘛,内核再去调用那个驱动,驱动的最底层和单片机模块是一样的,同样是对GPIO的操作,配置输入输出,以及某些特殊的寄存器. LED的点亮就是对GPIO的操作 .

对于ARM的GPIO调用需要通过IO映射的方法,要操作内存上对应的地址.

对于bcm2708上的io对应关系,可以查看bcm2835的手册,和stm32基本上是一样的,因为同为ARM体系:SouthEast

我参考的那博客讲这个比较清楚,可以参考下,由于树莓派的内核以及很好的提供了GPIO调用的接口,即把内存操作封装了很好,这里就不像那篇博客那样再自己写函数通过内存操作来进行GPIO操作,觉得有点麻烦,但是对于学好底层很有用.

  一  首先上个驱动程序

 

这里直接把该程序添加到内核的源码目录里面,也可在自己的目录下,但是要写Makefile.

在/drivers/char/新建rasp_led.c,内核中的kconfig文件和makefile文件,参照前一篇文章

led.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/********************************************************************/
/***************Rasp led 驱动程序************************************/
/***************作者: Embbnux Ji*************************************/
/***************博客: http://blog.csdn.net/embbnux/ *****************/
/********************************************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <mach/platform.h>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/gpio.h>
#define DEVICE_NAME "Pi_Led"
#define DRIVER_NAME "pi_led"
//class声明内核模块驱动信息,是UDEV能够自动生成/dev下相应文件
static dev_t pi_led_devno; //设备号
static struct class *pi_led_class;
static struct cdev pi_led_class_dev;
struct gpio_chip *gpiochip;
#define led_pin 4 //gpio 4
//这部分函数为内核调用后open的设备IO操作,和裸板程序一样
int open_flag=0;
static int pi_led_open(struct inode *inode, struct file *filp)
{
 printk("Open led ing!\n");
 if(open_flag ==0){
 open_flag =1;
 printk("Open led success!\n");
 return 0;
 }
 else{
 printk("Led has opened!\n");
 }
 return 0;
}
//这部分函数为内核调用后ioctl的设备IO操作,和裸板程序一样
static long pi_led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
 switch(cmd){
 case 0:
 gpiochip->set(gpiochip, led_pin, 0);
 printk("Led up!\n");
 break;
 case 1:
 gpiochip->set(gpiochip, led_pin, 1);
 printk("Led down!\n");
 break;
 }
 return 0;
}
static int pi_led_release(struct inode *inode,struct file *file){
 printk("Led has release!\n");
 return 0;
}
//file_operations使系统的open,ioctl等函数指针指向我们所写的led_open等函数,
//这样系统才能够调用
static struct file_operations pi_led_dev_fops = {
 .owner =THIS_MODULE,
 .open =pi_led_open,
 .unlocked_ioctl = pi_led_ioctl,
 .release = pi_led_release,
};
static int is_right_chip(struct gpio_chip *chip, void *data)
{
if (strcmp(data, chip->label) == 0)
 return 1;
 return 0;
}
//内核加载后的初始化函数.
static int __init pi_led_init(void)
{
 struct device *dev;
 int major; //自动分配主设备号
 major = alloc_chrdev_region(&pi_led_devno,0,1,DRIVER_NAME);
 //register_chrdev 注册字符设备使系统知道有LED这个模块在.
 cdev_init(&pi_led_class_dev, &pi_led_dev_fops);
 major = cdev_add(&pi_led_class_dev,pi_led_devno,1);
 //注册class
 pi_led_class = class_create(THIS_MODULE,DRIVER_NAME);
 dev = device_create(pi_led_class ,NULL,pi_led_devno,NULL,DRIVER_NAME);
 gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);
 gpiochip->direction_output(gpiochip, led_pin, 1);
 gpiochip->set(gpiochip, led_pin, 0);
 printk("pi led init ok!\n");
 return 0;
}
//内核卸载后的销毁函数.
void pi_led_exit(void)
{
 gpio_free(led_pin);
 device_destroy(pi_led_class,pi_led_devno);
 class_destroy(pi_led_class);
 cdev_del(&pi_led_class_dev);
 unregister_chrdev_region(pi_led_devno, 1);
 printk("pi led exit ok!\n");
}
module_init(pi_led_init);
module_exit(pi_led_exit);
MODULE_DESCRIPTION("Rasp Led Driver");
MODULE_AUTHOR("Embbnux Ji < http://blog.csdn.net/embbnux >");
MODULE_LICENSE("GPL");

二  源码框架分析

我们首先从内核模块的入口,module_init(pi_led_init)这个函数看起,可以看出初始化后调用pi_led_init这个函数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//内核加载后的初始化函数.
static int __init pi_led_init(void)
{
 struct device *dev;
 int major; //自动分配主设备号
 major = alloc_chrdev_region(&pi_led_devno,0,1,DRIVER_NAME);
 //register_chrdev 注册字符设备使系统知道有LED这个模块在.
 cdev_init(&pi_led_class_dev, &pi_led_dev_fops);
 major = cdev_add(&pi_led_class_dev,pi_led_devno,1);
 //注册class
 pi_led_class = class_create(THIS_MODULE,DRIVER_NAME);
 dev = device_create(pi_led_class ,NULL,pi_led_devno,NULL,DRIVER_NAME);
 gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);
 gpiochip->direction_output(gpiochip, led_pin, 1);
 gpiochip->set(gpiochip, led_pin, 0);
 printk("pi led init ok!\n");
 return 0;
}

初始化时首先分配给这个函数设备号,注册该设备,通过class注册使能够在/dev/目录下自动生成相应的设备文件,用户通过操作这个文件,来告诉内核怎么做.

由于是字符设备,所以对该文件的操作通过open,write,ioctl等函数,所以要把这个函数和底层的操作函数对应起来,这就要用到file_operation这个结构体,来声明:

1
2
3
4
5
6
7
8
//file_operations使系统的open,ioctl等函数指针指向我们所写的led_open等函数,
//这样系统才能够调用
static struct file_operations pi_led_dev_fops = {
 .owner =THIS_MODULE,
 .open =pi_led_open,
 .unlocked_ioctl = pi_led_ioctl,
 .release = pi_led_release,
};

这里就让open函数对应到pi_led_open函数,ioctl函数对应到pi_led_ioctl函数;

然后我们就只需要编写相应的pi_led_open以及pi_led_ioctl;这些函数里面的操作就是最底层的GPIO操作,和单片机是一样的.

三  GPIO操作

内核里面的GPIO操作函数,被定义在#include <linux/gpio.h>,这个头文件里面,树莓派官方做好了树莓派的GPIO在内核里面的注册,所以调用gpio.h里面的函数即可进行树莓派的GPIO操作.

1
gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);

通过上面这个函数把内核的GPIO操作和BCM2708的GPIO操作关联起来;

bcm2708的操作可以查看/arch/arm/mach-bcm2708/bcm2708_gpio.c文件,具体也是对内存地址的操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
#define GPIOFSEL(x) (0x00+(x)*4)
#define GPIOSET(x) (0x1c+(x)*4)
#define GPIOCLR(x) (0x28+(x)*4)
#define GPIOLEV(x) (0x34+(x)*4)
#define GPIOEDS(x) (0x40+(x)*4)
#define GPIOREN(x) (0x4c+(x)*4)
#define GPIOFEN(x) (0x58+(x)*4)
#define GPIOHEN(x) (0x64+(x)*4)
#define GPIOLEN(x) (0x70+(x)*4)
#define GPIOAREN(x) (0x7c+(x)*4)
#define GPIOAFEN(x) (0x88+(x)*4)
#define GPIOUD(x) (0x94+(x)*4)
#define GPIOUDCLK(x) (0x98+(x)*4)

这里定义的就是相应的GPIO寄存器的地址.

四  测试程序

ssh进入树莓派,在主目录下新建led.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
 int main(int argc, char **argv)
 {
 int on;
 int led_no;
 int fd;
 int i;
fd = open("/dev/pi_led", 0);
 if (fd < 0) {
 fd = open("/dev/pi_led", 0);
 }
 if (fd < 0) {
 perror("open device led");
 exit(1);
 }
for(i=0;i<=20;i++){
on = i%2;
ioctl(fd, on, led_no);
sleep(1);
}
close(fd);
return 0;
}

Center