First commit of project

This commit is contained in:
tdVincentB 2019-03-19 15:41:17 +01:00
commit 4c3f0eca57
14 changed files with 2207 additions and 0 deletions

21
Makefile Normal file
View File

@ -0,0 +1,21 @@
TOOLS_CFLAGS := -Wstrict-prototypes -Wshadow -Wpointer-arith -Wcast-qual \
-Wcast-align -Wwrite-strings -Wnested-externs -Winline \
-W -Wundef -Wmissing-prototypes
#
# Programs
#
all: funkey_gpio_management
funkey_gpio_management: funkey_gpio_management.o gpio-utils.o uinput.o gpio_mapping.o read_conf_file.o keydefs.o driver_pcal6416a.o
$(CC) $(LDFLAGS) -o $@ $^
#
# Objects
#
%.o: %.c
$(CC) $(CFLAGS) $(TOOLS_CFLAGS) -c $< -o $@
clean:
rm *.o funkey_gpio_management

79
driver_pcal6416a.c Normal file
View File

@ -0,0 +1,79 @@
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/select.h>
#include <linux/input.h>
#include "read_conf_file.h"
#include <assert.h>
#include <linux/i2c-dev.h>
#include "driver_pcal6416a.h"
/****************************************************************
* Defines
****************************************************************/
#define DEBUG_PCAL6416A_PRINTF (0)
#if (DEBUG_PCAL6416A_PRINTF)
#define DEBUG_PRINTF(...) printf(__VA_ARGS__);
#else
#define DEBUG_PRINTF(...)
#endif
/****************************************************************
* Static variables
****************************************************************/
int fd_i2c_expander;
char i2c0_sysfs_filename[] = "/dev/i2c-0";
/****************************************************************
* Static functions
****************************************************************/
/****************************************************************
* Public functions
****************************************************************/
bool pcal6416a_init(void) {
if ((fd_i2c_expander = open(i2c0_sysfs_filename,O_RDWR)) < 0) {
printf("Failed to open the I2C bus %s", i2c0_sysfs_filename);
// ERROR HANDLING; you can check errno to see what went wrong
return false;
}
if (ioctl(fd_i2c_expander,I2C_SLAVE,PCAL6416A_I2C_ADDR) < 0) {
printf("Failed to acquire bus access and/or talk to slave.\n");
// ERROR HANDLING; you can check errno to see what went wrong
return false;
}
uint16_t val_enable_pullups = 0xffff;
i2c_smbus_write_word_data ( fd_i2c_expander , PCAL6416A_EN_PULLUPDOWN , val_enable_pullups );
uint16_t val_enable_interrupts = 0x0000;
i2c_smbus_write_word_data ( fd_i2c_expander , PCAL6416A_INT_MASK , val_enable_interrupts );
return true;
}
bool pcal6416a_deinit(void) {
// Close I2C open interface
close(fd_i2c_expander);
return true;
}
uint16_t pcal6416a_read_mask_interrupts(void){
uint16_t val = i2c_smbus_read_word_data ( fd_i2c_expander , PCAL6416A_INT_STATUS );
DEBUG_PRINTF("READ PCAL6416A_INT_STATUS : 0x%04X\n",val);
return val;
}
uint16_t pcal6416a_read_mask_active_GPIOs(void){
uint16_t val = i2c_smbus_read_word_data ( fd_i2c_expander , PCAL6416A_INPUT );
val = 0xFFFF-val;
DEBUG_PRINTF("READ PCAL6416A_INPUT (active GPIOs) : 0x%04X\n",val);
return val;
}

39
driver_pcal6416a.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef _DRIVER_PCAL6416A_H_
#define _DRIVER_PCAL6416A_H_
/****************************************************************
* Includes
****************************************************************/
#include <stdbool.h>
/****************************************************************
* Defines
****************************************************************/
// Chip physical address
#define PCAL6416A_I2C_ADDR 0x20
// Chip registers adresses
#define PCAL6416A_INPUT 0x00 /* Input port [RO] */
#define PCAL6416A_DAT_OUT 0x02 /* GPIO DATA OUT [R/W] */
#define PCAL6416A_POLARITY 0x04 /* Polarity Inversion port [R/W] */
#define PCAL6416A_CONFIG 0x06 /* Configuration port [R/W] */
#define PCAL6416A_DRIVE0 0x40 /* Output drive strength Port0 [R/W] */
#define PCAL6416A_DRIVE1 0x42 /* Output drive strength Port1 [R/W] */
#define PCAL6416A_INPUT_LATCH 0x44 /* Port0 Input latch [R/W] */
#define PCAL6416A_EN_PULLUPDOWN 0x46 /* Port0 Pull-up/Pull-down enbl [R/W] */
#define PCAL6416A_SEL_PULLUPDOWN 0x48 /* Port0 Pull-up/Pull-down slct [R/W] */
#define PCAL6416A_INT_MASK 0x4A /* Interrupt mask [R/W] */
#define PCAL6416A_INT_STATUS 0x4C /* Interrupt status [RO] */
#define PCAL6416A_OUTPUT_CONFIG 0x4F /* Output port config [R/W] */
/****************************************************************
* Public functions
****************************************************************/
bool pcal6416a_init(void);
bool pcal6416a_deinit(void);
uint16_t pcal6416a_read_mask_interrupts(void);
uint16_t pcal6416a_read_mask_active_GPIOs(void);
#endif //_DRIVER_PCAL6416A_H_

78
funkey_gpio_management.c Normal file
View File

@ -0,0 +1,78 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h> // Defines signal-handling functions (i.e. trap Ctrl-C)
#include <sys/select.h>
#include "gpio-utils.h"
#include <assert.h>
#include "uinput.h"
#include "gpio_mapping.h"
#include "read_conf_file.h"
/****************************************************************
* Defines
****************************************************************/
/****************************************************************
* Global variables
****************************************************************/
int keepgoing = 1; // Set to 0 when ctrl-c is pressed
/****************************************************************
* signal_handler
****************************************************************/
void signal_handler(int sig);
// Callback called when SIGINT is sent to the process (Ctrl-C)
void signal_handler(int sig)
{
printf( "Ctrl-C pressed, cleaning up and exiting..\n" );
keepgoing = 0;
}
/****************************************************************
* Local functions
****************************************************************/
/****************************************************************
* Main
****************************************************************/
int main(int argc, char **argv, char **envp)
{
// Variables
STRUCT_MAPPED_GPIO * chained_list_mapping = NULL;
int nb_valid_gpios = 0;
int * gpio_pins = NULL;
// Set the signal callback for Ctrl-C
signal(SIGINT, signal_handler);
// Init uinput device
init_uinput();
// Read Conf File: Get GPIO pins to declare and all valid pin mappings
get_mapping_from_conf_file(&chained_list_mapping, &nb_valid_gpios, &gpio_pins);
// Init GPIOs
init_mapping_gpios(gpio_pins, nb_valid_gpios, chained_list_mapping);
// Main Loop
while (keepgoing) {
listen_gpios_interrupts();
}
// De-Init GPIOs
deinit_mapping_gpios();
/*
* Give userspace some time to read the events before we destroy the
* device with UI_DEV_DESTOY.
*/
close_uinput();
return 0;
}

55
funkey_gpio_mapping.conf Normal file
View File

@ -0,0 +1,55 @@
##################################
# Funkey GPIO keymap config file #
##################################
# Format:
#
# - First all GPIO Pin numbers must be declared (integers separated by commas)
# Example: 0,1,2,3,4,6,7,11,12,13,14,15
#
# - Then the mapping can be done as follows (one line per mapping):
# Pin_number[+Pin_number...], type_mapping, value, str_help_name_pin, str_help_fct_pin
#
# args: * Pin_number is the pin number concerned by the maping,
# add +Pin_number for multiple touch mapping (not limited in nb of pins)
# * type_mapping can be KEYBOARD or SHELL_COMMAND
# * value is :
# if type_mapping==KEYBOARD: the keycode from /usr/include/linux/input.h]
# if type_mapping==SHELL_COMMAND: the shell command to exec
# * str_help_name_pin is a sweet name for the pin (ex: PB5)
# * str_help_fct_pin is an help str to indicate the function of this mapping
###################################
# Pins declaration:
0,1,2,3,4,6,7,11,12,13,14,15
###################################
# Mapping:
6, KEYBOARD, KEY_S, KEY_S, Start
7, KEYBOARD, KEY_F, KEY_F, Fn
3, KEYBOARD, KEY_U, KEY_U, Up
4, KEYBOARD, KEY_L, KEY_L, Left
1, KEYBOARD, KEY_D, KEY_D, Down
0, KEYBOARD, KEY_R, KEY_R, Right
15, KEYBOARD, KEY_N, KEY_N, R1
2, KEYBOARD, KEY_M, KEY_M, L1
12, KEYBOARD, KEY_B, KEY_B, B
14, KEYBOARD, KEY_A, KEY_A, A
13, KEYBOARD, KEY_X, KEY_X, X
11, KEYBOARD, KEY_Y, KEY_Y, Y
7+7, KEYBOARD, KEY_K, KEY_K, Select
7+15, KEYBOARD, KEY_V, KEY_V, L2
7+2, KEYBOARD, KEY_O, KEY_O, R2
#7+3, SHELL_COMMAND, echo "Volume up", 6+3, Volume up
#7+1, SHELL_COMMAND, echo "Volume down", 6+1, Volume down
#7+0, SHELL_COMMAND, echo "Brightness up", 6+0, Brightness up
#7+4, SHELL_COMMAND, echo "Brightness down", 6+4, Brightness down
7+3, SHELL_COMMAND, /root/shell_cmds/start_gpsp.sh, 6+3, start gpsp
7+1, SHELL_COMMAND, /root/shell_cmds/start_pcsx.sh, 6+1, start pcsx
7+0, SHELL_COMMAND, /root/shell_cmds/start_psnes.sh, 6+0, start psnes
7+4, SHELL_COMMAND, /root/shell_cmds/start_mednafen.sh, 6+4, start mednafen GBC
7+11, SHELL_COMMAND, /root/shell_cmds/stop_all_emulators.sh, 6+4, stop all emulators

