szymon hrapkowicz
szymon hrapkowicz

Reputation: 143

Read from /dev/input

I have an USB RFID card reader which emulates keyboard. So when i put an card to it i see the string on a terminal window -i.e. "0684a24bc1"

But i would like to read it in my C program. There is no problem when i use: scanf("%s",buff);

But when i use below code i got a lot (about 500 bytes) not recognized data. Why? I would like to have non blocking read.

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>

int main(int argc, char ** argv) {
  int fd;
  char buf[256];

  fd = open("/dev/input/event3", O_RDWR | O_NOCTTY | O_NDELAY);
  if (fd == -1) {
    perror("open_port: Unable to open /dev/ttyAMA0 - ");
    return(-1);
  }

  // Turn off blocking for reads, use (fd, F_SETFL, FNDELAY) if you want that
  fcntl(fd, F_SETFL, 0);


  }

while(1){
  n = read(fd, (void*)buf, 255);
  if (n < 0) {
    perror("Read failed - ");
    return -1;
  } else if (n == 0) printf("No data on port\n");
  else {
    buf[n] = '\0';
    printf("%i bytes read : %s", n, buf);
  }
sleep(1);
printf("i'm still doing something");

}
  close(fd);
  return 0;
}

Upvotes: 11

Views: 48073

Answers (4)

Rolas
Rolas

Reputation: 143

#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <stdbool.h>

int main(int argc, char *argv[])
{
    int timeout_ms = 5000;
    char input_dev[] = "/dev/input/event17\0";
    int st;
    int ret;
    struct pollfd fds[1];
    
    fds[0].fd = open(input_dev, O_RDONLY|O_NONBLOCK);
    
    if(fds[0].fd<0)
    {
        printf("error unable open for reading '%s'\n",input_dev);
        return(0);
    }
    
    const int input_size = 4096;
    unsigned char input_data[input_size];
    memset(input_data,0,input_size);
    
    fds[0].events = POLLIN;
    
    int exit_on_key_press_count = 10;

    while(true)
    {
        ret = poll(fds, 1, timeout_ms);
    
        if(ret>0)
        {
            if(fds[0].revents)
            {
                ssize_t r = read(fds[0].fd,input_data,input_size);
                
                if(r<0)
                {
                    printf("error %d\n",(int)r);
                    break;
                }
                else
                {
                    printf("total bytes read %d/%d\n",(int)r,input_size);

                    for(int i = 0; i<r;i++)
                    {
                        printf("%02X ",(unsigned char)input_data[i]);
                    }
                    printf("\n");
                    memset(input_data,0,input_size);

                    exit_on_key_press_count--;
                    if(exit_on_key_press_count<1)
                        break;
                }
            }
            else
            {
                printf("error\n");
            }
        }
        else
        {
            printf("timeout\n");
        }
    }

    close(fds[0].fd);
    return 0;
}

$ sudo ./keypressed

total bytes read 72/4096

35 49 C9 5C 00 00 00 00 38 27 0B 00 00 00 00 00 04 00 04 00 5A 00 07 00 35 49 C9 5C 00 00 00 00 38 27 0B 00 00 00 00 00 01 00 50 00 01 00 00 00 35 49 C9 5C 00 00 00 00 38 27 0B 00 00 00 00 00 00 00 00 00 00 00 00 00

This is raw data, to convert to some key, I need to read 'Linux input documentation' link above...

Upvotes: 3

FALTO
FALTO

Reputation: 15

Combined answers of Hasturkun and Rolas

#include <fcntl.h>
#include <unistd.h>
#include <poll.h>
#include <stdbool.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
struct input_event {
    struct timeval time;
    unsigned short type;
    unsigned short code;
    unsigned int value;
};
int main(int argc, char *argv[])
{
    const int timeout_ms = -1;
    char* input_dev = argv[1];
    int st;
    int ret;
    struct pollfd fds[1];
    fds[0].fd = open(input_dev, O_RDONLY|O_NONBLOCK);
    if(fds[0].fd<0)
    {
        printf("error unable open for reading '%s'\n",input_dev);
        return 1;
    }
    const int input_size = sizeof(struct input_event);
    printf("input_size=%d\n", input_size);
    struct input_event* input_data;
    memset(input_data,0,input_size);
    fds[0].events = POLLIN;
    while(true)
    {
        ret = poll(fds, 1, timeout_ms);
        if(ret>0)
        {
            if(fds[0].revents)
            {
                ssize_t r = read(fds[0].fd,input_data,input_size);
                if(r<0)
                {
                    printf("error %d\n",(int)r);
                    break;
                }
                else
                {
            printf("time=%ld.%06lu type=%hu code=%hu value=%u\n", input_data->time.tv_sec, input_data->time.tv_usec, input_data->type, input_data->code, input_data->value);
                    memset(input_data,0,input_size);
                }
            }
            else
            {
                printf("error\n");
            }
        }
        else
        {
            printf("timeout\n");
        }
    }
    close(fds[0].fd);
    return 0;
}
$ sudo ./a.out /dev/input/event8
input_size=24
time=1715889657.362340 type=1 code=28 value=1
time=1715889657.362340 type=0 code=0 value=0
time=1715889657.618673 type=1 code=28 value=2
time=1715889657.618673 type=0 code=0 value=1
time=1715889657.658718 type=1 code=28 value=2
time=1715889657.658718 type=0 code=0 value=1
time=1715889657.698677 type=1 code=28 value=2
time=1715889657.698677 type=0 code=0 value=1
time=1715889657.738673 type=1 code=28 value=2
time=1715889657.738673 type=0 code=0 value=1
time=1715889657.748686 type=1 code=28 value=0
time=1715889657.748686 type=0 code=0 value=0

Upvotes: 0

ulidtko
ulidtko

Reputation: 15570

Your code is clearly wrong at opening an event device under /dev/input/. Even your error message is contradicting the choice:

perror("open_port: Unable to open /dev/ttyAMA0 - ");

Reads from /dev/input/eventN files return binary data with event descriptions (like pointer moving or button presses), not text. Your probably want to open some sort of serial emulation device instead.


10-year answer anniversary edit 🎉

Consider How to debug the input from an input-device (/dev/input/event*) on Unix.SE.

There's an easy to use reference decoder for /dev/input/eventN content. You can use it to verify and compare your code against.

Upvotes: -1

Hasturkun
Hasturkun

Reputation: 36412

According to the Linux input documentation, section 5, the /dev/input/eventX devices return data as following:

You can use blocking and nonblocking reads, also select() on the /dev/input/eventX devices, and you'll always get a whole number of input events on a read. Their layout is:

struct input_event {
      struct timeval time;
      unsigned short type;
      unsigned short code;
      unsigned int value; };

'time' is the timestamp, it returns the time at which the event happened. Type is for example EV_REL for relative moment, EV_KEY for a keypress or release. More types are defined in include/linux/input.h.

'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete list is in include/linux/input.h.

'value' is the value the event carries. Either a relative change for EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for release, 1 for keypress and 2 for autorepeat.

Upvotes: 18

Related Questions