嵌入式系统
数码管实验
1.阅读Makefile
ROOTFS_DIR=/source/rootfs
APP_NAME= segtest
CROSS_COMPILE=/usr/local/toolchain/toolchain-4.6.4/bin/arm-none-linux-gnueabi-
CC=$(CROSS_COMPILE)gcc
ifeq ($(KERNELRELEASE), )
KERNEL_DIR ?=/home/linux/workdir/kernel/linux-3.0.15
CUR_DIR=$(shell pwd)
all:
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
$(CC) $(APP_NAME).c -o $(APP_NAME)
clean :
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
rm -rf $(APP_NAME)
.PHONY : modules modules_install clean
install:
cp -raf *.ko $(APP_NAME) $(ROOTFS_DIR)/
else
obj-m +=FS4412_segdis_drv_2.o
endif
arm-none-linux-gnueabi-gcc segtest.c -pthread -o segtest
//segtest.c
#include "Ex3_API.h"
int main(void)
{
uint8_t cmd[9];
int i, cas, tmp, fd_segdis = open(SEGMENT_DISPLAY, O_WRONLY);
while (1)
{
printf("\n\nFS4412_segment_display Control:\n");
printf("[1]: clear segment displays\n");
printf("[2]: display 1 digit\n");
printf("[3]: display 8 numbers\n\n\n\n");
printf("[q]: Quit\n\n");
printf("Please select: ");
cas = 0;
scanf("%d", &cas);
printf("\n\n");
if (cas == 1)
{
cmd[0] = 0;
cmd[1] = 0;
FS4412_segdis_clr(fd_segdis, cmd);
}
else if (cas == 2)
{
printf("Please input [position(1~8) digit(0~F)]: ");
scanf("%d %c", &tmp, &cmd[1]);
cmd[0] = tmp;
if (cmd[0] > 0 && cmd[0] <= 8 &&
(cmd[1] >= '0' && cmd[1] <= '9' ||
cmd[1] >= 'A' && cmd[1] <= 'F' ||
cmd[1] >= 'a' && cmd[1] <= 'f'))
FS4412_segdis_w_dig(fd_segdis, cmd);
}
else if (cas == 3)
{
cmd[0] = 9;
printf("Please input 8 number(0~F): ");
while (getchar() != '\n');
for (i = 1; i <= 8; i++)
{
scanf("%c", &cmd[i]);
if (cmd[i] >= '0' && cmd[i] <= '9'
|| cmd[i] >= 'A' && cmd[i] <= 'F'
|| cmd[i] >= 'a' && cmd[i] <= 'f')
continue;
return 0;
}
FS4412_segdis_w_num(fd_segdis, cmd);
}
else
break;
}
return 0;
}
//Ex3_API.h
#ifndef _EX3_API_H
#define _EX3_API_H
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <pthread.h>
#include <signal.h>
/* path of devices */
#define LED ("/dev/FS4412_LED")
#define SEGMENT_DISPLAY ("/dev/FS4412_segdis")
#define LED_MAGIC 'L'
#define LED_STATE _IOR(LED_MAGIC, 0, uint8_t)
#define LED_SWITCH _IOW(LED_MAGIC, 1, uint8_t)
#define LED_ROTATE _IOW(LED_MAGIC, 2, size_t)
/**********************************************************************
* @Function: FS4412_LED_state
* @Description: get LED state
* @Param[in]: (int)fd:
* file descriptor of LED device,
* (uint8_t)led_sts[4]:
* led_sts[n] will be set 1 if led n is on,
* otherwise led_sts[n] will be set 0
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_LED_state(fd, led_sts) ioctl(fd, LED_STATE, led_sts)
/**********************************************************************
* @Function: FS4412_LED_switch
* @Description: switch on/off LED
* @Param[in]: (int)fd:
* file descriptor of LED device,
* (uint_8)led:
* LED number
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_LED_switch(fd, led) ioctl(fd, LED_SWITCH, led)
/**********************************************************************
* @Function: FS4412_LED_rotate
* @Description: move LED
* @Param[in]: (int)fd:
* file descriptor of LED device,
* (size_t)rt_args[2]:
* rt_args[0]: 0: stop rotating
* 1: move anticlockwise
* 2: move clockwise
* 3: rotate anticlockwise
* 4: rotate clockwise
* rt_args[1]: rotation delay (ms)
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_LED_rotate(fd, rt_args) ioctl(fd, LED_ROTATE, rt_args)
/*************************** NOTICE ***********************************
* there should be an interval of more than 2 ms
* between segment display control functions calls
*********************************************************************/
/**********************************************************************
* @Function: FS4412_segdis_clr
* @Description: clear segment displays
* @Param[in]: (int)fd:
* file descriptor of segment displays device,
* (uint8_t)cmd[2]:
* cmd[0]: must be 0
* cmd[1]: digit postion(1-8), if 0 clear all
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_segdis_clr(fd, cmd) write(fd, cmd, 2)
/**********************************************************************
* @Function: FS4412_segdis_w_dig
* @Description: display 1 digit
* @Param[in]: (int)fd_LED:
* file descriptor of segment displays device,
* (uint8_t)dig[2]:
* dig[0]: digit position(1-8)
* dig[1]: (char)digit to be displayed
* @Return: other than -1 upon successful completion
**********************************************************************/
#define
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/err.h>
#include <linux/uaccess.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/atomic.h>
#include "FS4412_segdis_drv_2.h"
#define DEV_NAME ("FS4412_segdis")
#define SEGDIS_BASEMINOR 0
#define SEGDIS_COUNT 1
MODULE_AUTHOR("Xiao Maolv");
MODULE_DESCRIPTION("segment displays drv for Ex3");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("1.0");
struct FS4412_segdis_struct
{
dev_t cd;
atomic_t count;
struct cdev Sdev;
struct i2c_client *client;
struct class *cls;
struct device *dev;
};
static int __init FS4412_segdis_init(void);
static void __exit FS4412_segdis_exit(void);
static int __devinit FS4412_segdis_probe(struct i2c_client *client, const struct i2c_device_id *id);
static int __devexit FS4412_segdis_remove(struct i2c_client *client);
static int FS4412_segdis_open(struct inode *inode, struct file *filp);
static int FS4412_segdis_release(struct inode *inode, struct file *filp);
static ssize_t FS4412_segdis_write(struct file *filp, const char __user *buffer, size_t count, loff_t *ppos);
static int FS4412_segdis_w_cmd(char *buffer, const size_t count);
struct FS4412_segdis_struct FS4412_segdis;
static const struct i2c_device_id FS4412_segdis_idtbl[] =
{
{DEV_NAME, 0},
{ },
};
MODULE_DEVICE_TABLE(i2c, FS4412_segdis_idtbl);
static struct i2c_driver FS4412_segdis_driver =
{
.probe = FS4412_segdis_probe,
.remove = __devexit_p(FS4412_segdis_remove),
.id_table = FS4412_segdis_idtbl,
.driver =
{
.name = DEV_NAME,
.owner = THIS_MODULE,
},
};
static struct file_operations fops =
{
.owner = THIS_MODULE,
.open = FS4412_segdis_open,
.release = FS4412_segdis_release,
.write = FS4412_segdis_write,
};
static int __init FS4412_segdis_init(void)
{
/* register segment display driver */
return i2c_add_driver(&FS4412_segdis_driver);
}
static void __exit FS4412_segdis_exit(void)
{
/* unregister segment display driver */
i2c_del_driver(&FS4412_segdis_driver);
}
static int __devinit FS4412_segdis_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int err;
FS4412_segdis.client = client;
/* allocate device numbers to segment display */
err = alloc_chrdev_region(&FS4412_segdis.cd, SEGDIS_BASEMINOR, SEGDIS_COUNT, DEV_NAME);
if (err < 0)
{
printk(KERN_ERR "fail to allocate segdis device number\n");
return err;
}
/* initialize cdev structure of segment display */
cdev_init(&FS4412_segdis.Sdev, &fops);
FS4412_segdis.Sdev.owner = THIS_MODULE;
/* add segment display device to the system */
err = cdev_add(&FS4412_segdis.Sdev, FS4412_segdis.cd, SEGDIS_COUNT);
if (err < 0)
{
printk(KERN_ERR "fail to add segdis to system\n");
unregister_chrdev_region(FS4412_segdis.cd, SEGDIS_COUNT);
return err;
}
/* create segment display device */
FS4412_segdis.cls = class_create(THIS_MODULE, DEV_NAME);
if (IS_ERR(FS4412_segdis.cls))
{
printk(KERN_ERR "fail to create class");
return PTR_ERR(FS4412_segdis.cls);
}
FS4412_segdis.dev = device_create(FS4412_segdis.cls, NULL, FS4412_segdis.cd, NULL, DEV_NAME);
if (IS_ERR(FS4412_segdis.dev))
{
printk(KERN_ERR "fail to create device");
return PTR_ERR(FS4412_segdis.dev);
}
printk(KERN_NOTICE "insert segdis drv\n");
return 0;
}
static int __devexit FS4412_segdis_remove(struct i2c_client *client)
{
/* remove segment display device */
device_destroy(FS4412_segdis.cls, FS4412_segdis.cd);
class_destroy(FS4412_segdis.cls);
/* remove segment display from the system */
cdev_del(&FS4412_segdis.Sdev);
/* unregister device numbers of segment display */
unregister_chrdev_region(FS4412_segdis.cd, SEGDIS_COUNT);
printk(KERN_NOTICE "remove segdis drv\n");
return 0;
}
static int FS4412_segdis_open(struct inode *inode, struct file *filp)
{
/* to be exclusive */
if (atomic_read(&FS4412_segdis.count))
{
printk(KERN_ERR "segment display busy\n");
return -EBUSY;
}
atomic_add(1, &FS4412_segdis.count);
/* clear segment display*/
char buf[] = {ZLG7290_CMDBUF0_REG_ADDR, ZLG7290_COMBUF0_SL_PREF | ZLG7290_COMBUF0_SL_VAL};
int err = i2c_master_send(FS4412_segdis.client, buf, 2);
if (err < 0)
{
printk(KERN_ERR "fail to clear the display when open\n");
return err;
}
return 0;
}
static int FS4412_segdis_release(struct inode *inode, struct file *filp)
{
/* clear segment display*/
char buf[] = {ZLG7290_CMDBUF0_REG_ADDR, ZLG7290_COMBUF0_SL_PREF | ZLG7290_COMBUF0_SL_VAL};
int err = i2c_master_send(FS4412_segdis.client, buf, 2);
if (err < 0)
{
printk(KERN_ERR "fail to clear the display when close\n");
return err;
}
if (!atomic_read(&FS4412_segdis.count))
{
printk(KERN_ERR "device closed before");
return -ENODEV;
}
atomic_sub(1, &FS4412_segdis.count);
return 0;
}
static ssize_t FS4412_segdis_write(struct file *filp, const char __user *buffer, size_t count, loff_t *ppos)
{
uint8_t i;
int err;
char *wbuf;
if (count != 2 && count != 9)
goto inval_err;
wbuf = kmalloc(count, GFP_KERNEL);
if (!wbuf)
{
printk(KERN_ERR "fail to alloc mem for write buf\n");
return -ENOMEM;
}
if (copy_from_user(wbuf, buffer, count))
{
printk(KERN_ERR "fail to get write buf from usr\n");
goto copy_err;
}
if (wbuf[0] > 9)
goto inval_err;
else if (!wbuf[0] && wbuf[1] > 8U)
goto inval_err;
else if (wbuf[0])
{
for (i = 1; i < count; i++)
{
if (wbuf[i] >= 'A' && wbuf[i] <= 'F')
wbuf[i] = wbuf[i] - 'A' + 10;
else if (wbuf[i] >= 'a' && wbuf[i] <= 'f')
wbuf[i] = wbuf[i] - 'a' + 10;
else if (wbuf[i] >= '0' && wbuf[i] <= '9')
wbuf[i] = wbuf[i] - '0';
else
goto inval_err;
}
}
err = FS4412_segdis_w_cmd(wbuf, count);
if (err < 0)
{
printk(KERN_ERR "i2c write err\n");
return err;
}
kfree(wbuf);
return 0;
inval_err:
printk(KERN_ERR "invalid agrs\n");
copy_err:
kfree(wbuf);
return -EINVAL;
}
/**********************************************************************
* @Function: FS4412_segdis_w_cmd
* @Description: issue segment display control command
* @Param[in]: (char)buffer[]: command
* (size_t)count: length of buffer
* @Return: 0 if success, otherwise negative errno
**********************************************************************/
static int FS4412_segdis_w_cmd(char *buffer, const size_t count)
{
int i;
char buf[9] = { ZLG7290_DPRAM0_ADDR };
uint8_t reg_addr[] = { ZLG7290_DPRAM0_ADDR, ZLG7290_DPRAM1_ADDR,ZLG7290_DPRAM2_ADDR,
ZLG7290_DPRAM3_ADDR, ZLG7290_DPRAM4_ADDR, ZLG7290_DPRAM5_ADDR,
ZLG7290_DPRAM6_ADDR, ZLG7290_DPRAM7_ADDR };
uint8_t num_tbl[] = { SEG_DIS_0, SEG_DIS_1, SEG_DIS_2, SEG_DIS_3, SEG_DIS_4,
SEG_DIS_5, SEG_DIS_6, SEG_DIS_7, SEG_DIS_8, SEG_DIS_9,
SEG_DIS_A, SEG_DIS_B, SEG_DIS_C, SEG_DIS_D, SEG_DIS_E,
SEG_DIS_F };
switch (buffer[0])
{
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
buf[0] = reg_addr[buffer[0] - 1];
buf[1] = num_tbl[(int)buffer[1]];
return i2c_master_send(FS4412_segdis.client, buf, 2);
case 9:
for (i = 1; i <= 8; i++)
buf[i] = num_tbl[(int)buffer[i]];
}
return i2c_master_send(FS4412_segdis.client, buf, 9);
}
module_init(FS4412_segdis_init);
module_exit(FS4412_segdis_exit);
#ifndef _FS4412_SEGDIS_DRV_2_H
#define _FS4412_SEGDIS_DRV_2_H
#define ZLG7290_CMDBUF0_REG_ADDR 0x07U
#define ZLG7290_DPRAM0_ADDR 0x10
#define ZLG7290_DPRAM1_ADDR 0x11
#define ZLG7290_DPRAM2_ADDR 0x12
#define ZLG7290_DPRAM3_ADDR 0x13
#define ZLG7290_DPRAM4_ADDR 0x14
#define ZLG7290_DPRAM5_ADDR 0x15
#define ZLG7290_DPRAM6_ADDR 0x16
#define ZLG7290_DPRAM7_ADDR 0x17
#define ZLG7290_COMBUF0_SL_PREF 0x10U
#define ZLG7290_COMBUF0_SL_VAL 0x07U
#define SEG_DIS_0 0xFC
#define SEG_DIS_1 0x0C
#define SEG_DIS_2 0xDA
#define SEG_DIS_3 0xF2
#define SEG_DIS_4 0x66
#define SEG_DIS_5 0xB6
#define SEG_DIS_6 0xBE
#define SEG_DIS_7 0xE0
#define SEG_DIS_8 0xFE
#define SEG_DIS_9 0xF6
#define SEG_DIS_A 0xEE
#define SEG_DIS_B 0x3E
#define SEG_DIS_C 0x9C
#define SEG_DIS_D 0x7A
#define SEG_DIS_E 0x9E
#define SEG_DIS_F 0x8E
#endif
LED实验
ROOTFS_DIR=/source/rootfs
APP_NAME= ledtest
CROSS_COMPILE=/usr/local/toolchain/toolchain-4.6.4/bin/arm-none-linux-gnueabi-
CC=$(CROSS_COMPILE)gcc
ifeq ($(KERNELRELEASE), )
KERNEL_DIR ?=/home/linux/workdir/kernel/linux-3.0.15
CUR_DIR=$(shell pwd)
all:
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
$(CC) $(APP_NAME).c -o $(APP_NAME)
clean :
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
rm -rf $(APP_NAME)
.PHONY : modules modules_install clean
install:
cp -raf *.ko $(APP_NAME) $(ROOTFS_DIR)/
else
obj-m +=FS4412_LED_drv.o
endif
//ledtest.c
#include "Ex3_API.h"
int main(void)
{
int led, cas;
uint8_t led_sts[4];
size_t rt_args[] = { 0, 500 };
int fd_LED = open(LED, O_RDWR);
while (1)
{
cas = 0;
printf("\n\n\nFS4412_LED Control:\n");
printf("[1]: switch on or off\n");
printf("[2]: move a step\n");
printf("[3]: rotate\n\n\n\n");
printf("[q]: Quit\n\n");
printf("Please select: ");
scanf("%d", &cas);
printf("\n\n");
if (cas == 1)
{
printf("Please input LED number(1~4): ");
scanf("%d", &led);
FS4412_LED_switch(fd_LED, led);
}
else if (cas == 2)
{
while (getchar() != '\n');
printf("Please input move direction [c(clockwise)/a(anti-clockwise)]: ");
scanf("%c", &rt_args[0]);
if (rt_args[0] == 'a' || rt_args[0] == 'A')
rt_args[0] = 1;
else if (rt_args[0] == 'c' || rt_args[0] == 'C')
rt_args[0] = 2;
FS4412_LED_rotate(fd_LED, rt_args);
}
else if (cas == 3)
{
while (getchar() != '\n');
printf("Please input rotate direction [c(clockwise)/a(anti-clockwise)]: ");
scanf("%c", &rt_args[0]);
if (rt_args[0] == 'a' || rt_args[0] == 'A')
rt_args[0] = 3;
else if (rt_args[0] == 'c' || rt_args[0] == 'C')
rt_args[0] = 4;
FS4412_LED_rotate(fd_LED, rt_args);
printf("rotating...\n");
sleep(8);
rt_args[0] = 0;
FS4412_LED_rotate(fd_LED, rt_args);
}
else
break;
}
return 0;
}
#ifndef _EX3_API_H
#define _EX3_API_H
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <pthread.h>
#include <signal.h>
/* path of devices */
#define LED ("/dev/FS4412_LED")
#define SEGMENT_DISPLAY ("/dev/FS4412_segdis")
#define LED_MAGIC 'L'
#define LED_STATE _IOR(LED_MAGIC, 0, uint8_t)
#define LED_SWITCH _IOW(LED_MAGIC, 1, uint8_t)
#define LED_ROTATE _IOW(LED_MAGIC, 2, size_t)
/**********************************************************************
* @Function: FS4412_LED_state
* @Description: get LED state
* @Param[in]: (int)fd:
* file descriptor of LED device,
* (uint8_t)led_sts[4]:
* led_sts[n] will be set 1 if led n is on,
* otherwise led_sts[n] will be set 0
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_LED_state(fd, led_sts) ioctl(fd, LED_STATE, led_sts)
/**********************************************************************
* @Function: FS4412_LED_switch
* @Description: switch on/off LED
* @Param[in]: (int)fd:
* file descriptor of LED device,
* (uint_8)led:
* LED number
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_LED_switch(fd, led) ioctl(fd, LED_SWITCH, led)
/**********************************************************************
* @Function: FS4412_LED_rotate
* @Description: move LED
* @Param[in]: (int)fd:
* file descriptor of LED device,
* (size_t)rt_args[2]:
* rt_args[0]: 0: stop rotating
* 1: move anticlockwise
* 2: move clockwise
* 3: rotate anticlockwise
* 4: rotate clockwise
* rt_args[1]: rotation delay (ms)
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_LED_rotate(fd, rt_args) ioctl(fd, LED_ROTATE, rt_args)
/*************************** NOTICE ***********************************
* there should be an interval of more than 2 ms
* between segment display control functions calls
*********************************************************************/
/**********************************************************************
* @Function: FS4412_segdis_clr
* @Description: clear segment displays
* @Param[in]: (int)fd:
* file descriptor of segment displays device,
* (uint8_t)cmd[2]:
* cmd[0]: must be 0
* cmd[1]: digit postion(1-8), if 0 clear all
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_segdis_clr(fd, cmd) write(fd, cmd, 2)
/**********************************************************************
* @Function: FS4412_segdis_w_dig
* @Description: display 1 digit
* @Param[in]: (int)fd_LED:
* file descriptor of segment displays device,
* (uint8_t)dig[2]:
* dig[0]: digit position(1-8)
* dig[1]: (char)digit to be displayed
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_segdis_w_dig(fd, dig) write(fd, dig, 2)
/**********************************************************************
* @Function: FS4412_segdis_w_num
* @Description: display 8 number
* @Param[in]: (int)fd:
* file descriptor of segment displays device,
* (uint8_t)num[9]:
* num[0]: must be 9
* num[1-8]: (char)numbers to be displayed
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_segdis_w_num(fd, num) write(fd, num, 9)
#endif
#ifndef _FS4412_LED_DRV_H
#define _FS4412_LED_DRV_H
/*
* SFR memory map
*/
#define GPIO_RIGHT_BASE 0x11000000U
#define GPIO_LEFT_BASE 0x11400000U
#define GPF3_BASE (GPIO_LEFT_BASE + 0x01E0U)
#define GPX1_BASE (GPIO_RIGHT_BASE + 0x0C20U)
#define GPX2_BASE (GPIO_RIGHT_BASE + 0x0C40U)
/*
* SFR structures
*/
typedef struct
{
uint32_t CON;
uint32_t DAT;
} GPIO_TypeDef;
/*
* Bit operation
*/
/* Bit operation for GPF3_CON */
#define GPF3_CON_4_POS (16U)
#define GPF3_CON_4_MSK (0x0FU << GPF3_CON_4_POS)
#define GPF3_CON_4_CLR (~GPF3_CON_4_MSK)
#define GPF3_CON_4_OUT (0x01U << GPF3_CON_4_POS)
#define GPF3_CON_5_POS (20U)
#define GPF3_CON_5_MSK (0x0FU << GPF3_CON_5_POS)
#define GPF3_CON_5_CLR (~GPF3_CON_5_MSK)
#define GPF3_CON_5_OUT (0x01U << GPF3_CON_5_POS)
/* Bit operation for GPX1_CON */
#define GPX1_CON_0_POS (0U)
#define GPX1_CON_0_MSK (0x0FU << GPX1_CON_0_POS)
#define GPX1_CON_0_CLR (~GPX1_CON_0_MSK)
#define GPX1_CON_0_OUT (0x01U << GPX1_CON_0_POS)
/* Bit operation for GPX2_CON */
#define GPX2_CON_7_POS (28U)
#define GPX2_CON_7_MSK (0x0FU << GPX2_CON_7_POS)
#define GPX2_CON_7_CLR (~GPX2_CON_7_MSK)
#define GPX2_CON_7_OUT (0x01U << GPX2_CON_7_POS)
/* Bit operation for GPF3_DAT */
#define GPF3_DAT_4_POS (4U)
#define GPF3_DAT_4_MSK (0x01U << GPF3_DAT_4_POS)
#define GPF3_DAT_4_CLR (~GPF3_DAT_4_MSK)
#define GPF3_DAT_5_POS (5U)
#define GPF3_DAT_5_MSK (0x01U << GPF3_DAT_5_POS)
#define GPF3_DAT_5_CLR (~GPF3_DAT_5_MSK)
/* Bit operation for GPX1_DAT */
#define GPX1_DAT_0_POS (0U)
#define GPX1_DAT_0_MSK (0x01U << GPX1_DAT_0_POS)
#define GPX1_DAT_0_CLR (~GPX1_DAT_0_MSK)
/* Bit operation for GPX2_DAT */
#define GPX2_DAT_7_POS (7U)
#define GPX2_DAT_7_MSK (0x01U << GPX2_DAT_7_POS)
#define GPX2_DAT_7_CLR (~GPX2_DAT_7_MSK)
#endif
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/device.h>
#include <linux/atomic.h>
#include "FS4412_LED_drv.h"
#define DEV_NAME ("FS4412_LED")
#define LED_BASEMINOR 0
#define LED_COUNT 1
#define LOCK 0
#define ULOCK 1
#define MAX_NR 2
#define LED_MAGIC 'L'
#define LED_STATE _IOR(LED_MAGIC, 0, uint8_t)
#define LED_SWITCH _IOW(LED_MAGIC, 1, uint8_t)
#define LED_ROTATE _IOW(LED_MAGIC, MAX_NR, size_t)
MODULE_AUTHOR("Xiao Maolv");
MODULE_DESCRIPTION("LED drv for Ex3");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("1.0");
struct FS4412_LED_struct
{
dev_t cd;
spinlock_t slock;
atomic_t count;
uint8_t dat[4];
uint8_t state[4];
size_t rt_cmd[2];
struct cdev Ldev;
struct task_struct *rt_thrd;
struct class *cls;
struct device *dev;
GPIO_TypeDef *reg[4];
};
struct FS4412_LED_reg_ops_struct
{
uint8_t GPIO_DAT_POS[4];
uint8_t GPIO_DAT_MSK[4];
uint8_t GPIO_DAT_CLR[4];
};
static int __init FS4412_LED_drv_init(void);
static void __exit FS4412_LED_drv_exit(void);
static int FS4412_LED_ioremap(void);
static void FS4412_LED_iounmap(void);
static int FS4412_LED_open(struct inode *inode, struct file *filp);
static int FS4412_LED_release(struct inode *inode, struct file *filp);
static long FS4412_LED_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
static void FS4412_LED_init(void);
static void FS4412_LED_deinit(void);
static void FS4412_LED_state(const uint8_t lock_flg);
static void FS4412_LED_switch(uint8_t pos);
static int FS4412_LED_rtctl(void);
static int FS4412_LED_rotate(void);
static struct FS4412_LED_struct FS4412_LED;
static struct FS4412_LED_reg_ops_struct FS4412_LED_reg_ops =
{
{GPF3_DAT_4_POS, GPF3_DAT_5_POS, GPX2_DAT_7_POS, GPX1_DAT_0_POS},
{GPF3_DAT_4_MSK, GPF3_DAT_5_MSK, GPX2_DAT_7_MSK, GPX1_DAT_0_MSK},
{GPF3_DAT_4_CLR, GPF3_DAT_5_CLR, GPX2_DAT_7_CLR, GPX1_DAT_0_CLR}
};
static struct file_operations fops =
{
.owner = THIS_MODULE,
.open = FS4412_LED_open,
.release = FS4412_LED_release,
.unlocked_ioctl = FS4412_LED_unlocked_ioctl,
};
static int __init FS4412_LED_drv_init(void)
{
int err;
/* allocate device numbers to LED */
err = alloc_chrdev_region(&FS4412_LED.cd, LED_BASEMINOR, LED_COUNT, DEV_NAME);
if (err < 0)
{
printk(KERN_ERR "fail to allocate LED device number\n");
return err;
}
/* initialize cdev structure of LED */
cdev_init(&FS4412_LED.Ldev, &fops);
FS4412_LED.Ldev.owner = THIS_MODULE;
/* add LED device to the system */
err = cdev_add(&FS4412_LED.Ldev, FS4412_LED.cd, LED_COUNT);
if (err < 0)
{
printk(KERN_ERR "fail to add LED to system\n");
goto cdev_add_err;
}
/* map GPIO */
err = FS4412_LED_ioremap();
if (err < 0)
{
printk(KERN_ERR "fail to remap LED\n");
goto ioremap_err;
}
/* create LED device */
FS4412_LED.cls = class_create(THIS_MODULE, DEV_NAME);
if (IS_ERR(FS4412_LED.cls))
{
printk(KERN_ERR "fail to create class");
return PTR_ERR(FS4412_LED.cls);
}
FS4412_LED.dev = device_create(FS4412_LED.cls, NULL, FS4412_LED.cd, NULL, DEV_NAME);
if (IS_ERR(FS4412_LED.dev))
{
printk(KERN_ERR "fail to create device");
return PTR_ERR(FS4412_LED.dev);
}
printk(KERN_NOTICE "insert LED drv\n");
return 0;
ioremap_err:
cdev_del(&FS4412_LED.Ldev);
cdev_add_err:
unregister_chrdev_region(FS4412_LED.cd, LED_COUNT);
return err;
}
static void __exit FS4412_LED_drv_exit(void)
{
/* remove LED device */
device_destroy(FS4412_LED.cls, FS4412_LED.cd);
class_destroy(FS4412_LED.cls);
/* unmap GPIO */
FS4412_LED_iounmap();
/* remove LED from the system */
cdev_del(&FS4412_LED.Ldev);
/* unregister device numbers of LED */
unregister_chrdev_region(FS4412_LED.cd, LED_COUNT);
printk(KERN_NOTICE "remove LED drv\n");
}
/**********************************************************************
* @Function: FS4412_LED_ioremap
* @Description: map physical address of GPIO register
* related to LED to virtual address space
* @Param[in]: None
* @Return: 0 if success, otherwise -EIO
**********************************************************************/
static int FS4412_LED_ioremap(void)
{
FS4412_LED.reg[0] = FS4412_LED.reg[1] = ioremap(GPF3_BASE, 8);
if (!FS4412_LED.reg[0])
return -EIO;
FS4412_LED.reg[2] = ioremap(GPX2_BASE, 8);
if (!FS4412_LED.reg[2])
return -EIO;
FS4412_LED.reg[3] = ioremap(GPX1_BASE, 8);
if (!FS4412_LED.reg[3])
return -EIO;
return 0;
}
/**********************************************************************
* @Function: FS4412_LED_iounmap
* @Description: unmap GPIO register related to LED
* @Param[in]: None
* @Return: None
**********************************************************************/
static void FS4412_LED_iounmap(void)
{
iounmap(FS4412_LED.reg[0]);
iounmap(FS4412_LED.reg[2]);
iounmap(FS4412_LED.reg[3]);
}
static int FS4412_LED_open(struct inode *inode, struct file *filp)
{
/* to be exclusive */
if (atomic_read(&FS4412_LED.count))
{
printk(KERN_ERR "LED busy\n");
return -EBUSY;
}
atomic_add(1, &FS4412_LED.count);
spin_lock_init(&FS4412_LED.slock);
FS4412_LED_init();
return 0;
}
static int FS4412_LED_release(struct inode *inode, struct file *filp)
{
if (FS4412_LED.rt_thrd)
{
kthread_stop(FS4412_LED.rt_thrd);
FS4412_LED.rt_thrd = NULL;
}
FS4412_LED_deinit();
if (!atomic_read(&FS4412_LED.count))
{
printk(KERN_ERR "device closed before");
return -ENODEV;
}
atomic_sub(1, &FS4412_LED.count);
return 0;
}
static long FS4412_LED_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case LED_STATE:
FS4412_LED_state(ULOCK);
if (copy_to_user((void *) arg, FS4412_LED.state,
sizeof(FS4412_LED.state)))
{
printk(KERN_ERR "fail to get LED state\n");
return -EINVAL;
}
break;
case LED_SWITCH:
if (!arg || arg > 4)
goto inval_err;
FS4412_LED_switch(arg);
break;
case LED_ROTATE:
if (copy_from_user(FS4412_LED.rt_cmd, (void *) arg,
sizeof(FS4412_LED.rt_cmd)))
{
printk(KERN_ERR "fail to pass arguments\n");
return -EINVAL;
}
if (FS4412_LED.rt_cmd[0] > 4
|| FS4412_LED.rt_cmd[0] > 2 && FS4412_LED.rt_cmd[1] < 100)
goto inval_err;
return FS4412_LED_rtctl();
}
return 0;
inval_err:
printk(KERN_ERR "invalid ioctl args\n");
return -EINVAL;
}
/**********************************************************************
* @Function: FS4412_LED_init
* @Description: initialize GPIO controlling LEDs
* @Param[in]: None
* @Return: None
**********************************************************************/
static void FS4412_LED_init(void)
{
writel(
readl(&FS4412_LED.reg[0]->CON) & GPF3_CON_4_CLR & GPF3_CON_5_CLR
| GPF3_CON_4_OUT | GPF3_CON_5_OUT, &FS4412_LED.reg[0]->CON);
writel(readl(&FS4412_LED.reg[2]->CON) & GPX2_CON_7_CLR | GPX2_CON_7_OUT,
&FS4412_LED.reg[2]->CON);
writel(readl(&FS4412_LED.reg[3]->CON) & GPX1_CON_0_CLR | GPX1_CON_0_OUT,
&FS4412_LED.reg[3]->CON);
FS4412_LED_deinit();
}
/**********************************************************************
* @Function: FS4412_LED_deinit
* @Description: switch off LEDs
* @Param[in]: None
* @Return: None
**********************************************************************/
static void FS4412_LED_deinit(void)
{
FS4412_LED_state(LOCK);
writel(
FS4412_LED.dat[0] & FS4412_LED_reg_ops.GPIO_DAT_CLR[0]
& FS4412_LED_reg_ops.GPIO_DAT_CLR[1],
&FS4412_LED.reg[0]->DAT);
writel(FS4412_LED.dat[2] & FS4412_LED_reg_ops.GPIO_DAT_CLR[2],
&FS4412_LED.reg[2]->DAT);
writel(FS4412_LED.dat[3] & FS4412_LED_reg_ops.GPIO_DAT_CLR[3],
&FS4412_LED.reg[3]->DAT);
spin_unlock(&FS4412_LED.slock);
}
/**********************************************************************
* @Function: FS4412_LED_state
* @Description: read GPIO data registers to get LED state
* @Param[in]: (uint8_t)lock_flg: return with spin_lock if not 0
* @Return: None
**********************************************************************/
static void FS4412_LED_state(const uint8_t lock_flg)
{
uint8_t i;
spin_lock(&FS4412_LED.slock);
for (i = 0; i < 4; i++)
{
FS4412_LED.dat[i] = readl(&FS4412_LED.reg[i]->DAT);
FS4412_LED.state[i] = FS4412_LED.dat[i]
& FS4412_LED_reg_ops.GPIO_DAT_MSK[i];
FS4412_LED.state[i] >>= FS4412_LED_reg_ops.GPIO_DAT_POS[i];
}
if (lock_flg)
spin_unlock(&FS4412_LED.slock);
}
/**********************************************************************
* @Function: FS4412_LED_switch
* @Description: switch on/off LED
* @Param[in]: (uint8_t)pos: LED number
* @Return: None
**********************************************************************/
static void FS4412_LED_switch(uint8_t pos)
{
uint8_t dat;
spin_lock(&FS4412_LED.slock);
dat = readl(&FS4412_LED.reg[--pos]->DAT);
writel(
dat & FS4412_LED_reg_ops.GPIO_DAT_MSK[pos] ?
dat & FS4412_LED_reg_ops.GPIO_DAT_CLR[pos] :
dat | FS4412_LED_reg_ops.GPIO_DAT_MSK[pos],
&FS4412_LED.reg[pos]->DAT);
spin_unlock(&FS4412_LED.slock);
}
/**********************************************************************
* @Function: FS4412_LED_rtctl
* @Description: control the movement of LED
* @Param[in]: None
* @Return: 0 if success, otherwise -ENOMEM
**********************************************************************/
static int FS4412_LED_rtctl(void)
{
if (FS4412_LED.rt_cmd[0] > 2 && !FS4412_LED.rt_thrd)
{
FS4412_LED.rt_thrd = kthread_run((int (*)(void *)) FS4412_LED_rotate,
NULL, "FS4412_LED_rotate");
if (IS_ERR(FS4412_LED.rt_thrd))
printk(KERN_ERR "fail to create kthread\n");
return PTR_ERR(FS4412_LED.rt_thrd);
}
else if (FS4412_LED.rt_cmd[0] <= 2 && FS4412_LED.rt_thrd)
{
kthread_stop(FS4412_LED.rt_thrd);
FS4412_LED.rt_thrd = NULL;
}
if (FS4412_LED.rt_cmd[0] && FS4412_LED.rt_cmd[0] <= 2)
FS4412_LED_rotate();
return 0;
}
/**********************************************************************
* @Function: FS4412_LED_rotate
* @Description: move LED
* @Param[in]: None
* @Return: 0 if success
**********************************************************************/
static int FS4412_LED_rotate(void)
{
uint8_t i, dir, pos, wval, n;
do
{
dir = FS4412_LED.rt_cmd[0] == 1 || FS4412_LED.rt_cmd[0] == 3 ? 0 : 1;
n = dir ? 3 : 4;
FS4412_LED_state(LOCK);
for (i = 0; i < n; i++)
{
pos = (dir ? i + 1 : i - 1) & 3;
wval = FS4412_LED.state[i] ?
FS4412_LED.dat[pos] | FS4412_LED_reg_ops.GPIO_DAT_MSK[pos] :
FS4412_LED.dat[pos] & FS4412_LED_reg_ops.GPIO_DAT_CLR[pos];
if (!pos)
wval = FS4412_LED.state[++i] ?
wval | FS4412_LED_reg_ops.GPIO_DAT_MSK[1] :
wval & FS4412_LED_reg_ops.GPIO_DAT_CLR[1];
if (pos == 1)
wval = FS4412_LED.state[3] ?
wval | FS4412_LED_reg_ops.GPIO_DAT_MSK[0] :
wval & FS4412_LED_reg_ops.GPIO_DAT_CLR[0];
writel(wval, &FS4412_LED.reg[pos]->DAT);
}
spin_unlock(&FS4412_LED.slock);
if (FS4412_LED.rt_cmd[0] > 2)
mdelay(FS4412_LED.rt_cmd[1]);
} while (FS4412_LED.rt_cmd[0] > 2 && !kthread_should_stop());
return 0;
}
module_init(FS4412_LED_drv_init);
module_exit(FS4412_LED_drv_exit);
//------------------------------
QT移植
我的共享文件夹为桌面
ubuntu下在 /mnt/hgfs/Desktop
与LED相关的一些函数:
待实现功能:
QT下做四个图标,做几个按钮,点按钮一,点亮图标1,点按钮二,点亮图标2,旋转,led跟随
int fd_LED = open(LED, O_RDWR);
//开关
FS4412_LED_switch(int led,int status);//led=>led地址; status=>状态
//旋转
FS4412_LED_rotate(fd_LED, rt_args);
旋转:
目前已知状态为:[red,blue,yellow,green]
如果旋转的话需要记住相应的状态;
2021-04-14
./qtcreator
于该目录下
~/Qt5.4.2/Tools/QtCreator/bin
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "stdio.h"
#include "stdint.h"
#include "ex3_api.h"
char *stringCat(char *str1, char *str2);
int strlen(char *str);
void check();
void click(int number);
bool status[4] = {false};
char *common = "background-color:rgb(255,255,255)";
char *colors[]={
"red;",
"blue;",
"yellow;",
"green;"
};
bool flag = false;
int times = 5;
QPushButton *b_ss[4];
int fd_LED = -1;
int strlen(char *str) {
int i = 0;
while (str[i] != '\0') {
i++;
}
return i;
}
char *stringCat(char *str1, char *str2) {
int len1 = strlen(str1);
int len2 = strlen(str2);
int len = len1 + len2;
char *res = new char[len];
int j = 0;
int i = 0;
for (j = 0; j < len1; ++j) {
res[j] = str1[j];
}
for ( i = 0; i < len2; ++i) {
res[j + i] = str2[i];
}
res[i+j] = '\0';
return res;
// strcpy(res, str1);
// strcat(res, str2);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow){
ui->setupUi(this);
// b_ss = {ui->p_s_1,ui->p_s_2,ui->p_s_3,ui->p_s_4};
b_ss[0] = ui->p_c_1;
b_ss[1] = ui->p_c_2;
b_ss[2] = ui->p_c_3;
b_ss[3] = ui->p_c_4;
fd_LED = open(LED,O_RDWR);
printf("open device->%d\n",fd_LED);
ui->p_c_1->setStyleSheet(common);
ui->p_c_2->setStyleSheet(common);
ui->p_c_3->setStyleSheet(common);
ui->p_c_4->setStyleSheet(common);
}
//QPushButton *b_ss = {ui.};
//QPushButton *b_cs ={};
MainWindow::~MainWindow()
{
// free(status);
// free(*colors);
// free(*b_ss);
// free(common);
delete ui;
}
void MainWindow::on_exit_clicked(){
}
void MainWindow::click(int number){
FS4412_LED_switch(fd_LED,number+1);
if(!status[number]){
(b_ss[number])->setStyleSheet(stringCat("background-color:",colors[number]));
}else{
(b_ss[number])->setStyleSheet(common);
}
status[number]=!status[number];
};
void MainWindow::on_p_c_1_clicked(){
click(0);
}
void MainWindow::on_p_c_2_clicked(){
click(1);
}
void MainWindow::on_p_c_3_clicked(){
click(2);
}
void MainWindow::on_p_c_4_clicked(){
click(3);
}
void MainWindow::on_r_l_clicked(){
flag = false;
size_t rt_args[] = {0,500};
rt_args[0] = 1;
for(int i=0;i>=0;i++){
if(flag){break;}
delay(500);
rotate_left();
FS4412_LED_rotate(fd_LED,rt_args);
}
rt_args[0] = 0;
FS4412_LED_rotate(fd_LED,rt_args);
}
void MainWindow::on_r_r_clicked(){
flag = false;
size_t rt_args[] = {0,500};
rt_args[0] = 2;
for(int i=0;i>=0;i++){
if(flag){
break;
}
delay(500);
rotate_right();
FS4412_LED_rotate(fd_LED,rt_args);
}
rt_args[0] = 0;
FS4412_LED_rotate(fd_LED,rt_args);
}
void MainWindow::on_r_r_1_clicked(){
size_t rt_args[] = {0,500};
rt_args[0] = 2;
rotate_right();
FS4412_LED_rotate(fd_LED,rt_args);
rt_args[0] = 0;
FS4412_LED_rotate(fd_LED,rt_args);
}
void MainWindow::on_r_l_1_clicked(){
size_t rt_args[] = {0,500};
rt_args[0] = 1;
rotate_left();
FS4412_LED_rotate(fd_LED,rt_args);
rt_args[0] = 0;
FS4412_LED_rotate(fd_LED,rt_args);
}
void MainWindow::rotate_left(){
int len = sizeof(status)/sizeof(status[0]);
bool tmp = status[0];
for(int i = 0;i<len-1;i++){
status[i] = status[i+1];
}
status[len-1] = tmp;
char*tmp1 = colors[0];
for(int i = 0;i<len-1;i++){
colors[i] = colors[i+1];
}
colors[len-1] = tmp1;
for(int i=0;i<len;i++){
if(status[i]){
(*b_ss[i]).setStyleSheet(stringCat("background-color:",colors[i]));
}else{
(*b_ss[i]).setStyleSheet(common);
}
}
}
void MainWindow::rotate_right(){
int len = sizeof(status)/sizeof(status[0]);
bool tmp = status[len-1];
for(int i = len-1;i>0;i--){
status[i] = status[i-1];
}
status[0] = tmp;
char*tmp1 = colors[len-1];
for(int i = len-1;i>0;i--){
colors[i] = colors[i-1];
}
colors[0] = tmp1;
for(int i=0;i<len;i++){
if(status[i]){
(*b_ss[i]).setStyleSheet(stringCat("background-color:",colors[i]));
}else{
(*b_ss[i]).setStyleSheet(common);
}
}
}
void MainWindow::delay(int n){
QEventLoop loop;
QTimer::singleShot(n,&loop,SLOT(quit()));
loop.exec();
}
void MainWindow::on_pushButton_clicked()
{
QApplication* app;
app->exit(0);
}
void MainWindow::on_r_stop_clicked()
{
flag = !flag;
}
//对应界面文件
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>536</width>
<height>354</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QPushButton" name="p_c_1">
<property name="geometry">
<rect>
<x>40</x>
<y>30</y>
<width>51</width>
<height>51</height>
</rect>
</property>
<property name="text">
<string>l1</string>
</property>
</widget>
<widget class="QPushButton" name="p_c_2">
<property name="geometry">
<rect>
<x>120</x>
<y>30</y>
<width>51</width>
<height>51</height>
</rect>
</property>
<property name="text">
<string>l2</string>
</property>
</widget>
<widget class="QPushButton" name="p_c_3">
<property name="geometry">
<rect>
<x>40</x>
<y>100</y>
<width>51</width>
<height>51</height>
</rect>
</property>
<property name="text">
<string>l3</string>
</property>
</widget>
<widget class="QPushButton" name="p_c_4">
<property name="geometry">
<rect>
<x>120</x>
<y>100</y>
<width>51</width>
<height>51</height>
</rect>
</property>
<property name="text">
<string>l4</string>
</property>
</widget>
<widget class="QPushButton" name="r_l">
<property name="geometry">
<rect>
<x>240</x>
<y>200</y>
<width>81</width>
<height>51</height>
</rect>
</property>
<property name="text">
<string><--</string>
</property>
</widget>
<widget class="QPushButton" name="r_r">
<property name="geometry">
<rect>
<x>440</x>
<y>200</y>
<width>81</width>
<height>51</height>
</rect>
</property>
<property name="text">
<string>--></string>
</property>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>470</x>
<y>0</y>
<width>61</width>
<height>61</height>
</rect>
</property>
<property name="text">
<string>x</string>
</property>
</widget>
<widget class="QPushButton" name="r_l_1">
<property name="geometry">
<rect>
<x>330</x>
<y>200</y>
<width>51</width>
<height>51</height>
</rect>
</property>
<property name="text">
<string><-</string>
</property>
</widget>
<widget class="QPushButton" name="r_r_1">
<property name="geometry">
<rect>
<x>380</x>
<y>200</y>
<width>51</width>
<height>51</height>
</rect>
</property>
<property name="text">
<string>-></string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>536</width>
<height>28</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QToolBar" name="toolBar_2">
<property name="windowTitle">
<string>toolBar_2</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QToolBar" name="toolBar_3">
<property name="windowTitle">
<string>toolBar_3</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
ex3_api.h
#ifndef _EX3_API_H
#define _EX3_API_H
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <pthread.h>
#include <signal.h>
/* path of devices */
#define LED ("/dev/FS4412_LED")
#define SEGMENT_DISPLAY ("/dev/FS4412_segdis")
#define LED_MAGIC 'L'
#define LED_STATE _IOR(LED_MAGIC, 0, uint8_t)
#define LED_SWITCH _IOW(LED_MAGIC, 1, uint8_t)
#define LED_ROTATE _IOW(LED_MAGIC, 2, size_t)
/**********************************************************************
* @Function: FS4412_LED_state
* @Description: get LED state
* @Param[in]: (int)fd:
* file descriptor of LED device,
* (uint8_t)led_sts[4]:
* led_sts[n] will be set 1 if led n is on,
* otherwise led_sts[n] will be set 0
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_LED_state(fd, led_sts) ioctl(fd, LED_STATE, led_sts)
/**********************************************************************
* @Function: FS4412_LED_switch
* @Description: switch on/off LED
* @Param[in]: (int)fd:
* file descriptor of LED device,
* (uint_8)led:
* LED number
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_LED_switch(fd, led) ioctl(fd, LED_SWITCH, led)
/**********************************************************************
* @Function: FS4412_LED_rotate
* @Description: move LED
* @Param[in]: (int)fd:
* file descriptor of LED device,
* (size_t)rt_args[2]:
* rt_args[0]: 0: stop rotating
* 1: move anticlockwise
* 2: move clockwise
* 3: rotate anticlockwise
* 4: rotate clockwise
* rt_args[1]: rotation delay (ms)
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_LED_rotate(fd, rt_args) ioctl(fd, LED_ROTATE, rt_args)
/*************************** NOTICE ***********************************
* there should be an interval of more than 2 ms
* between segment display control functions calls
*********************************************************************/
/**********************************************************************
* @Function: FS4412_segdis_clr
* @Description: clear segment displays
* @Param[in]: (int)fd:
* file descriptor of segment displays device,
* (uint8_t)cmd[2]:
* cmd[0]: must be 0
* cmd[1]: digit postion(1-8), if 0 clear all
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_segdis_clr(fd, cmd) write(fd, cmd, 2)
/**********************************************************************
* @Function: FS4412_segdis_w_dig
* @Description: display 1 digit
* @Param[in]: (int)fd_LED:
* file descriptor of segment displays device,
* (uint8_t)dig[2]:
* dig[0]: digit position(1-8)
* dig[1]: (char)digit to be displayed
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_segdis_w_dig(fd, dig) write(fd, dig, 2)
/**********************************************************************
* @Function: FS4412_segdis_w_num
* @Description: display 8 number
* @Param[in]: (int)fd:
* file descriptor of segment displays device,
* (uint8_t)num[9]:
* num[0]: must be 9
* num[1-8]: (char)numbers to be displayed
* @Return: other than -1 upon successful completion
**********************************************************************/
#define FS4412_segdis_w_num(fd, num) write(fd, num, 9)
#endif
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "QTimer"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_p_c_2_clicked();
void on_p_c_1_clicked();
void on_p_c_3_clicked();
void on_p_c_4_clicked();
void click(int );
void on_r_l_clicked();
void on_r_l_1_clicked();
void on_r_r_clicked();
void on_r_r_1_clicked();
void on_exit_clicked();
void rotate_left();
void rotate_right();
void delay(int);
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
2021-0-4-24
嵌入式小作业-网络聊天室
hw.pro中引入:
QT+=sql
QT+=network
QString s = ui->text_input->toPlainText();
printf("%s",s.toStdString().data());
#-------------------------------------------------
#
# Project created by QtCreator 2021-04-24T10:08:07
#
#-------------------------------------------------
QT += core gui
QT+=sql
QT+=network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = server
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.ui
ERROR: Removing 'hello': Device or resource busy
原因:编译软件时的gcc版本和系统内核的
hello1.c
```c
#include "linux/init.h"
#include "linux/module.h"
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void){
printk("hello world->by liyuan\n");
return 0;
}
static void hello_exit(void){
printk("goodbye -> by liyuan!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
else
obj-m:=hello1.o
endif
make CC=gcc46
sudo insmod hello1
sudo rmmod hello1
ll /sys/module/hello1
modinfo hello1.ko
cat /var/log/kern.log
cat /var/log/syslog
dmesg
while true
do
cat /proc/kmsg
sleep 1
done
另开一个terminal
sudo rmmod hello1
sudo insmod hello1
记得查看 globalmem.c中定义的主设备号
//globalmem.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#define GLOBALMEM_SIZE 0x1000
#define MEM_CLEAR 0x1
#define GLOBALMEM_MAJOR 230
static int globalmem_major = GLOBALMEM_MAJOR;
module_param(globalmem_major, int, S_IRUGO);
struct globalmem_dev {
struct cdev cdev;
unsigned char mem[GLOBALMEM_SIZE];
};
struct globalmem_dev *globalmem_devp;
static int globalmem_open(struct inode *inode, struct file *filp)
{
filp->private_data = globalmem_devp;
return 0;
}
static int globalmem_release(struct inode *inode, struct file *filp)
{
return 0;
}
static long globalmem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct globalmem_dev *dev = filp->private_data;
switch (cmd) {
case MEM_CLEAR:
memset(dev->mem, 0, GLOBALMEM_SIZE);
printk(KERN_INFO "globalmem is set to zero\n");
break;
default:
return -EINVAL;
}
return 0;
}
static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct globalmem_dev *dev = filp->private_data;
if (p > GLOBALMEM_SIZE)
return 0;
if (count > GLOBALMEM_SIZE - p)
count = GLOBALMEM_SIZE - p;
if (copy_to_user(buf, dev->mem + p, count)) {
ret = -EFAULT;
} else {
*ppos += count;
ret = count;
printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p);
}
return ret;
}
static ssize_t globalmem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct globalmem_dev *dev = filp->private_data;
if (p > GLOBALMEM_SIZE)
return 0;
if (count > GLOBALMEM_SIZE - p)
count = GLOBALMEM_SIZE - p;
if (copy_from_user(dev->mem + p, buf, count)) {
return -EFAULT;
} else {
*ppos += count;
ret = count;
printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p);
}
return ret;
}
static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
{
loff_t ret = 0;
switch (orig) {
case 0:
if (offset < 0) {
ret = -EINVAL;
break;
}
if ((unsigned int)offset > GLOBALMEM_SIZE) {
ret = -EINVAL;
break;
}
filp->f_pos = (unsigned int)offset;
ret = filp->f_pos;
break;
case 1:
if ((filp->f_pos + offset) > GLOBALMEM_SIZE) {
ret = -EINVAL;
break;
}
if ((filp->f_pos + offset) < 0) {
ret = -EINVAL;
break;
}
filp->f_pos += offset;
ret = filp->f_pos;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static const struct file_operations globalmem_fops = {
.owner = THIS_MODULE,
.llseek = globalmem_llseek,
.read = globalmem_read,
.write = globalmem_write,
.unlocked_ioctl = globalmem_ioctl,
.open = globalmem_open,
.release = globalmem_release,
};
static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
{
int err, devno = MKDEV(globalmem_major, index);
cdev_init(&dev->cdev, &globalmem_fops);
dev->cdev.owner = THIS_MODULE;
err = cdev_add(&dev->cdev, devno, 1);
if (err) {
printk(KERN_NOTICE "Error %d adding globalmem %d", err, index);
}
}
static int __init globalmem_init(void)
{
int ret;
dev_t devno = MKDEV(globalmem_major, 0);
if (globalmem_major) {
ret = register_chrdev_region(devno, 1, "globalmem");
} else {
ret = alloc_chrdev_region(&devno, 0, 1, "globalmem");
globalmem_major = MAJOR(devno);
}
if (ret < 0)
return ret;
globalmem_devp = kzalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
if (!globalmem_devp) {
ret = -ENOMEM;
goto fail_malloc;
}
globalmem_setup_cdev(globalmem_devp, 0);
return 0;
fail_malloc:
unregister_chrdev_region(devno, 1);
return ret;
}
static void __exit globalmem_exit(void)
{
cdev_del(&globalmem_devp->cdev);
kfree(globalmem_devp);
unregister_chrdev_region(MKDEV(globalmem_major, 0), 1);
}
module_init(globalmem_init);
module_exit(globalmem_exit);
MODULE_AUTHOR("HLY");
MODULE_LICENSE("GPL");
//Makefile
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
else
obj-m:=globalmem.o
endif
make CC=gcc46
insmod globalmem.ko
rmmod globalmem
//该 230 需要查看globalmeme.c中设置的major version
mknod /dev/globalmem c 230 0
echo “liyuan” > /dev/globalmem2
cat /dev/globalmem2
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#define LENGTH 100
int main(int argc, char *argv[])
{
int fd,len;
char str[LENGTH];
fd = open("/dev/globalmem", O_RDWR);
if (fd) {
write(fd, "Hello World", strlen("Hello World"));
close(fd);
printf ("okokokokok\n");
}
fd = open("/dev/globalmem", O_RDWR);
len = read(fd, str, LENGTH);
str[len] = '\0';
printf("str:%s\n",str);
close(fd);
return 0;
}
./test
计算器
```c
//mainwidnow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "stack.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_number_0_clicked();
void on_number_1_clicked();
void on_number_2_clicked();
void on_number_3_clicked();
void on_number_4_clicked();
void on_number_5_clicked();
void on_number_6_clicked();
void on_number_7_clicked();
void on_number_8_clicked();
void on_number_9_clicked();
void on_char_left_bracket_clicked();
void on_char_right_bracket_clicked();
void on_operand_remain_clicked();
void on_char_clear_clicked();
void on_char_cal_clicked();
void on_operand_div_clicked();
void on_operand_mul_clicked();
void on_operand_sub_clicked();
void on_operand_add_clicked();
void calConcat(QString str);
// bool isDight(QCharRef c);
void on_char_dot_clicked();
std::string convert(std::string str);
int priority(char c);
int calculate(std::string str) ;
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
//node.h
#ifndef NODE
#define NODE
class Node {
public:
Node *next;
int data;
explicit Node(int i);
};
#endif // NODE
//stack.h
#ifndef STACK
#define STACK
#include "node.h"
class Stack {
public:
Node *root;
int size;
public:
void push(int data);
int pop();
int top();
bool isEmpty();
Stack();
};
#endif // STACK
//main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QString"
#include "vector"
#include"stdio.h"
#include "iostream"
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//ui->input->setLayoutDirection(Qt::LeftToRight);
ui->input->setReadOnly(true);
//ui->input->setStyleSheet("text-align:right;");
}
MainWindow::~MainWindow()
{
delete ui;
}
QString input="";
int MainWindow::priority(char c) {
switch (c) {
case '(':
return -1;
case ')':
return -1;
case '+':
return 0;
case '-':
return 0;
case '*':
return 1;
case '/':
return 1;
default:
return -1;
}
}
void MainWindow::on_number_0_clicked()
{
calConcat("0");
}
void MainWindow::on_number_1_clicked()
{
calConcat("1");
}
void MainWindow::on_number_2_clicked()
{
calConcat("2");
}
void MainWindow::on_number_3_clicked()
{
calConcat("3");
}
void MainWindow::on_number_4_clicked()
{
calConcat("4");
}
void MainWindow::on_number_5_clicked()
{
calConcat("5");
}
void MainWindow::on_number_6_clicked()
{
calConcat("6");
}
void MainWindow::on_number_7_clicked()
{
calConcat("7");
}
void MainWindow::on_number_8_clicked()
{
calConcat("8");
}
void MainWindow::on_number_9_clicked()
{
calConcat("9");
}
void MainWindow::on_char_left_bracket_clicked()
{
calConcat("(");
}
void MainWindow::on_char_right_bracket_clicked()
{
calConcat(")");
}
void MainWindow::on_operand_remain_clicked()
{
calConcat("%");
}
void MainWindow::on_char_clear_clicked()
{
ui->input->clear();
input.clear();
}
void MainWindow::on_operand_div_clicked()
{
calConcat("/");
}
void MainWindow::on_operand_mul_clicked()
{
calConcat("*");
}
void MainWindow::on_operand_sub_clicked()
{
calConcat("-");
}
void MainWindow::on_operand_add_clicked()
{
calConcat("+");
}
void MainWindow::on_char_dot_clicked()
{
calConcat(".");
}
void MainWindow::on_char_cal_clicked(){
int res = calculate(convert(input.toStdString()));
ui->input->clear();
QString tmp = input+"\n"+QString::number(res);
input.clear();
ui->input->clear();
ui->input->insertPlainText(tmp);
}
void MainWindow::calConcat(QString str){
input+=str;
ui->input->setText(input);
}
int MainWindow::calculate(string str) {
//cout<<"calculate"<<endl;
vector<string> stack;
vector<string> res;
for (int i = 0, start = 0; i < str.length(); ++i) {
char c = str.at(i);
if (c == ' ') {
// cout<<1;
string s = str.substr(start, i - start);
start = i + 1;
stack.push_back(s);
}
}
// cout<<1;
// cout<<stack.at(0);
// cout<<stack.size();
for (int i = 0; i < stack.size(); ++i) {
// cout<<i<<endl;
string s = stack.at(i);
if (s == "+" || s == "-" || s == "*" || s == "/") {
float num1 = atof(res.at(res.size() - 1).c_str());
res.pop_back();
float num2 = atof(res.at(res.size() - 1).c_str());
res.pop_back();
switch (s.at(0)) {
case '+':
res.push_back(QString("%1").arg(num1 + num2).toStdString());
break;
case '-':
res.push_back(QString("%1").arg(num2 - num1).toStdString());
break;
case '*':
res.push_back(QString("%1").arg(num1 * num2).toStdString());
break;
case '/':
res.push_back(QString("%1").arg(num2 / num1).toStdString());
break;
}
} else {
res.push_back(stack.at(i));
}
}
stack.clear();
return atof(res.at(res.size() - 1).c_str());
}
string MainWindow::convert(std::string str) {
Stack *stack = new Stack();
string res = "";
char tmp = str.at(0);
if(tmp=='-'){
str = "0"+str;
}
cout<<str<<endl;
for (int i = 0; i < str.length(); ++i) {
char c = str.at(i);
if (isdigit(c)) {
string tmp = "";
//tmp += c;
do {
tmp += c;
i++;
} while (i < str.length() && isdigit(c = str.at(i)));
i--;
res += tmp;
res += " ";
continue;
}
if (c == '(') {
stack->push('(');
} else if (c == ')') {
while (!stack->isEmpty() && stack->top() != '(') {
// cout << (char) stack->pop();
res += (char) stack->pop();
res += " ";
}
stack->pop();
} else {
if (stack->isEmpty()) {
stack->push(c);
continue;
}
bool mark = false;
while (!stack->isEmpty() && (priority(stack->top()) >=priority(c))) {
res += (char) stack->pop();
res += " ";
mark = true;
}
// if (!mark) {
stack->push(c);
// }
}
}
// cout<<res<<endl;
while (!stack->isEmpty()) {
//cout<<res<<endl;
res += (char) stack->pop();
res += " ";
}
// cout<<"liyuan"<<endl;
return res;
}
//node.cpp
#include "node.h"
//
// Created by Administrator on 2021/5/12.
//
Node::Node(int data) {
this->data = data;
}
//stack.cpp
//
// Created by Administrator on 2021/5/12.
//
#include "stack.h"
void Stack::push(int data) {
Node *n = new Node(data);
n->next = this->root->next;
this->root->next = n;
this->size++;
}
int Stack::pop() {
if (isEmpty()) {
return -1;
}
this->size--;
Node *e = this->root->next;
this->root->next = this->root->next->next;
return e->data;
}
int Stack::top() {
if (isEmpty()) {
return -1;
}
return this->root->next->data;
}
bool Stack::isEmpty() {
return this->size == 0;
}
Stack::Stack() {
this->root = new Node(-1);
this->size=0;
}
//网络聊天室
//server
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QNetworkInterface>
#include <QMessageBox>
#include "QDateTime"
QTcpServer tcpServer;
QList<QTcpSocket*> tcpClients;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
// tcpServer = new QTcpServer(this);
ui->setupUi(this);
//获取网卡的ip地址,包括本机ip地址
const QHostAddress ip = QNetworkInterface().allAddresses().at(1);
QList<QHostAddress> localAllAddresses = QNetworkInterface().allAddresses();
for(int i=0;i<localAllAddresses.count();i++){
ui->ip->appendPlainText(localAllAddresses.at(i).toString());
}
// QString port = ui->port->text();
//绑定newConnectionSlot信号函数和newConnection(C语言自带的方法)方法,newConnection connect(&tcpServer,SIGNAL(newConnection()),this,SLOT(newConnectionSlot()));
tcpServer.listen(QHostAddress::Any,8888);
ui->port->setText("8888");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::newConnectionSlot(){
QTcpSocket *socket = tcpServer.nextPendingConnection();
//add this socket to list
tcpClients.append(socket);
QString str = socket->peerAddress().toString()+":"+socket->peerPort()+"join in.";
ui->users->appendPlainText(str);
connect(socket,SIGNAL(readyRead()),this,SLOT(readDataSlot()));
connect(socket,SIGNAL(disconnected()),this,SLOT(disconnectedSlot()));
}
void MainWindow::readDataSlot(){
for(int i=0;i<tcpClients.count();i++){
if(tcpClients.at(i)->bytesAvailable()){
QByteArray info = tcpClients.at(i)->readAll();
QString msg =tcpClients.at(i)->peerAddress().toString()+":"+info.toStdString().data();
QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
msg = time+" "+msg;
ui->users->appendPlainText(msg.toStdString().data());
sendMessage(msg);
}
}
}
void MainWindow::sendMessage(QString message){
for(int i=0;i<tcpClients.count();i++){
tcpClients.at(i)->write(message.toStdString().data());
}
}
void MainWindow::disconnectedSlot(){
}
//client
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "stdio.h"
#include "QTcpSocket"
QTcpSocket tcpSocket;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//绑定connetced信号和onConnected函数
connect(&tcpSocket,SIGNAL(connected()),this,SLOT(onConnected()));
//绑定disconnected信号和onDisconnected函数
connect(&tcpSocket,SIGNAL(disconnected()),this,SLOT(onDisconnected()));
//绑定readyRead信号和onDataReceived方法
connect(&tcpSocket,SIGNAL(readyRead()),this,SLOT(onDataReceived()));
ui->server_address->setText("192.168.31.192:8888");
//tcpSocket.connectToHost("127.0.0.1",8888);s
}
void MainWindow::onConnected(){
}
void MainWindow::onDisconnected(){}
//当接受到来自服务端的数据流
void MainWindow::onDataReceived(){
if(tcpSocket.bytesAvailable()){
QByteArray data;
data.resize(tcpSocket.bytesAvailable());
tcpSocket.read(data.data(),data.size());
// data.
// printf("test:%s",data.toPercentEncoding().data();
QString str = QString(data);
ui->text_receive->append(str);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
//send message to server
//发送数据流给服务端
void MainWindow::on_btn_send_clicked()
{
QString s = ui->text_input->toPlainText();
if(s!=""){
tcpSocket.write(s.toLocal8Bit());
ui->text_input->clear();
}
}
//refresh the text receiver
//
//void MainWindow::appendData(){
// QByteArray localReadAll = tcpSocket.readAll();
// if(localReadAll.isEmpty()){
// ui->text_receive->append(localReadAll);
// }
//}
//exit断开tcp连接
void MainWindow::on_pushButton_clicked()
{
tcpSocket.disconnectFromHost();
QApplication*app;
app->exit(0);
}
//0
void MainWindow::on_btn_0_clicked()
{
ui->text_input->insertPlainText("0");
}
//1
void MainWindow::on_btn_1_clicked()
{
ui->text_input->insertPlainText("1");
}
//建立tcp连接
void MainWindow::on_connect_clicked()
{
QString address = ui->server_address->text();
QStringList ss = address.split(":");
tcpSocket.connectToHost(ss.at(0),ss.at(1).toInt());
}
嵌入式系统大作业 - 矩阵键盘驱动设计(input系统)
linux中,input设备使用input_dev结构体描述,设备驱动需按如下步骤实现:
(1)在驱动模块加载函数中设置input设备支持input子系统哪些事件;
(2)将input设备注册到input子系统
(3)利用中断在input设备发生输入操作时,提交所发生的时间以及对应的键值/坐标
1.设备驱动层
将底层的硬件输入转化为统一事件形式,向输入核心层汇报
2.核心层
为驱动层提供设备注册与操作接口,通知事件处理层对事件进行处理;
3.事件处理层
与用户空间交互。
4.用户空间
C语言实现的应用程序。
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/irq.h>
#include <asm/io.h>
#include<linux/interrupt.h>
#include <linux/uaccess.h>
#include<mach/irqs.h>
//arch/arm/mach-s5pv210/include/mach/irqs.h
static struct input_dev *button_dev;
#define GPK1CON 0x11000C20
#define BUTTON_IRQ IRQ_EINT(10)
static int key_major = 240;
static int key_minor = 0;
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("liyuan");
static struct input_dev *button_dev;
//struct key_device{
// int keyval;
// struct cdev cdev;
// struct semaphore sem;
// wait_queue_head_t rq;
//}key_device;
//static int fs4412_key_open(struct inode *inode, struct file *filp){
// // container_of()通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址
// struct key_device *dev = container_of(inode->i_cdev, struct key_device, cdev);
// // private_data用来保存自定义设备结构体的地址
// filp->private_data = dev;
// printk("fs4412_key is opened\n");
// return 0;
//}
//
//static int fs4412_key_release(struct inode *inode, struct file *filp){
// printk("fs4412_key is closed\n");
// return 0;
//}
//
//static int fs4412_key_read(struct file *filp, char __user *buf, size_t size, loff_t *off){
// struct key_device *dev = filp->private_data;
// // semaphore 信号量 同时只能有一个任务可以访问信号量保护的共享资源。-> 同步/互斥
// // sem初始值为1, 如果当前资源计数大于0,那么信号量处于触发状态;
// // 如果当前资源计数等于0,那么信号量处于未触发状态;那么系统会让调用线程进入等待状态。
// down(&dev->sem);
// while (dev->keyval == 0) // 根据硬件图可知,keyval=0表示没有按键被按下
// {
// // 该函数释放信号量sem,即把sem的值加1,如果sem的值为非正数,表明有任务等待该信号量,因此唤醒这些等待者。
// up(&dev->sem);
// /* 如果设置了O_NONBLOCK标志,read和write的行为是不同的,如果进程没有数据就绪时调用了read,
// 或者在缓冲区没有空间时调用了write,系统只是简单的返回 -EAGAIN,而不会阻塞进程. */
// if (filp->f_flags & O_NONBLOCK) // 判断f_flags是否是O_NONBLOCK非阻塞标志
// return -EAGAIN; // 返回-EAGAIN再次执行
// if (wait_event_interruptible(dev->rq, dev->keyval != 0)) // https://blog.youkuaiyun.com/djinglan/article/details/8150444
// return -ERESTARTSYS;
// down(&dev->sem);
// }
// // 如果数据拷贝成功,则返回零;否则,返回没有拷贝成功的数据字节数。
// if (copy_to_user(buf, &dev->keyval, sizeof(int))){
// up(&dev->sem);
// return -EFAULT;
// }
// dev->keyval = 0;
// up(&dev->sem);
// return sizeof(int);
//}
//
//static struct file_operations fs4412_key_ops = {
// .owner = THIS_MODULE,
// .open = fs4412_key_open,
// .release = fs4412_key_release,
// .read = fs4412_key_read,
//};
unsigned int key_value[65] ={
0,KEY_D, KEY_NUMERIC_POUND, KEY_0, KEY_NUMERIC_STAR, 5, 6, 7, 8,
KEY_C, KEY_9, KEY_8, KEY_7, 13, 14, 15, 16,
KEY_B, KEY_6, KEY_5, KEY_4, 21, 22, 23, 24,
KEY_A, KEY_3, KEY_2, KEY_1, 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,
};
static irqreturn_t button_interrupt(int irq, void *dummy){
//向上层汇报按键事件,汇报值,是否可读取到值
// input_report_key(button_dev, key_value[8], inb(BUTTON_PORT) & 1);
//TODO 此处模拟
//上报下降沿
input_report_key(button_dev,key_value[8],1);
printk("I-R-Q: ");
//发送同步标识
input_sync(button_dev);
//中断正常执行,操作系统管理所有软硬件资源
return IRQ_HANDLED;
}
static int __init button_init(void){
int error;
/*申请中断(共享中断)
irq 中断号
handler 中断处理函数
flags 标志位,中断于上升沿,下降沿触发.
name 中断名字
dev 传递参数,一般为NULL
*/
if (request_irq(BUTTON_IRQ, button_interrupt, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "button", NULL)) {
printk(KERN_ERR "button.c: Can't allocate irq %d\n", BUTTON_IRQ);
return -EBUSY;
}
button_dev = input_allocate_device();
if (!button_dev) {
printk(KERN_ERR "button.c: Not enough memory\n");
error = -ENOMEM;
goto err_free_irq;
}
//一般使用 set_bit(EV_KEY,input->evbit);
//告诉输入系统其可生成或接受什么事件
button_dev->evbit[0] = BIT_MASK(EV_KEY);
//button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
int i=0;
for(i=1; i <= 64; i++){
button_dev->keybit[BIT_WORD(key_value[i])] |= BIT_MASK(key_value[i]);
}
//注册
error = input_register_device(button_dev);
if (error) {
printk(KERN_ERR "button.c: Failed to register device\n");
goto err_free_dev;
}
return 0;
err_free_dev:
input_free_device(button_dev);
err_free_irq:
free_irq(BUTTON_IRQ, button_interrupt);
return error;
}
static void __exit button_exit(void){
input_unregister_device(button_dev);
//释放中断
free_irq(BUTTON_IRQ, button_interrupt);
}
module_init(button_init);
module_exit(button_exit);
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <plat/gpio-cfg.h>
#define ZLG7290_NAME "zlg7290"
/*zlg7290 I2C device definition*/
static dev_t zlg7290_devt;
static int zlg7290_minor = 0;
static struct class *zlg7290_class;
static DECLARE_WAIT_QUEUE_HEAD(keyRead_waitq);//INT button half
#define ADDR_ZLG7290 0x70 /* ZLG7290 address 0x70*/
/*zlg7290 device struct*/
struct zlg7290
{
struct cdev cdev;
struct device *class_dev;
struct i2c_client *client;
struct work_struct work;
struct workqueue_struct *queue;
uint32_t irq;
};
struct zlg7290 *qj_zlg7290;
static volatile int key_press =0;
/*****************Character device File operations application interface part
* begin********/
static int zlg7290_hw_write(struct zlg7290 *ctr_zlg7290, int len, size_t *retlen, char *buf)
{
struct i2c_client *client = ctr_zlg7290->client;
unsigned char tbuf[2]; /*tbuf[0] is register address , tbuf[1] is the value to write in */
// unsigned short i;
tbuf[0] = buf[0];
tbuf[1] = buf[1];
if (i2c_master_send(client, tbuf, 2) != 2)
{
dev_err(&client->dev, "i2c write error/n");
return -EIO;
}
return 0;
}
static int zlg7290_hw_read(struct zlg7290 *ctr_zlg7290 , int len, size_t *retlen, char *buf)
{
struct i2c_client *client = ctr_zlg7290->client;
int ret;
struct i2c_msg msg[] =
{
{ client->addr, 0, len, buf }, /*the buf contains register address*/
{ client->addr, I2C_M_RD, len, buf },/*the buf contains register value*/
};
ret =i2c_transfer(client->adapter, msg, 2);
if (ret < 0)
{
printk("ret=%d,addr=%x\n",ret,client->addr);
dev_err(&client->dev, "i2c read error/n");
return -EIO;
}
*retlen = len;
return 0;
}
static irqreturn_t zlg7290_interrupt(int irq, void *dev_id) {
struct zlg7290 *ctr_zlg7290;
//int ret = 0;
// size_t retlen = 0;
// char *kbuf;
printk("%s(%d)\n", __FUNCTION__, __LINE__);
ctr_zlg7290 = (struct zlg7290 *)dev_id;
disable_irq_nosync(ctr_zlg7290->irq);
if (!work_pending(&ctr_zlg7290->work)) {
queue_work(ctr_zlg7290->queue, &ctr_zlg7290->work);
}
// key_press =1;
// wake_up_interruptible(&keyRead_waitq);
return IRQ_HANDLED;
}
static int zlg7290_open(struct inode *inode, struct file *file)
{
int err;
struct zlg7290 *ctr_zlg7290 = container_of(inode->i_cdev, struct zlg7290, cdev);
#if 0
s5p_register_gpio_interrupt(ctr_zlg7290->irq);
ctr_zlg7290->irq = gpio_to_irq(ctr_zlg7290->irq);
err = request_irq(ctr_zlg7290->irq, zlg7290_interrupt,
IRQ_TYPE_EDGE_FALLING /*IRQF_TRIGGER_FALLING*/, "zlg7290", ctr_zlg7290);
if (err < 0) {
//dev_err(&ctr_zlg7290jjkk->client->dev, "Request IRQ %d failed, %d\n", ctr_zlg7290->irq, err);
dev_err(&(ctr_zlg7290->client)->dev, "Request IRQ %d failed, %d\n", ctr_zlg7290->irq, err);
return err;
}
#endif
file->private_data = ctr_zlg7290;
printk("irq=%d\n",ctr_zlg7290->irq);
return 0;
}
static int zlg7290_release(struct inode *inode, struct file *file)
{
file->private_data = NULL;
free_irq(qj_zlg7290->irq,NULL);
return 0;
}
static ssize_t zlg7290_writereg(struct file *file, const char __user *buf,
size_t count, loff_t *fpos)
{
struct zlg7290 *ctr_zlg7290 = file->private_data;
char *kbuf;
size_t retlen = 0;
int ret = 0;
if (!count) return 0;
kbuf = kmalloc(count, GFP_KERNEL);
if (kbuf == NULL)
return -ENOMEM;
/*(Cuntianrui Warning)the *buf is buf[2]
* in user mode , buf[0] is register
* address and buf[1] is register value*/
if (copy_from_user(kbuf,buf,count))
{
kfree(kbuf);
return -EFAULT;
}
ret = zlg7290_hw_write(ctr_zlg7290, count, &retlen, kbuf);
if (ret)
{
kfree(kbuf);
return ret;
}
kfree(kbuf);
return retlen;
}
static ssize_t zlg7290_readreg(struct file *file, char __user *buf, size_t count, loff_t *fpos)
{
struct zlg7290 *ctr_zlg7290 = file->private_data;
size_t retlen = 0;
int ret = 0;
char *kbuf;
if (!count) return 0;
/*if key_press = 0 , sleep here*/
wait_event_interruptible(keyRead_waitq, key_press);
/*running to this line , key_press is 1*/
key_press = 0;
kbuf = kmalloc(count, GFP_KERNEL);
if (kbuf == NULL)
return -ENOMEM;
/*(Cuntianrui Warning)buf is in
* user mode,and need put
* register address in it before
* calling read function
* The function return
* register content in buf
* */
if (copy_from_user(kbuf, buf, 1))
return -EFAULT;
ret = zlg7290_hw_read(ctr_zlg7290, count, &retlen, kbuf);
if (ret) {
kfree(kbuf);
return ret;
}
if (copy_to_user(buf,kbuf,count))
{
kfree(kbuf);
return -EFAULT;
}
kfree(kbuf);
return retlen;
}
static struct file_operations zlg7290_fops =
{
.owner = THIS_MODULE,
.read = zlg7290_readreg,
.write = zlg7290_writereg,
.open = zlg7290_open,
.release = zlg7290_release,
};
static void zlg7290_irq_work(struct work_struct *work) {
struct zlg7290 *ctr_zlg7290 = container_of(work, struct zlg7290, work);
/************test key and led**********/
#if 1
size_t retlen = 0;
char *kbuf;
static char bfbuf[10];
struct i2c_client *client = ctr_zlg7290->client;
int ret,i,key;
kbuf = kmalloc(9, GFP_KERNEL);
kbuf[0] = 1;
struct i2c_msg msgr[] =
{
{ client->addr, 0, 1, kbuf }, /*the buf contains key value register address*/
{ client->addr, I2C_M_RD, 2, kbuf },/*the buf contains key register value and repeat count*/
};
struct i2c_msg msgw[] =
{
{ client->addr, 0, 9, kbuf }, /*the buf contains LED register begin address and LED0~7 value*/
};
ret = i2c_transfer(client->adapter, msgr, 2);
if (ret < 0)
{
printk("ret=%d,addr=%x\n",ret,client->addr);
dev_err(&client->dev, "i2c read error/n");
}
key = kbuf[0];
printk("key=%x,repeat count=%x\n",key,kbuf[1]);
kbuf[0] = 0x10;/*LED register begin address*/
/*
for(i = 1;i < 9;i++)
{
if(key == 0x1c)
{
kbuf[i] = 0x0c;//1
}
if(key == 0x1b)
{
kbuf[i] = 0xb6;//5
}
if(key == 0x1a)
{
kbuf[i] = 0xf6;//9
}
if(key == 0x19)
{
kbuf[i] = 0xa2;//d
}
if(key == 0x14)
{
kbuf[i] = 0xda;//2
}
if(key == 0x13)
{
kbuf[i] = 0xbe;//6
}
if(key == 0x12)
{
kbuf[i] = 0xef;//a
}
if(key == 0x11)
{
kbuf[i] = 0x9f;//e
}
if(key == 0xc)
{
kbuf[i] = 0x0f2;//3
}
if(key == 0xb)
{
kbuf[i] = 0xe0;//7
}
if(key == 0xa)
{
kbuf[i] = 0x1f;//b
}
if(key == 0x9)
{
kbuf[i] = 0x8f;//f
}
if(key == 0x4)
{
kbuf[i] = 0x67 ;//4
}
if(key == 0x3)
{
kbuf[i] = 0xff; //8
}
if(key == 0x2)
{
kbuf[i] = 0x9c; //c
}
if(key == 0x1)
{
kbuf[i] = 0xfd;//0
}
}
*/
for(i = 1;i < 8;i++)
{
kbuf[i+1] = kbuf[i];
}
if(key == 0x1c)
{
kbuf[1] = 0x0c;//1
}
if(key == 0x1b)
{
kbuf[1] = 0xb6;//5
}
if(key == 0x1a)
{
kbuf[1] = 0xf6;//9
}
if(key == 0x19)
{
kbuf[1] = 0x7a;//d
}
if(key == 0x14)
{
kbuf[1] = 0xda;//2
}
if(key == 0x13)
{
kbuf[1] = 0xbe;//6
}
if(key == 0x12)
{
kbuf[1] = 0xee;//A
}
if(key == 0x11)
{
kbuf[1] = 0x9e;//E
}
if(key == 0xc)
{
kbuf[1] = 0x0f2;//3
}
if(key == 0xb)
{
kbuf[1] = 0xe0;//7
}
if(key == 0xa)
{
kbuf[1] = 0x3e;//b
}
if(key == 0x9)
{
kbuf[1] = 0x8e;//f
}
if(key == 0x4)
{
kbuf[1] = 0x66 ;//4
}
if(key == 0x3)
{
kbuf[1] = 0xfe; //8
}
if(key == 0x2)
{
kbuf[1] = 0x9c; //c
}
if(key == 0x1)
{
kbuf[1] = 0xfc;//0
}
for(i = 1;i < 8;i++)
{
kbuf[i+1] = bfbuf[i];
bfbuf[i] = kbuf[i];
}
/
ret =i2c_transfer(client->adapter, msgw, 1);
if (ret < 0)
{
printk("ret=%d,addr=%x\n",ret,client->addr);
dev_err(&client->dev, "i2c read error/n");
}
kfree(kbuf);
printk("test end\n");
#endif
enable_irq(ctr_zlg7290->irq);
}
static int zlg7290_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
// struct zlg7290_i2c_platform_data *pdata;
// struct zlg7290 *ctr_zlg7290;
int ret = 0;
int err = -EINVAL;
if (!(qj_zlg7290 = kmalloc(sizeof(struct zlg7290), GFP_KERNEL)))
return -ENOMEM;
printk("zlg7290 probe\n");
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
return err;
}
qj_zlg7290->client = client;
qj_zlg7290->irq = client->irq;
i2c_set_clientdata(client, qj_zlg7290);
cdev_init(&qj_zlg7290->cdev, &zlg7290_fops);
qj_zlg7290->cdev.owner = THIS_MODULE;
ret = cdev_add(&qj_zlg7290->cdev, MKDEV(MAJOR(zlg7290_devt), zlg7290_minor), 1);
if (ret < 0) {
dev_err(&client->dev, "register char device failed/n");
// goto exit_detach;
return ret;
}
qj_zlg7290->class_dev = device_create(zlg7290_class, NULL,
MKDEV(MAJOR(zlg7290_devt),
zlg7290_minor),
NULL, "zlg7290%d",
zlg7290_minor);
if (IS_ERR(qj_zlg7290->class_dev)) {
dev_err(&client->dev, "can not create class device/n");
ret = PTR_ERR(qj_zlg7290->class_dev);
// goto exit_cdev_del;
return ret;
}
INIT_WORK(&qj_zlg7290->work, zlg7290_irq_work);
qj_zlg7290->queue = create_singlethread_workqueue("zlg7290-queue");
if (!qj_zlg7290->queue) {
err = -ESRCH;
// goto exit_create_singlethread;
return err;
}
dev_info(&client->dev, "device at /dev/zlg7290%d (%d:%d)/n",
zlg7290_minor, MAJOR(zlg7290_devt), zlg7290_minor);
s5p_register_gpio_interrupt(qj_zlg7290->irq);
qj_zlg7290->irq = gpio_to_irq(qj_zlg7290->irq);
err = request_irq(qj_zlg7290->irq, zlg7290_interrupt,
IRQ_TYPE_EDGE_FALLING /*IRQF_TRIGGER_FALLING*/, "zlg7290", qj_zlg7290);
if (err < 0) {
//dev_err(&ctr_zlg7290jjkk->client->dev, "Request IRQ %d failed, %d\n", ctr_zlg7290->irq, err);
dev_err(&(qj_zlg7290->client)->dev, "Request IRQ %d failed, %d\n", qj_zlg7290->irq, err);
return err;
}
// zlg7290_minor++;
//return 0;
/*
pdata = client->dev.platform_data;
if (!pdata) {
dev_err(&client->dev, "failed to get platform data!\n");
return err;
}
*/
// err = request_irq(client->irq, zlg7290_interrupt,
// disable_irq(client->irq);
// dev_info(&client->dev, "Firmware version 0x%02x\n", val);
// enable_irq(client->irq);
dev_info(&client->dev, "------zlg7290 initialized\n");
return 0;
}
static int __devexit zlg7290_remove(struct i2c_client *client) {
free_irq(client->irq, NULL);
i2c_set_clientdata(client, NULL);
return 0;
}
static const struct i2c_device_id zlg7290_id[] = {
{ZLG7290_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, zlg7290_id);
static struct i2c_driver zlg7290_driver= {
.probe = zlg7290_probe,
.remove = __devexit_p(zlg7290_remove),
.id_table = zlg7290_id,
.driver = {
.name = ZLG7290_NAME,
.owner = THIS_MODULE,
},
};
static int __init zlg7290_init(void)
{
int ret;
zlg7290_class = class_create(THIS_MODULE, "zlg7290");
if (IS_ERR(zlg7290_class))
return PTR_ERR(zlg7290_class);
ret = alloc_chrdev_region(&zlg7290_devt, 0, 5, "zlg7290");
if (ret < 0)
{
printk(KERN_ERR "failed to allocate char dev region/n");
class_destroy(zlg7290_class);
return ret;
}
return i2c_add_driver(&zlg7290_driver);
}
static void __exit zlg7290_exit(void)
{
class_destroy(zlg7290_class);
unregister_chrdev_region(zlg7290_devt, 5);
i2c_del_driver(&zlg7290_driver);
}
/*****************ZLG7290 I2C driver interface part
* END**************************/
MODULE_AUTHOR("farsight");
MODULE_DESCRIPTION("zlg7290 driver");
MODULE_LICENSE("GPL");
module_init(zlg7290_init);
module_exit(zlg7290_exit);