241
gpio-utils.c Normal file
View File

@ -0,0 +1,241 @@
/* Copyright (c) 2011, RidgeRun
* All rights reserved.
*
From https://www.ridgerun.com/developer/wiki/index.php/Gpio-int-test.c
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the RidgeRun.
* 4. Neither the name of the RidgeRun nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY RIDGERUN ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL RIDGERUN BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "gpio-utils.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
/****************************************************************
* gpio_export
****************************************************************/
int gpio_export(unsigned int gpio)
{
int fd, len;
char buf[MAX_BUF];
fd = open(SYSFS_GPIO_DIR "/export", O_WRONLY);
if (fd < 0) {
perror("gpio/export");
return fd;
}
len = snprintf(buf, sizeof(buf), "%d", gpio);
write(fd, buf, len);
close(fd);
return 0;
}
/****************************************************************
* gpio_unexport
****************************************************************/
int gpio_unexport(unsigned int gpio)
{
int fd, len;
char buf[MAX_BUF];
fd = open(SYSFS_GPIO_DIR "/unexport", O_WRONLY);
if (fd < 0) {
perror("gpio/export");
return fd;
}
len = snprintf(buf, sizeof(buf), "%d", gpio);
write(fd, buf, len);
close(fd);
return 0;
}
/****************************************************************
* gpio_set_dir
****************************************************************/
int gpio_set_dir(unsigned int gpio, const char* dir)
{
int fd, len;
char buf[MAX_BUF];
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/direction", gpio);
fd = open(buf, O_WRONLY);
if (fd < 0) {
perror("gpio/direction");
return fd;
}
write(fd, dir, sizeof(dir)+1);
close(fd);
return 0;
}
/****************************************************************
* gpio_set_value
****************************************************************/
int gpio_set_value(unsigned int gpio, unsigned int value)
{
int fd, len;
char buf[MAX_BUF];
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
fd = open(buf, O_WRONLY);
if (fd < 0) {
perror("gpio/set-value");
return fd;
}
if (value)
write(fd, "1", 2);
else
write(fd, "0", 2);
close(fd);
return 0;
}
/****************************************************************
* gpio_get_value
****************************************************************/
int gpio_get_value(unsigned int gpio, unsigned int *value)
{
int fd, len;
char buf[MAX_BUF];
char ch;
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
fd = open(buf, O_RDONLY);
if (fd < 0) {
perror("gpio/get-value");
return fd;
}
read(fd, &ch, 1);
if (ch != '0') {
*value = 1;
} else {
*value = 0;
}
close(fd);
return 0;
}
/****************************************************************
* gpio_set_edge
****************************************************************/
int gpio_set_edge(unsigned int gpio, const char *edge)
{
int fd, len;
char buf[MAX_BUF];
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio);
fd = open(buf, O_WRONLY);
if (fd < 0) {
perror("gpio/set-edge");
return fd;
}
write(fd, edge, strlen(edge) + 1);
close(fd);
return 0;
}
/****************************************************************
* gpio_fd_open
****************************************************************/
int gpio_fd_open(unsigned int gpio, unsigned int dir)
{
int fd, len;
char buf[MAX_BUF];
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
fd = open(buf, dir | O_NONBLOCK );
if (fd < 0) {
perror("gpio/fd_open");
}
return fd;
}
/****************************************************************
* gpio_fd_close
****************************************************************/
int gpio_fd_close(int fd)
{
return close(fd);
}
/****************************************************************
* ain_get_value (from Mike McDonald)
* https://groups.google.com/forum/#!topic/beagleboard-ece497/SLJ5nQQ_GoU
****************************************************************/
int ain_get_value(unsigned int ain, unsigned int *value)
{
int fd, len, bytesRead;
char buf[MAX_BUF];
char adc_in[ADC_BUF];
len = snprintf(buf, sizeof(buf), SYSFS_AIN_DIR "/AIN%d", ain);
fd = open(buf, O_RDONLY);
if (fd < 0) {
perror(buf);
return fd;
}
// Read from the
bytesRead = read(fd, adc_in, ADC_BUF);
// Turn the buffer value (a string) into an integer
if (bytesRead != -1) {
*value = atoi(adc_in);
adc_in[bytesRead] = (int)NULL;
lseek(fd, 0, SEEK_SET);
}
// Sleep for a little to ensure that we get good ADC values
usleep(1000);
close(fd);
return bytesRead;
}

17
gpio-utils.h Normal file
View File

@ -0,0 +1,17 @@
#define SYSFS_GPIO_DIR "/sys/class/gpio"
#define MAX_BUF 64
int gpio_export(unsigned int gpio);
int gpio_unexport(unsigned int gpio);
int gpio_set_dir(unsigned int gpio, const char* dir);
int gpio_set_value(unsigned int gpio, unsigned int value);
int gpio_get_value(unsigned int gpio, unsigned int *value);
int gpio_set_edge(unsigned int gpio, const char *edge);
int gpio_fd_open(unsigned int gpio, unsigned int dir);
int gpio_fd_close(int fd);
// Analog in
#define ADC_BUF 1024
#define SYSFS_AIN_DIR "/sys/devices/ocp.2/helper.11"
int ain_get_value(unsigned int ain, unsigned int *value);

353
gpio_mapping.c Normal file
View File

@ -0,0 +1,353 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <sys/select.h>
#include <linux/input.h>
#include "gpio_mapping.h"
#include "driver_pcal6416a.h"
/****************************************************************
* Defines
****************************************************************/
#define die(str, args...) do { \
perror(str); \
return(EXIT_FAILURE); \
} while(0)
#define DEBUG_GPIO_PRINTF (0)
#define ERROR_GPIO_PRINTF (1)
#if (DEBUG_GPIO_PRINTF)
#define GPIO_PRINTF(...) printf(__VA_ARGS__);
#else
#define GPIO_PRINTF(...)
#endif
#if (ERROR_GPIO_PRINTF)
#define GPIO_ERROR_PRINTF(...) printf(__VA_ARGS__);
#else
#define GPIO_ERROR_PRINTF(...)
#endif
/****************************************************************
* Static variables
****************************************************************/
static int nb_mapped_gpios;
static int * gpio_pins;
STRUCT_MAPPED_GPIO * chained_list_mapping;
static int max_fd = 0;
static int gpio_fd_interrupt_i2c;
static fd_set fds;
static bool * mask_gpio_value;
/****************************************************************
* Static functions
****************************************************************/
/***** Add a fd to fd_set, and update max_fd_nb ******/
static int safe_fd_set(int fd, fd_set* list_fds, int* max_fd_nb) {
assert(max_fd_nb != NULL);
FD_SET(fd, list_fds);
if (fd > *max_fd_nb) {
*max_fd_nb = fd;
}
return 0;
}
/***** Clear fd from fds, update max fd if needed *****/
static int safe_fd_clr(int fd, fd_set* list_fds, int* max_fd_nb) {
assert(max_fd_nb != NULL);
FD_CLR(fd, list_fds);
if (fd == *max_fd_nb) {
(*max_fd_nb)--;
}
return 0;
}
/***** Apply mapping activation fuction *****/
static void apply_mapping_activation(STRUCT_MAPPED_GPIO * node_mapping){
node_mapping->activated = true;
if(node_mapping->type_mapping == TYPE_MAPPING_KEYBOARD){
GPIO_PRINTF("Apply mapping activation fct: Key event: %d\n", node_mapping->key_value);
sendKey(node_mapping->key_value, 1);
//sendKeyAndStopKey(node_mapping->key_value);
}
else if(node_mapping->type_mapping == TYPE_MAPPING_SHELL_COMMAND){
GPIO_PRINTF("Apply mapping activation fct: shell command \"%s\"\n", node_mapping->shell_command);
system(node_mapping->shell_command);
}
}
/***** Apply mapping desactivation function *****/
static void apply_mapping_desactivation(STRUCT_MAPPED_GPIO * node_mapping){
node_mapping->activated = false;
if(node_mapping->type_mapping == TYPE_MAPPING_KEYBOARD){
GPIO_PRINTF("Apply mapping desactivation fct: Key event: %d\n", node_mapping->key_value);
sendKey(node_mapping->key_value, 0);
}
else if(node_mapping->type_mapping == TYPE_MAPPING_SHELL_COMMAND){
//GPIO_PRINTF("Apply mapping desactivation fct: shell command \"%s\"\n", node_mapping->shell_command);
}
}
static void find_and_call_mapping_function(int idx_gpio_interrupted,
STRUCT_MAPPED_GPIO * cl_mapping,
bool* mask_gpio_current_interrupts,
bool * mask_gpio_values,
bool activation){
// Init variables
STRUCT_MAPPED_GPIO * current = cl_mapping;
bool mapping_found = false;
// Search if there are mappings to deactivate
while (current != NULL) {
int i;
bool gpio_found_pin_in_mapping = false;
bool all_gpio_activated_in_mapping = true;
//GPIO_PRINTF(" Mapping searching for idx_gpio_interrupted: %d, and %s: \n", idx_gpio_interrupted, activation?"activation":"deactivation")
for (i=0; i < current->nb_simultaneous_pins; i++){
//GPIO_PRINTF(" Pin in mapping: %d, pin_idx=%d\n", gpio_pins[current->pins_idx[i]], current->pins_idx[i]);
// Find if current mapping contains interrupted pin
if (current->pins_idx[i] == idx_gpio_interrupted){
gpio_found_pin_in_mapping = true;
}
// Check if all other pins of current mapping were already activated in previous mask
if(!mask_gpio_values[current->pins_idx[i]]){
all_gpio_activated_in_mapping = false;
}
}
// If this mapping contains the interrupted pin and all other pins activated:
if(gpio_found_pin_in_mapping && all_gpio_activated_in_mapping){
// Treating activation cases
if(activation){
// if real mapping already found => need to deactivate previously activated ones
if(mapping_found && current->activated){
GPIO_PRINTF(" Mapping Deactivation because real one already found: GPIO %d found in following activated mapping: \n",
gpio_pins[idx_gpio_interrupted]);
print_chained_list_node(current);
apply_mapping_desactivation(current);
}
else if(!mapping_found){ // If this is the real mapping
if(current->activated){
GPIO_ERROR_PRINTF("WARNING in find_and_call_mapping_function - Activating already activated mapping %s\n",
current->fct_help_str);
}
// Print information and activate mapping
GPIO_PRINTF(" Mapping Activation: GPIO %d found in following deactivated mapping: \n",
gpio_pins[idx_gpio_interrupted]);
print_chained_list_node(current);
apply_mapping_activation(current);
}
}
else{ // Treating deactivation cases
if(current->activated){
GPIO_PRINTF(" Mapping Desactivation: GPIO %d found in following activated mapping: \n",
gpio_pins[idx_gpio_interrupted]);
print_chained_list_node(current);
apply_mapping_desactivation(current);
}
}
// Set that mapping has been found
mapping_found = true;
}
// Next node in chained list
current = current->next_mapped_gpio;
}
}
/***** Init GPIO Interrupt i2c expander fd *****/
static int init_gpio_interrupt(void)
{
// Variables
int cur_pin_nb = GPIO_PIN_I2C_EXPANDER_INTERRUPT;
GPIO_PRINTF("Initializing Interrupt i2c expander GPIO pin fd: %d\n", cur_pin_nb);
// Init fds fd_set
FD_ZERO(&fds);
//Initializing I2C interrupt GPIO
gpio_export(cur_pin_nb);
//gpio_set_edge(cur_pin_nb, "both"); // Can be rising, falling or both
gpio_set_edge(cur_pin_nb, "falling"); // Can be rising, falling or both
gpio_fd_interrupt_i2c = gpio_fd_open(cur_pin_nb, O_RDONLY);
// add stdin and the sock fd to fds fd_set
safe_fd_set(gpio_fd_interrupt_i2c, &fds, &max_fd);
return 0;
}
/***** DeInit GPIO Interrupt i2c expander fd *****/
static int deinit_gpio_interrupt(void)
{
GPIO_PRINTF("DeInitializing Interrupt i2c expander GPIO pin fd\n");
// Remove stdin and sock fd from fds fd_set
safe_fd_clr(gpio_fd_interrupt_i2c, &fds, &max_fd);
// Unexport GPIO
gpio_fd_close(gpio_fd_interrupt_i2c);
return 0;
}
/****************************************************************
* Public functions
****************************************************************/
/***** Init I2C expander pin mappings *****/
int init_mapping_gpios(int * gpio_pins_to_declare, int nb_gpios_to_declare,
STRUCT_MAPPED_GPIO * chained_list_mapping_gpios)
{
// Variables
int idx_gpio;
unsigned int cur_pin_nb;
// Store arguments
nb_mapped_gpios = nb_gpios_to_declare;
gpio_pins = gpio_pins_to_declare;
chained_list_mapping = chained_list_mapping_gpios;
// Init values
mask_gpio_value = malloc(nb_mapped_gpios*sizeof(bool));
memset(mask_gpio_value, false, nb_mapped_gpios*sizeof(bool));
STRUCT_MAPPED_GPIO * current = chained_list_mapping;
do{
//set mapping deactivated
current->activated = false;
// Next node in chained list
current = current->next_mapped_gpio;
} while(current != NULL);
// Init GPIO interrupt from I2C expander
init_gpio_interrupt();
// Init I2C expander
pcal6416a_init();
return 0;
}
/***** DeInit GPIO fds *****/
int deinit_mapping_gpios(void)
{
// DeInit GPIO interrupt from I2C expander
deinit_gpio_interrupt();
// DeInit I2C expander
pcal6416a_deinit();
return 0;
}
/***** Listen GPIOs interrupts *****/
int listen_gpios_interrupts(void)
{
// Variables
char buffer[2];
int idx_gpio, value;
bool previous_mask_gpio_value[nb_mapped_gpios];
bool mask_gpio_current_interrupts[nb_mapped_gpios];
uint16_t val_i2c_mask_interrupted, val_i2c_mask_active;
bool interrupt_found = false;
// Back up master
fd_set dup = fds;
// Init masks
memcpy(previous_mask_gpio_value, mask_gpio_value, nb_mapped_gpios*sizeof(bool));
memset(mask_gpio_value, false, nb_mapped_gpios*sizeof(bool));
memset(mask_gpio_current_interrupts, false, nb_mapped_gpios*sizeof(bool));
// Note the max_fd+1
if (select(max_fd+1, NULL, NULL, &dup, NULL) < 0) {
perror("select");
return -1;
}
// Check if interrupt from I2C expander
// Check which cur_fd is available for read
for (int cur_fd = 0; cur_fd <= max_fd; cur_fd++) {
if (FD_ISSET(cur_fd, &dup)) {
// Revenir au debut du fichier (lectures successives).
lseek(cur_fd, 0, SEEK_SET);
// Read current gpio value
if (read(cur_fd, & buffer, 2) != 2) {
perror("read");
break;
}
// Effacer le retour-chariot.
buffer[1] = '\0';
value = 1-atoi(buffer);
// Found interrupt
interrupt_found = true;
}
}
if(interrupt_found){
// Read I2C GPIO masks:
val_i2c_mask_interrupted = pcal6416a_read_mask_interrupts();
val_i2c_mask_active = pcal6416a_read_mask_active_GPIOs();
// Find GPIO idx correspondance
for (idx_gpio=0; idx_gpio<nb_mapped_gpios; idx_gpio++){
uint16_t tmp_mask_gpio = (1 << gpio_pins[idx_gpio]);
// Found GPIO idx in active GPIOs
if(val_i2c_mask_active & tmp_mask_gpio){
mask_gpio_value[idx_gpio] = true;
}
// Found GPIO idx in interrupt mask
if(val_i2c_mask_interrupted & tmp_mask_gpio){
// Print information
GPIO_PRINTF(" --> Interrupt GPIO: %d, idx_pin: %d\n", gpio_pins[idx_gpio], idx_gpio);
mask_gpio_current_interrupts[idx_gpio] = true;
}
}
// Find and call mapping functions (after all active gpios have been assigned):
for (idx_gpio=0; idx_gpio<nb_mapped_gpios; idx_gpio++){
if(!mask_gpio_current_interrupts[idx_gpio]) continue;
if (mask_gpio_value[idx_gpio]){
find_and_call_mapping_function(idx_gpio,
chained_list_mapping,
mask_gpio_current_interrupts,
mask_gpio_value,
true);
}
else{
find_and_call_mapping_function(idx_gpio,
chained_list_mapping,
mask_gpio_current_interrupts,
previous_mask_gpio_value,
false);
}
}
}
return 0;
}

25
gpio_mapping.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef _GPIO_MAPPING_H_
#define _GPIO_MAPPING_H_
/****************************************************************
* Includes
****************************************************************/
#include "gpio-utils.h"
#include "uinput.h"
#include "read_conf_file.h"
/****************************************************************
* Defines
****************************************************************/
#define GPIO_PIN_I2C_EXPANDER_INTERRUPT 35 //PB3
//#define GPIO_PIN_I2C_EXPANDER_INTERRUPT 38 //PB6
/****************************************************************
* Public functions
****************************************************************/
int init_mapping_gpios(int * gpio_pins_to_declare, int nb_gpios_to_declare,
STRUCT_MAPPED_GPIO * chained_list_mapping_gpios);
int deinit_mapping_gpios(void);
int listen_gpios_interrupts(void);
#endif //_GPIO_MAPPING_H_

576
keydefs.c Normal file
View File

@ -0,0 +1,576 @@
/**** keydefs.c ****************************/
/* M. Moller 2013-01-16 */
/* Universal RPi GPIO keyboard daemon */
/*******************************************/
/*
Copyright (C) 2013 Michael Moller.
This file is part of the Universal Raspberry Pi GPIO keyboard daemon.
This is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
*/
#include <stdio.h>
#include "gpio_mapping.h"
const key_names_s key_names[] = {
/*
a subset of
sed 's/^#define \([^ \t]\+\)[ \t]*\([^\ \t]\+\)/ { \"\1\",\t\2 },/' /usr/include/linux/input.h
*/
{ "KEY_RESERVED", 0 },
{ "KEY_ESC", 1 },
{ "KEY_1", 2 },
{ "KEY_2", 3 },
{ "KEY_3", 4 },
{ "KEY_4", 5 },
{ "KEY_5", 6 },
{ "KEY_6", 7 },
{ "KEY_7", 8 },
{ "KEY_8", 9 },
{ "KEY_9", 10 },
{ "KEY_0", 11 },
{ "KEY_MINUS", 12 },
{ "KEY_EQUAL", 13 },
{ "KEY_BACKSPACE", 14 },
{ "KEY_TAB", 15 },
{ "KEY_Q", 16 },
{ "KEY_W", 17 },
{ "KEY_E", 18 },
{ "KEY_R", 19 },
{ "KEY_T", 20 },
{ "KEY_Y", 21 },
{ "KEY_U", 22 },
{ "KEY_I", 23 },
{ "KEY_O", 24 },
{ "KEY_P", 25 },
{ "KEY_LEFTBRACE", 26 },
{ "KEY_RIGHTBRACE", 27 },
{ "KEY_ENTER", 28 },
{ "KEY_LEFTCTRL", 29 },
{ "KEY_A", 30 },
{ "KEY_S", 31 },
{ "KEY_D", 32 },
{ "KEY_F", 33 },
{ "KEY_G", 34 },
{ "KEY_H", 35 },
{ "KEY_J", 36 },
{ "KEY_K", 37 },
{ "KEY_L", 38 },
{ "KEY_SEMICOLON", 39 },
{ "KEY_APOSTROPHE", 40 },
{ "KEY_GRAVE", 41 },
{ "KEY_LEFTSHIFT", 42 },
{ "KEY_BACKSLASH", 43 },
{ "KEY_Z", 44 },
{ "KEY_X", 45 },
{ "KEY_C", 46 },
{ "KEY_V", 47 },
{ "KEY_B", 48 },
{ "KEY_N", 49 },
{ "KEY_M", 50 },
{ "KEY_COMMA", 51 },
{ "KEY_DOT", 52 },
{ "KEY_SLASH", 53 },
{ "KEY_RIGHTSHIFT", 54 },
{ "KEY_KPASTERISK", 55 },
{ "KEY_LEFTALT", 56 },
{ "KEY_SPACE", 57 },
{ "KEY_CAPSLOCK", 58 },
{ "KEY_F1", 59 },
{ "KEY_F2", 60 },
{ "KEY_F3", 61 },
{ "KEY_F4", 62 },
{ "KEY_F5", 63 },
{ "KEY_F6", 64 },
{ "KEY_F7", 65 },
{ "KEY_F8", 66 },
{ "KEY_F9", 67 },
{ "KEY_F10", 68 },
{ "KEY_NUMLOCK", 69 },
{ "KEY_SCROLLLOCK", 70 },
{ "KEY_KP7", 71 },
{ "KEY_KP8", 72 },
{ "KEY_KP9", 73 },
{ "KEY_KPMINUS", 74 },
{ "KEY_KP4", 75 },
{ "KEY_KP5", 76 },
{ "KEY_KP6", 77 },
{ "KEY_KPPLUS", 78 },
{ "KEY_KP1", 79 },
{ "KEY_KP2", 80 },
{ "KEY_KP3", 81 },
{ "KEY_KP0", 82 },
{ "KEY_KPDOT", 83 },
{ "KEY_ZENKAKUHANKAKU", 85 },
{ "KEY_102ND", 86 },
{ "KEY_F11", 87 },
{ "KEY_F12", 88 },
{ "KEY_RO", 89 },
{ "KEY_KATAKANA", 90 },
{ "KEY_HIRAGANA", 91 },
{ "KEY_HENKAN", 92 },
{ "KEY_KATAKANAHIRAGANA", 93 },
{ "KEY_MUHENKAN", 94 },
{ "KEY_KPJPCOMMA", 95 },
{ "KEY_KPENTER", 96 },
{ "KEY_RIGHTCTRL", 97 },
{ "KEY_KPSLASH", 98 },
{ "KEY_SYSRQ", 99 },
{ "KEY_RIGHTALT", 100 },
{ "KEY_LINEFEED", 101 },
{ "KEY_HOME", 102 },
{ "KEY_UP", 103 },
{ "KEY_PAGEUP", 104 },
{ "KEY_LEFT", 105 },
{ "KEY_RIGHT", 106 },
{ "KEY_END", 107 },
{ "KEY_DOWN", 108 },
{ "KEY_PAGEDOWN", 109 },
{ "KEY_INSERT", 110 },
{ "KEY_DELETE", 111 },
{ "KEY_MACRO", 112 },
{ "KEY_MUTE", 113 },
{ "KEY_VOLUMEDOWN", 114 },
{ "KEY_VOLUMEUP", 115 },
{ "KEY_POWER", 116 }, /* SC System Power Down */
{ "KEY_KPEQUAL", 117 },
{ "KEY_KPPLUSMINUS", 118 },
{ "KEY_PAUSE", 119 },
{ "KEY_SCALE", 120 }, /* AL Compiz Scale (Expose) */
{ "KEY_KPCOMMA", 121 },
{ "KEY_HANGEUL", 122 },
{ "KEY_HANGUEL", 122 /*KEY_HANGEUL*/ },
{ "KEY_HANJA", 123 },
{ "KEY_YEN", 124 },
{ "KEY_LEFTMETA", 125 },
{ "KEY_RIGHTMETA", 126 },
{ "KEY_COMPOSE", 127 },
{ "KEY_STOP", 128 }, /* AC Stop */
{ "KEY_AGAIN", 129 },
{ "KEY_PROPS", 130 }, /* AC Properties */
{ "KEY_UNDO", 131 }, /* AC Undo */
{ "KEY_FRONT", 132 },
{ "KEY_COPY", 133 }, /* AC Copy */
{ "KEY_OPEN", 134 }, /* AC Open */
{ "KEY_PASTE", 135 }, /* AC Paste */
{ "KEY_FIND", 136 }, /* AC Search */
{ "KEY_CUT", 137 }, /* AC Cut */
{ "KEY_HELP", 138 }, /* AL Integrated Help Center */
{ "KEY_MENU", 139 }, /* Menu (show menu) */
{ "KEY_CALC", 140 }, /* AL Calculator */
{ "KEY_SETUP", 141 },
{ "KEY_SLEEP", 142 }, /* SC System Sleep */
{ "KEY_WAKEUP", 143 }, /* System Wake Up */
{ "KEY_FILE", 144 }, /* AL Local Machine Browser */
{ "KEY_SENDFILE", 145 },
{ "KEY_DELETEFILE", 146 },
{ "KEY_XFER", 147 },
{ "KEY_PROG1", 148 },
{ "KEY_PROG2", 149 },
{ "KEY_WWW", 150 }, /* AL Internet Browser */
{ "KEY_MSDOS", 151 },
{ "KEY_COFFEE", 152 }, /* AL Terminal Lock/Screensaver */
{ "KEY_SCREENLOCK", 152 /*KEY_COFFEE*/ },
{ "KEY_DIRECTION", 153 },
{ "KEY_CYCLEWINDOWS", 154 },
{ "KEY_MAIL", 155 },
{ "KEY_BOOKMARKS", 156 }, /* AC Bookmarks */
{ "KEY_COMPUTER", 157 },
{ "KEY_BACK", 158 }, /* AC Back */
{ "KEY_FORWARD", 159 }, /* AC Forward */
{ "KEY_CLOSECD", 160 },
{ "KEY_EJECTCD", 161 },
{ "KEY_EJECTCLOSECD", 162 },
{ "KEY_NEXTSONG", 163 },
{ "KEY_PLAYPAUSE", 164 },
{ "KEY_PREVIOUSSONG", 165 },
{ "KEY_STOPCD", 166 },
{ "KEY_RECORD", 167 },
{ "KEY_REWIND", 168 },
{ "KEY_PHONE", 169 }, /* Media Select Telephone */
{ "KEY_ISO", 170 },
{ "KEY_CONFIG", 171 }, /* AL Consumer Control Configuration */
{ "KEY_HOMEPAGE", 172 }, /* AC Home */
{ "KEY_REFRESH", 173 }, /* AC Refresh */
{ "KEY_EXIT", 174 }, /* AC Exit */
{ "KEY_MOVE", 175 },
{ "KEY_EDIT", 176 },
{ "KEY_SCROLLUP", 177 },
{ "KEY_SCROLLDOWN", 178 },
{ "KEY_KPLEFTPAREN", 179 },
{ "KEY_KPRIGHTPAREN", 180 },
{ "KEY_NEW", 181 }, /* AC New */
{ "KEY_REDO", 182 }, /* AC Redo/Repeat */
{ "KEY_F13", 183 },
{ "KEY_F14", 184 },
{ "KEY_F15", 185 },
{ "KEY_F16", 186 },
{ "KEY_F17", 187 },
{ "KEY_F18", 188 },
{ "KEY_F19", 189 },
{ "KEY_F20", 190 },
{ "KEY_F21", 191 },
{ "KEY_F22", 192 },
{ "KEY_F23", 193 },
{ "KEY_F24", 194 },
{ "KEY_PLAYCD", 200 },
{ "KEY_PAUSECD", 201 },
{ "KEY_PROG3", 202 },
{ "KEY_PROG4", 203 },
{ "KEY_DASHBOARD", 204 }, /* AL Dashboard */
{ "KEY_SUSPEND", 205 },
{ "KEY_CLOSE", 206 }, /* AC Close */
{ "KEY_PLAY", 207 },
{ "KEY_FASTFORWARD", 208 },
{ "KEY_BASSBOOST", 209 },
{ "KEY_PRINT", 210 }, /* AC Print */
{ "KEY_HP", 211 },
{ "KEY_CAMERA", 212 },
{ "KEY_SOUND", 213 },
{ "KEY_QUESTION", 214 },
{ "KEY_EMAIL", 215 },
{ "KEY_CHAT", 216 },
{ "KEY_SEARCH", 217 },
{ "KEY_CONNECT", 218 },
{ "KEY_FINANCE", 219 }, /* AL Checkbook/Finance */
{ "KEY_SPORT", 220 },
{ "KEY_SHOP", 221 },
{ "KEY_ALTERASE", 222 },
{ "KEY_CANCEL", 223 }, /* AC Cancel */
{ "KEY_BRIGHTNESSDOWN", 224 },
{ "KEY_BRIGHTNESSUP", 225 },
{ "KEY_MEDIA", 226 },
{ "KEY_SWITCHVIDEOMODE", 227 }, /* Cycle between available video
outputs (Monitor/LCD/TV-out/etc) */
{ "KEY_KBDILLUMTOGGLE", 228 },
{ "KEY_KBDILLUMDOWN", 229 },
{ "KEY_KBDILLUMUP", 230 },
{ "KEY_SEND", 231 }, /* AC Send */
{ "KEY_REPLY", 232 }, /* AC Reply */
{ "KEY_FORWARDMAIL", 233 }, /* AC Forward Msg */
{ "KEY_SAVE", 234 }, /* AC Save */
{ "KEY_DOCUMENTS", 235 },
{ "KEY_BATTERY", 236 },
{ "KEY_BLUETOOTH", 237 },
{ "KEY_WLAN", 238 },
{ "KEY_UWB", 239 },
{ "KEY_UNKNOWN", 240 },
{ "KEY_VIDEO_NEXT", 241 }, /* drive next video source */
{ "KEY_VIDEO_PREV", 242 }, /* drive previous video source */
{ "KEY_BRIGHTNESS_CYCLE", 243 }, /* brightness up, after max is min */
{ "KEY_BRIGHTNESS_ZERO", 244 }, /* brightness off, use ambient */
{ "KEY_DISPLAY_OFF", 245 }, /* display device to off state */
{ "KEY_WIMAX", 246 },
{ "KEY_RFKILL", 247 }, /* Key that controls all radios */
{ "KEY_MICMUTE", 248 }, /* Mute / unmute the microphone */
/* Code 255 is reserved for special needs of AT keyboard driver */
{ "BTN_MISC", 0x100 },
{ "BTN_0", 0x100 },
{ "BTN_1", 0x101 },
{ "BTN_2", 0x102 },
{ "BTN_3", 0x103 },
{ "BTN_4", 0x104 },
{ "BTN_5", 0x105 },
{ "BTN_6", 0x106 },
{ "BTN_7", 0x107 },
{ "BTN_8", 0x108 },
{ "BTN_9", 0x109 },
{ "BTN_MOUSE", 0x110 },
{ "BTN_LEFT", 0x110 },
{ "BTN_RIGHT", 0x111 },
{ "BTN_MIDDLE", 0x112 },
{ "BTN_SIDE", 0x113 },
{ "BTN_EXTRA", 0x114 },
{ "BTN_FORWARD", 0x115 },
{ "BTN_BACK", 0x116 },
{ "BTN_TASK", 0x117 },
{ "BTN_JOYSTICK", 0x120 },
{ "BTN_TRIGGER", 0x120 },
{ "BTN_THUMB", 0x121 },
{ "BTN_THUMB2", 0x122 },
{ "BTN_TOP", 0x123 },
{ "BTN_TOP2", 0x124 },
{ "BTN_PINKIE", 0x125 },
{ "BTN_BASE", 0x126 },
{ "BTN_BASE2", 0x127 },
{ "BTN_BASE3", 0x128 },
{ "BTN_BASE4", 0x129 },
{ "BTN_BASE5", 0x12a },
{ "BTN_BASE6", 0x12b },
{ "BTN_DEAD", 0x12f },
{ "BTN_GAMEPAD", 0x130 },
{ "BTN_A", 0x130 },
{ "BTN_B", 0x131 },
{ "BTN_C", 0x132 },
{ "BTN_X", 0x133 },
{ "BTN_Y", 0x134 },
{ "BTN_Z", 0x135 },
{ "BTN_TL", 0x136 },
{ "BTN_TR", 0x137 },
{ "BTN_TL2", 0x138 },
{ "BTN_TR2", 0x139 },
{ "BTN_SELECT", 0x13a },
{ "BTN_START", 0x13b },
{ "BTN_MODE", 0x13c },
{ "BTN_THUMBL", 0x13d },
{ "BTN_THUMBR", 0x13e },
#if 0
{ "BTN_DIGI", 0x140 },
{ "BTN_TOOL_PEN", 0x140 },
{ "BTN_TOOL_RUBBER", 0x141 },
{ "BTN_TOOL_BRUSH", 0x142 },
{ "BTN_TOOL_PENCIL", 0x143 },
{ "BTN_TOOL_AIRBRUSH", 0x144 },
{ "BTN_TOOL_FINGER", 0x145 },
{ "BTN_TOOL_MOUSE", 0x146 },
{ "BTN_TOOL_LENS", 0x147 },
{ "BTN_TOOL_QUINTTAP", 0x148 }, /* Five fingers on trackpad */
{ "BTN_TOUCH", 0x14a },
{ "BTN_STYLUS", 0x14b },
{ "BTN_STYLUS2", 0x14c },
{ "BTN_TOOL_DOUBLETAP", 0x14d },
{ "BTN_TOOL_TRIPLETAP", 0x14e },
{ "BTN_TOOL_QUADTAP", 0x14f }, /* Four fingers on trackpad */
{ "BTN_WHEEL", 0x150 },
{ "BTN_GEAR_DOWN", 0x150 },
{ "BTN_GEAR_UP", 0x151 },
{ "KEY_OK", 0x160 },
{ "KEY_SELECT", 0x161 },
{ "KEY_GOTO", 0x162 },
{ "KEY_CLEAR", 0x163 },
{ "KEY_POWER2", 0x164 },
{ "KEY_OPTION", 0x165 },
{ "KEY_INFO", 0x166 }, /* AL OEM Features/Tips/Tutorial */
{ "KEY_TIME", 0x167 },
{ "KEY_VENDOR", 0x168 },
{ "KEY_ARCHIVE", 0x169 },
{ "KEY_PROGRAM", 0x16a }, /* Media Select Program Guide */
{ "KEY_CHANNEL", 0x16b },
{ "KEY_FAVORITES", 0x16c },
{ "KEY_EPG", 0x16d },
{ "KEY_PVR", 0x16e }, /* Media Select Home */
{ "KEY_MHP", 0x16f },
{ "KEY_LANGUAGE", 0x170 },
{ "KEY_TITLE", 0x171 },
{ "KEY_SUBTITLE", 0x172 },
{ "KEY_ANGLE", 0x173 },
{ "KEY_ZOOM", 0x174 },
{ "KEY_MODE", 0x175 },
{ "KEY_KEYBOARD", 0x176 },
{ "KEY_SCREEN", 0x177 },
{ "KEY_PC", 0x178 }, /* Media Select Computer */
{ "KEY_TV", 0x179 }, /* Media Select TV */
{ "KEY_TV2", 0x17a }, /* Media Select Cable */
{ "KEY_VCR", 0x17b }, /* Media Select VCR */
{ "KEY_VCR2", 0x17c }, /* VCR Plus */
{ "KEY_SAT", 0x17d }, /* Media Select Satellite */
{ "KEY_SAT2", 0x17e },
{ "KEY_CD", 0x17f }, /* Media Select CD */
{ "KEY_TAPE", 0x180 }, /* Media Select Tape */
{ "KEY_RADIO", 0x181 },
{ "KEY_TUNER", 0x182 }, /* Media Select Tuner */
{ "KEY_PLAYER", 0x183 },
{ "KEY_TEXT", 0x184 },
{ "KEY_DVD", 0x185 }, /* Media Select DVD */
{ "KEY_AUX", 0x186 },
{ "KEY_MP3", 0x187 },
{ "KEY_AUDIO", 0x188 }, /* AL Audio Browser */
{ "KEY_VIDEO", 0x189 }, /* AL Movie Browser */
{ "KEY_DIRECTORY", 0x18a },
{ "KEY_LIST", 0x18b },
{ "KEY_MEMO", 0x18c }, /* Media Select Messages */
{ "KEY_CALENDAR", 0x18d },
{ "KEY_RED", 0x18e },
{ "KEY_GREEN", 0x18f },
{ "KEY_YELLOW", 0x190 },
{ "KEY_BLUE", 0x191 },
{ "KEY_CHANNELUP", 0x192 }, /* Channel Increment */
{ "KEY_CHANNELDOWN", 0x193 }, /* Channel Decrement */
{ "KEY_FIRST", 0x194 },
{ "KEY_LAST", 0x195 }, /* Recall Last */
{ "KEY_AB", 0x196 },
{ "KEY_NEXT", 0x197 },
{ "KEY_RESTART", 0x198 },
{ "KEY_SLOW", 0x199 },
{ "KEY_SHUFFLE", 0x19a },
{ "KEY_BREAK", 0x19b },
{ "KEY_PREVIOUS", 0x19c },
{ "KEY_DIGITS", 0x19d },
{ "KEY_TEEN", 0x19e },
{ "KEY_TWEN", 0x19f },
{ "KEY_VIDEOPHONE", 0x1a0 }, /* Media Select Video Phone */
{ "KEY_GAMES", 0x1a1 }, /* Media Select Games */
{ "KEY_ZOOMIN", 0x1a2 }, /* AC Zoom In */
{ "KEY_ZOOMOUT", 0x1a3 }, /* AC Zoom Out */
{ "KEY_ZOOMRESET", 0x1a4 }, /* AC Zoom */
{ "KEY_WORDPROCESSOR", 0x1a5 }, /* AL Word Processor */
{ "KEY_EDITOR", 0x1a6 }, /* AL Text Editor */
{ "KEY_SPREADSHEET", 0x1a7 }, /* AL Spreadsheet */
{ "KEY_GRAPHICSEDITOR", 0x1a8 }, /* AL Graphics Editor */
{ "KEY_PRESENTATION", 0x1a9 }, /* AL Presentation App */
{ "KEY_DATABASE", 0x1aa }, /* AL Database App */
{ "KEY_NEWS", 0x1ab }, /* AL Newsreader */
{ "KEY_VOICEMAIL", 0x1ac }, /* AL Voicemail */
{ "KEY_ADDRESSBOOK", 0x1ad }, /* AL Contacts/Address Book */
{ "KEY_MESSENGER", 0x1ae }, /* AL Instant Messaging */
{ "KEY_DISPLAYTOGGLE", 0x1af }, /* Turn display (LCD) on and off */
{ "KEY_SPELLCHECK", 0x1b0 }, /* AL Spell Check */
{ "KEY_LOGOFF", 0x1b1 }, /* AL Logoff */
{ "KEY_DOLLAR", 0x1b2 },
{ "KEY_EURO", 0x1b3 },
{ "KEY_FRAMEBACK", 0x1b4 }, /* Consumer - transport controls */
{ "KEY_FRAMEFORWARD", 0x1b5 },
{ "KEY_CONTEXT_MENU", 0x1b6 }, /* GenDesc - system context menu */
{ "KEY_MEDIA_REPEAT", 0x1b7 }, /* Consumer - transport control */
{ "KEY_10CHANNELSUP", 0x1b8 }, /* 10 channels up (10+) */
{ "KEY_10CHANNELSDOWN", 0x1b9 }, /* 10 channels down (10-) */
{ "KEY_IMAGES", 0x1ba }, /* AL Image Browser */
{ "KEY_DEL_EOL", 0x1c0 },
{ "KEY_DEL_EOS", 0x1c1 },
{ "KEY_INS_LINE", 0x1c2 },
{ "KEY_DEL_LINE", 0x1c3 },
{ "KEY_FN", 0x1d0 },
{ "KEY_FN_ESC", 0x1d1 },
{ "KEY_FN_F1", 0x1d2 },
{ "KEY_FN_F2", 0x1d3 },
{ "KEY_FN_F3", 0x1d4 },
{ "KEY_FN_F4", 0x1d5 },
{ "KEY_FN_F5", 0x1d6 },
{ "KEY_FN_F6", 0x1d7 },
{ "KEY_FN_F7", 0x1d8 },
{ "KEY_FN_F8", 0x1d9 },
{ "KEY_FN_F9", 0x1da },
{ "KEY_FN_F10", 0x1db },
{ "KEY_FN_F11", 0x1dc },
{ "KEY_FN_F12", 0x1dd },
{ "KEY_FN_1", 0x1de },
{ "KEY_FN_2", 0x1df },
{ "KEY_FN_D", 0x1e0 },
{ "KEY_FN_E", 0x1e1 },
{ "KEY_FN_F", 0x1e2 },
{ "KEY_FN_S", 0x1e3 },
{ "KEY_FN_B", 0x1e4 },
{ "KEY_BRL_DOT1", 0x1f1 },
{ "KEY_BRL_DOT2", 0x1f2 },
{ "KEY_BRL_DOT3", 0x1f3 },
{ "KEY_BRL_DOT4", 0x1f4 },
{ "KEY_BRL_DOT5", 0x1f5 },
{ "KEY_BRL_DOT6", 0x1f6 },
{ "KEY_BRL_DOT7", 0x1f7 },
{ "KEY_BRL_DOT8", 0x1f8 },
{ "KEY_BRL_DOT9", 0x1f9 },
{ "KEY_BRL_DOT10", 0x1fa },
{ "KEY_NUMERIC_0", 0x200 }, /* used by phones, remote controls, */
{ "KEY_NUMERIC_1", 0x201 }, /* and other keypads */
{ "KEY_NUMERIC_2", 0x202 },
{ "KEY_NUMERIC_3", 0x203 },
{ "KEY_NUMERIC_4", 0x204 },
{ "KEY_NUMERIC_5", 0x205 },
{ "KEY_NUMERIC_6", 0x206 },
{ "KEY_NUMERIC_7", 0x207 },
{ "KEY_NUMERIC_8", 0x208 },
{ "KEY_NUMERIC_9", 0x209 },
{ "KEY_NUMERIC_STAR", 0x20a },
{ "KEY_NUMERIC_POUND", 0x20b },
{ "KEY_CAMERA_FOCUS", 0x210 },
{ "KEY_WPS_BUTTON", 0x211 }, /* WiFi Protected Setup key */
{ "KEY_TOUCHPAD_TOGGLE", 0x212 }, /* Request switch touchpad on or off */
{ "KEY_TOUCHPAD_ON", 0x213 },
{ "KEY_TOUCHPAD_OFF", 0x214 },
{ "KEY_CAMERA_ZOOMIN", 0x215 },
{ "KEY_CAMERA_ZOOMOUT", 0x216 },
{ "KEY_CAMERA_UP", 0x217 },
{ "KEY_CAMERA_DOWN", 0x218 },
{ "KEY_CAMERA_LEFT", 0x219 },
{ "KEY_CAMERA_RIGHT", 0x21a },
{ "BTN_TRIGGER_HAPPY", 0x2c0 },
{ "BTN_TRIGGER_HAPPY1", 0x2c0 },
{ "BTN_TRIGGER_HAPPY2", 0x2c1 },
{ "BTN_TRIGGER_HAPPY3", 0x2c2 },
{ "BTN_TRIGGER_HAPPY4", 0x2c3 },
{ "BTN_TRIGGER_HAPPY5", 0x2c4 },
{ "BTN_TRIGGER_HAPPY6", 0x2c5 },
{ "BTN_TRIGGER_HAPPY7", 0x2c6 },
{ "BTN_TRIGGER_HAPPY8", 0x2c7 },
{ "BTN_TRIGGER_HAPPY9", 0x2c8 },
{ "BTN_TRIGGER_HAPPY10", 0x2c9 },
{ "BTN_TRIGGER_HAPPY11", 0x2ca },
{ "BTN_TRIGGER_HAPPY12", 0x2cb },
{ "BTN_TRIGGER_HAPPY13", 0x2cc },
{ "BTN_TRIGGER_HAPPY14", 0x2cd },
{ "BTN_TRIGGER_HAPPY15", 0x2ce },
{ "BTN_TRIGGER_HAPPY16", 0x2cf },
{ "BTN_TRIGGER_HAPPY17", 0x2d0 },
{ "BTN_TRIGGER_HAPPY18", 0x2d1 },
{ "BTN_TRIGGER_HAPPY19", 0x2d2 },
{ "BTN_TRIGGER_HAPPY20", 0x2d3 },
{ "BTN_TRIGGER_HAPPY21", 0x2d4 },
{ "BTN_TRIGGER_HAPPY22", 0x2d5 },
{ "BTN_TRIGGER_HAPPY23", 0x2d6 },
{ "BTN_TRIGGER_HAPPY24", 0x2d7 },
{ "BTN_TRIGGER_HAPPY25", 0x2d8 },
{ "BTN_TRIGGER_HAPPY26", 0x2d9 },
{ "BTN_TRIGGER_HAPPY27", 0x2da },
{ "BTN_TRIGGER_HAPPY28", 0x2db },
{ "BTN_TRIGGER_HAPPY29", 0x2dc },
{ "BTN_TRIGGER_HAPPY30", 0x2dd },
{ "BTN_TRIGGER_HAPPY31", 0x2de },
{ "BTN_TRIGGER_HAPPY32", 0x2df },
{ "BTN_TRIGGER_HAPPY33", 0x2e0 },
{ "BTN_TRIGGER_HAPPY34", 0x2e1 },
{ "BTN_TRIGGER_HAPPY35", 0x2e2 },
{ "BTN_TRIGGER_HAPPY36", 0x2e3 },
{ "BTN_TRIGGER_HAPPY37", 0x2e4 },
{ "BTN_TRIGGER_HAPPY38", 0x2e5 },
{ "BTN_TRIGGER_HAPPY39", 0x2e6 },
{ "BTN_TRIGGER_HAPPY40", 0x2e7 },
#endif
{ "LAST", -1 },
};

382
read_conf_file.c Normal file
View File

@ -0,0 +1,382 @@
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/select.h>
#include <linux/input.h>
#include "read_conf_file.h"
#include <assert.h>
/****************************************************************
* Defines
****************************************************************/
#define die(str, args...) do { \
perror(str); \
return(EXIT_FAILURE); \
} while(0)
#define DEBUG_READ_CONF_FILE_PRINTF (0)
#if (DEBUG_READ_CONF_FILE_PRINTF)
#define READ_CONF_FILE_PRINTF(...) printf(__VA_ARGS__);
#else
#define READ_CONF_FILE_PRINTF(...)
#endif
/****************************************************************
* Extern variables
****************************************************************/
extern key_names_s key_names[];
/****************************************************************
* Static variables
****************************************************************/
static STRUCT_MAPPED_GPIO * head_chained_list_mapping_gpio = NULL;
static int count_valid_gpios = 0;
static int gpio_pins[MAX_NUM_GPIO];
/****************************************************************
* Static functions
****************************************************************/
/* Return linux Key code from corresponding str*/
static int find_key(const char *name)
{
int i=0;
while(key_names[i].code >= 0){
if(!strncmp(key_names[i].name, name, 32))break;
i++;
}
if(key_names[i].code < 0){
i = 0;
}
return i;
}
/* Return pin idx in the array of instanciated pins */
static int get_idx_pin(int* ptr_list_gpio_pins, int size_list_gpio_pins, int pin_number_to_find){
int idx;
for (idx=0; idx<size_list_gpio_pins; idx++){
if(ptr_list_gpio_pins[idx] == pin_number_to_find){
return idx;
}
}
// if we get here, then we did not find the pin:
idx=-1;
return idx;
}
/* function to swap data of two nodes a and b in chained list */
static void swap(STRUCT_MAPPED_GPIO *a, STRUCT_MAPPED_GPIO *b)
{
STRUCT_MAPPED_GPIO temp;
memcpy(&temp, a, sizeof(STRUCT_MAPPED_GPIO));
memcpy(a, b, sizeof(STRUCT_MAPPED_GPIO));
memcpy(b, &temp, sizeof(STRUCT_MAPPED_GPIO));
b->next_mapped_gpio = a->next_mapped_gpio;
a->next_mapped_gpio = b;
}
/* Bubble sort the given linked list */
static void bubbleSort(STRUCT_MAPPED_GPIO *head)
{
int swapped, i;
STRUCT_MAPPED_GPIO *ptr1 = head;
STRUCT_MAPPED_GPIO *lptr = NULL;
/* Checking for empty list */
if (ptr1 == NULL)
return;
do
{
swapped = 0;
ptr1 = head;
while (ptr1->next_mapped_gpio != lptr)
{
if (ptr1->nb_simultaneous_pins < ptr1->next_mapped_gpio->nb_simultaneous_pins)
{
swap(ptr1, ptr1->next_mapped_gpio);
swapped = 1;
}
ptr1 = ptr1->next_mapped_gpio;
}
lptr = ptr1;
}
while (swapped);
}
/* Push new node in chained list */
static void push(STRUCT_MAPPED_GPIO ** head, STRUCT_MAPPED_GPIO * new_mapping) {
STRUCT_MAPPED_GPIO ** current = head;
while (*current != NULL) {
current = &(*current)->next_mapped_gpio;
}
/* now we can add a new variable */
*current = malloc(sizeof(STRUCT_MAPPED_GPIO));
memcpy(*current, new_mapping, sizeof(STRUCT_MAPPED_GPIO));
(*current)->next_mapped_gpio = NULL;
}
/****************************************************************
* Public functions
****************************************************************/
void get_mapping_from_conf_file(STRUCT_MAPPED_GPIO ** chained_list_mapping,
int* nb_valid_gpios, int ** valid_gpio_pins){
/* Variables */
READ_CONF_FILE_PRINTF("Reading the config file:\n");
FILE *fp;
char ln[MAX_LN_LENGTH];
int lnno = 0;
char conffile[80];
bool pins_declaration_line = true;
/* search for the conf file in ~/.funkey_gpio_mapping.conf and /etc/funkey_gpio_mapping.conf */
sprintf(conffile, "%s/.funkey_gpio_mapping.conf", getenv("HOME"));
fp = fopen(conffile, "r");
if(!fp){
fp = fopen("/etc/funkey_gpio_mapping.conf", "r");
if(!fp){
fp = fopen("./funkey_gpio_mapping.conf", "r");
if(!fp){
perror(conffile);
perror("/etc/funkey_gpio_mapping.conf");
perror("./funkey_gpio_mapping.conf");
}
sprintf(conffile, "./funkey_gpio_mapping.conf");
}
else{
sprintf(conffile, "/etc/funkey_gpio_mapping.conf");
}
}
if(fp){
READ_CONF_FILE_PRINTF("Config file found at %s\n", conffile);
}
/* Main loop to read conf file (purposely exploded and not in multiple sub-functions) */
while(fp && !feof(fp)){
if(fgets(ln, MAX_LN_LENGTH, fp)){
lnno++;
if(strlen(ln) > 1){
if(ln[0]=='#')continue;
READ_CONF_FILE_PRINTF("\nCurrent line : %s\n", ln);
// ************ Pins declaration ************
if(pins_declaration_line){
char* token;
int token_int;
//count nb valid GPIOs and store them
token = strtok(ln, ",");
while(token != NULL){
token_int = atoi(token);
if(token_int || !strcmp(token, "0")){
gpio_pins[count_valid_gpios] = token_int;
count_valid_gpios++;
READ_CONF_FILE_PRINTF("GPIO %d declared\n", token_int);
}
else{
READ_CONF_FILE_PRINTF("Could not declare GPIO: %s\n", token);
}
token = strtok(NULL, ",");
}
pins_declaration_line = false;
}
// ************ Pins mapping ************
else{
STRUCT_MAPPED_GPIO cur_gpio_mapping;
char* end_ln;
char* token_comma;
char * current_arg;
int cur_arg_idx = MAPPING_ARG_PINS;
int idx_pin = 0;
int cur_pin;
bool add_current_mapping = true;
token_comma = strtok_r(ln, ",", &end_ln);
while(token_comma != NULL && cur_arg_idx < NB_MAPPING_ARG_NAMES && add_current_mapping){
current_arg= token_comma;
//remove_initial_spaces:
while(*current_arg==' ' && *current_arg!=0){current_arg++;}
READ_CONF_FILE_PRINTF(" Current arg: %s\n", current_arg);
//Handle current mapping arg
switch(cur_arg_idx){
case MAPPING_ARG_PINS:
//count nb valid GPIOs and store them
;char* end_arg;
char * token_plus = strtok_r(current_arg, "+", &end_arg);
while(token_plus != NULL){
cur_pin = atoi(token_plus);
if(cur_pin || !strcmp(token_plus, "0")){
int idx_cur_pin = get_idx_pin(gpio_pins, count_valid_gpios, cur_pin);
if(idx_cur_pin == -1){
READ_CONF_FILE_PRINTF(" Could not find GPIO: %s in previously instanciated GPIOs\n", token_plus);
add_current_mapping = false;
break;
}
cur_gpio_mapping.pins_idx[idx_pin] = idx_cur_pin;
idx_pin++;
READ_CONF_FILE_PRINTF(" GPIO %d in current mapping\n", cur_pin);
}
else{
READ_CONF_FILE_PRINTF(" Could not find GPIO: %s\n", token_plus);
add_current_mapping = false;
break;
}
token_plus = strtok_r(NULL, "+", &end_arg);//strtok_r(NULL, ",");
}
cur_gpio_mapping.nb_simultaneous_pins = idx_pin;
break;
case MAPPING_ARG_TYPE:
if(!strcmp(current_arg, "KEYBOARD")){
cur_gpio_mapping.type_mapping = TYPE_MAPPING_KEYBOARD;
}
else if(!strcmp(current_arg, "SHELL_COMMAND")){
cur_gpio_mapping.type_mapping = TYPE_MAPPING_SHELL_COMMAND;
}
else{
READ_CONF_FILE_PRINTF(" %s is not a valid mapping type\n", current_arg);
add_current_mapping = false;
break;
}
break;
case MAPPING_ARG_VALUE:
switch (cur_gpio_mapping.type_mapping){
case TYPE_MAPPING_KEYBOARD:
cur_gpio_mapping.key_value = find_key(current_arg);
if(!cur_gpio_mapping.key_value){
READ_CONF_FILE_PRINTF(" Could not find Key: %s\n", current_arg);
add_current_mapping = false;
}
break;
case TYPE_MAPPING_SHELL_COMMAND:
cur_gpio_mapping.shell_command = malloc(strlen(current_arg)*sizeof(char));
strcpy(cur_gpio_mapping.shell_command, current_arg);
break;
default:
READ_CONF_FILE_PRINTF(" %d is not a valid mapping type\n", cur_gpio_mapping.type_mapping);
add_current_mapping = false;
break;
}
break;
case MAPPING_ARG_STR_HELP_PIN_NAME:
if(!strlen(current_arg)) continue;
cur_gpio_mapping.pin_help_str = malloc(strlen(current_arg)*sizeof(char));
strcpy(cur_gpio_mapping.pin_help_str, current_arg);
break;
case MAPPING_ARG_STR_HELP_PIN_FCT:
if(!strlen(current_arg)) continue;
cur_gpio_mapping.fct_help_str = malloc(strlen(current_arg)*sizeof(char));
strcpy(cur_gpio_mapping.fct_help_str, current_arg);
break;
default:
break;
}
//next arg
token_comma = strtok_r(NULL, ",", &end_ln);
cur_arg_idx++;
}
if(add_current_mapping){
push(&head_chained_list_mapping_gpio, &cur_gpio_mapping);
READ_CONF_FILE_PRINTF("Current Mapping added successfully\n\n");
}
else{
READ_CONF_FILE_PRINTF("Current Mapping not added\n\n");
}
}
}
}
}
READ_CONF_FILE_PRINTF("Sorting Chained list...\n");
bubbleSort(head_chained_list_mapping_gpio);
print_all_chained_list(head_chained_list_mapping_gpio);
print_gpios(gpio_pins, count_valid_gpios);
if(fp){
fclose(fp);
}
/* Return parameters */
*chained_list_mapping = head_chained_list_mapping_gpio;
*nb_valid_gpios = count_valid_gpios;
*valid_gpio_pins = gpio_pins;
}
/* Print all chained list content */
void print_all_chained_list(STRUCT_MAPPED_GPIO * head){
STRUCT_MAPPED_GPIO * current = head;
int idx = 0;
READ_CONF_FILE_PRINTF("Printing Chained list:\n ");
while (current != NULL) {
READ_CONF_FILE_PRINTF("Chained list Mapping GPIOs, idx: %d\n", idx);
print_chained_list_node(current);
idx++;
current = current->next_mapped_gpio;
}
}
/* Print one chained list node */
void print_chained_list_node(STRUCT_MAPPED_GPIO * node){
// Print Pins:
if(node->nb_simultaneous_pins > 1){
READ_CONF_FILE_PRINTF(" %d Simultaneous pins at following idx: [", node->nb_simultaneous_pins);
int i;
for (i=0; i < node->nb_simultaneous_pins; i++){
READ_CONF_FILE_PRINTF("%d%s", node->pins_idx[i], (i==node->nb_simultaneous_pins-1)?"]\n":",");
}
}
else{
READ_CONF_FILE_PRINTF(" idx pin: %d\n", node->pins_idx[0]);
}
// Type mapping and Value
if (node->type_mapping == TYPE_MAPPING_KEYBOARD){
READ_CONF_FILE_PRINTF(" Type mapping: TYPE_MAPPING_KEYBOARD\n");
READ_CONF_FILE_PRINTF(" Key: %d\n", node->key_value);
}
else if (node->type_mapping == TYPE_MAPPING_SHELL_COMMAND){
READ_CONF_FILE_PRINTF(" Type mapping: TYPE_MAPPING_SHELL_COMMAND\n");
READ_CONF_FILE_PRINTF(" Shell command: %s\n", node->shell_command);
}
// Pin help String
if(node->pin_help_str[0]){
READ_CONF_FILE_PRINTF(" Pins: %s\n", node->pin_help_str);
}
// Function help String
if(node->fct_help_str[0]){
READ_CONF_FILE_PRINTF(" Function: %s\n", node->fct_help_str);
}
}
void print_gpios(int * valid_gpio_pins, int nb_valid_gpios){
READ_CONF_FILE_PRINTF("GPIO pins:\n[");
for(int i = 0; i< nb_valid_gpios; i++) {
READ_CONF_FILE_PRINTF("%d%s", valid_gpio_pins[i], (i==nb_valid_gpios-1)?"]\n":",");
}
}

74
read_conf_file.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef _READ_CONF_FILE_H_
#define _READ_CONF_FILE_H_
/****************************************************************
* Includes
****************************************************************/
#include <stdbool.h>
/****************************************************************
* Defines
****************************************************************/
#define MAX_NUM_GPIO 32
#define MAX_SIMULTANEOUS_GPIO 12
#define MAX_LENGTH_STR_PINS 48
#define MAX_LENGTH_STR_TYPE 16
#define MAX_LENGTH_STR_VALUE 256
#define MAX_LENGTH_STR_HELP_PIN_NAME 48
#define MAX_LENGTH_STR_HELP_PIN_FCT 256
#define MAX_LN_LENGTH (MAX_LENGTH_STR_PINS+\
MAX_LENGTH_STR_TYPE+\
MAX_LENGTH_STR_VALUE+\
MAX_LENGTH_STR_HELP_PIN_NAME+\
MAX_LENGTH_STR_HELP_PIN_FCT)
typedef enum{
TYPE_MAPPING_KEYBOARD,
TYPE_MAPPING_SHELL_COMMAND,
NB_TYPE_MAPPING,
} ENUM_TYPE_MAPPING;
typedef enum{
MAPPING_ARG_PINS = 0,
MAPPING_ARG_TYPE,
MAPPING_ARG_VALUE,
MAPPING_ARG_STR_HELP_PIN_NAME,
MAPPING_ARG_STR_HELP_PIN_FCT,
NB_MAPPING_ARG_NAMES,
} ENUM_MAPPING_ARGS_NAMES;
typedef struct{
char name[32];
int code;
}key_names_s;
typedef struct gpio_mapping_s{
int pins_idx[MAX_SIMULTANEOUS_GPIO];
int nb_simultaneous_pins;
ENUM_TYPE_MAPPING type_mapping;
int key_value;
char *shell_command;
char *pin_help_str;
char *fct_help_str;
struct gpio_mapping_s * next_mapped_gpio;
bool activated;
}STRUCT_MAPPED_GPIO;
/****************************************************************
* Public functions
****************************************************************/
void get_mapping_from_conf_file(STRUCT_MAPPED_GPIO ** chained_list_mapping,
int* nb_valid_gpios, int ** valid_gpio_pins);
void print_all_chained_list(STRUCT_MAPPED_GPIO * head);
void print_chained_list_node(STRUCT_MAPPED_GPIO * node);
void print_gpios(int * valid_gpio_pins, int nb_valid_gpios);
#endif //_READ_CONF_FILE_H_

230
uinput.c Normal file
View File

@ -0,0 +1,230 @@
/**** uinput.c *****************************/
/* M. Moller 2013-01-16 */
/* Universal RPi GPIO keyboard daemon */
/*******************************************/
/*
Copyright (C) 2013 Michael Moller.
This file is part of the Universal Raspberry Pi GPIO keyboard daemon.
This is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>
//#include "config.h"
//include "daemon.h"
#include "uinput.h"
static int sendRel(int dx, int dy);
static int sendSync(void);
static struct input_event uidev_ev;
static int uidev_fd;
/*static keyinfo_s lastkey;*/
#define die(str, args...) do { \
perror(str); \
return(EXIT_FAILURE); \
} while(0)
#define DEBUG_UINPUT_PRINTF (0)
#if DEBUG_UINPUT_PRINTF
#define UINPUT_PRINTF(...) printf(__VA_ARGS__);
#else
#define UINPUT_PRINTF(...)
#endif
int init_uinput(void)
{
int fd;
struct uinput_user_dev uidev;
int i;
fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if(fd < 0)
die("/dev/uinput");
if(ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_EVBIT, EV_REP) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_EVBIT, EV_REL) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_RELBIT, REL_X) < 0)
die("error: ioctl");
if(ioctl(fd, UI_SET_RELBIT, REL_Y) < 0)
die("error: ioctl");
/* don't forget to add all the keys! */
for(i=0; i<256; i++){
if(ioctl(fd, UI_SET_KEYBIT, i) < 0)
die("error: ioctl");
}
memset(&uidev, 0, sizeof(uidev));
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample");
uidev.id.bustype = BUS_USB;
uidev.id.vendor = 0x1;
uidev.id.product = 0x1;
uidev.id.version = 1;
/*if(write(fd, &uidev, sizeof(uidev)) < 0)
die("error: write");*/
if(ioctl(fd, UI_DEV_SETUP, &uidev) < 0)
die("error: ioctl");
if(ioctl(fd, UI_DEV_CREATE) < 0)
die("error: ioctl");
uidev_fd = fd;
sleep(1);
return 0;
}
int test_uinput(void)
{
int dx, dy;
int i,k;
//srand(time(NULL));
int op = 1;
while(1) {
//switch(rand() % 4) {
switch(op) {
case 0:
dx = -10;
dy = -1;
break;
case 1:
dx = 10;
dy = 1;
break;
case 2:
dx = -1;
dy = 10;
break;
case 3:
dx = 1;
dy = -10;
break;
}
/*k = send_gpio_keys(21, 1);
sendKey(k, 0);*/
sendKey(KEY_D, 0);
for(i = 0; i < 20; i++) {
//sendKey(KEY_D, 1);
//sendKey(KEY_D, 0);
sendRel(dx, dy);
usleep(15000);
}
sleep(10);
}
}
int close_uinput(void)
{
sleep(2);
if(ioctl(uidev_fd, UI_DEV_DESTROY) < 0)
die("error: ioctl");
close(uidev_fd);
return 0;
}
int sendKey(int key, int value)
{
struct input_event ie;
//memset(&uidev_ev, 0, sizeof(struct input_event));
//gettimeofday(&uidev_ev.time, NULL);
ie.type = EV_KEY;
ie.code = key;
ie.value = value;
ie.time.tv_sec = 0;
ie.time.tv_usec = 0;
UINPUT_PRINTF("sendKey: %d = %d\n", key, value);
if(write(uidev_fd, &ie, sizeof(struct input_event)) < 0)
die("error: write");
sendSync();
return 0;
}
int sendKeyAndStopKey(int key)
{
sendKey(key, 1);
sendKey(key, 0);
return 0;
}
static int sendRel(int dx, int dy)
{
memset(&uidev_ev, 0, sizeof(struct input_event));
uidev_ev.type = EV_REL;
uidev_ev.code = REL_X;
uidev_ev.value = dx;
if(write(uidev_fd, &uidev_ev, sizeof(struct input_event)) < 0)
die("error: write");
memset(&uidev_ev, 0, sizeof(struct input_event));
uidev_ev.type = EV_REL;
uidev_ev.code = REL_Y;
uidev_ev.value = dy;
if(write(uidev_fd, &uidev_ev, sizeof(struct input_event)) < 0)
die("error: write");
sendSync();
return 0;
}
static int sendSync(void)
{
UINPUT_PRINTF("sendSync\n");
//memset(&uidev_ev, 0, sizeof(struct input_event));
struct input_event ie;
ie.type = EV_SYN;
ie.code = SYN_REPORT;
ie.value = 0;
ie.time.tv_sec = 0;
ie.time.tv_usec = 0;
if(write(uidev_fd, &ie, sizeof(struct input_event)) < 0)
die("error: sendSync - write");
return 0;
}

37
uinput.h Normal file
View File

@ -0,0 +1,37 @@
/**** uinput.h *****************************/
/* M. Moller 2013-01-16 */
/* Universal RPi GPIO keyboard daemon */
/*******************************************/
/*
Copyright (C) 2013 Michael Moller.
This file is part of the Universal Raspberry Pi GPIO keyboard daemon.
This is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
*/
#ifndef _UINPUT_H_
#define _UINPUT_H_
int init_uinput(void);
int test_uinput(void);
int close_uinput(void);
int send_gpio_keys(int gpio, int value);
int sendKey(int key, int value);
int sendKeyAndStopKey(int key);
//void get_last_key(keyinfo_s *kp);
#endif //_UINPUT_H_