I've searched for quite some time now for a solution to my problem.
I'd like to read RFID tags on my Raspberry, but I want to do it in C-code, as the rest of my project is written in C.
I have a few questions to the following C-code I found here on stackoverflow.com:
What .h includes do I need for the code below?
Where is the interface setup, that I'm using? (/dev/ttyAMA0)
Please help me to get this code snippet working right, as it's been holding me up for a few days already.
char read_rfid(char* rfid_num) {
fd_set input_fdset;
ssize_t length;
int done;
for(done=0; done < 14; ) {
FD_ZERO(&input_fdset);
FD_SET(fd,&input_fdset);
if(select(fd+1 ,&input_fdset, NULL,NULL,NULL) == -1) {
if (errno == EAGAIN) continue;
perror("Terminal select() failed");
return -1;
}
if(FD_ISSET(fd,&input_fdset)) {
if((length = read(fd,rfid_num+done,14-done)) == -1) {
if (errno == EAGAIN) continue;
perror("Terminal: read() failed");
return -1;
}
write(STDOUT_FILENO,rfid_num+done,length);
done += length;
}
}
return 0;
}
int setupRS232()
{
struct termios term_attr;
if((fd = open(RFID,O_RDWR)) == -1)
{
perror("Can't open Device");
return(1);
}
if(tcgetattr(fd,&term_attr) != 0)
{
perror("terminal: tcgetattr() failed");
return(1);
}
term_attr.c_cflag = BAUD|CS8|CRTSCTS|CLOCAL|CREAD;
term_attr.c_iflag = 0;
term_attr.c_oflag = 0;
term_attr.c_lflag = 0;
if(tcsetattr(fd,TCSAFLUSH,&term_attr) != 0)
{
perror("terminal: tcsetattr() failed");
return(1);
}
}
int main(int argc, char** argv)
{
char rfid_num[14];
int i;
if(setupRS232() == 1)
return(1);
puts("Waiting for transponder...");
read_rfid(rfid_num);
for(i=0;i<20;i++)
{
printf("%x\n",rfid_num[i]);
}
}
#include <unistd.h> // for read & write functions
#include <sys/select.h> // fd_set functions
#include <stdio.h> // for perror & printf family
#include <sys/types.h> // for open related function
#include <sys/stat.h> // for open related function
#include <fcntl.h> // for open related function
#include <termios.h> // for terminal functions
#include <errno.h> // for error code
#define RFID "path_to_rfid" // FIXME <- you should set this properly
char read_rfid(char* rfid_num, int fd)
{
fd_set input_fdset;
ssize_t length;
int done;
for(done=0; done < 14; ) {
FD_ZERO(&input_fdset);
FD_SET(fd,&input_fdset);
if(select(fd+1 ,&input_fdset, NULL,NULL,NULL) == -1) {
perror("Terminal select() failed");
return -1;
}
if(FD_ISSET(fd,&input_fdset)) {
if((length = read(fd,rfid_num+done,14-done)) == -1) {
perror("Terminal: read() failed");
return -1;
}
write(STDOUT_FILENO,rfid_num+done,length);
done += length;
}
}
return 0;
}
int setupRS232()
{
struct termios term_attr;
int fd = 0;
if((fd = open(RFID,O_RDWR)) == -1) {
perror("Can't open Device");
return(-1);
}
if(tcgetattr(fd,&term_attr) != 0)
{
perror("terminal: tcgetattr() failed");
close(fd);
return(-1);
}
term_attr.c_cflag = CBAUD|CS8|CRTSCTS|CLOCAL|CREAD;
term_attr.c_iflag = 0;
term_attr.c_oflag = 0;
term_attr.c_lflag = 0;
if(tcsetattr(fd,TCSAFLUSH,&term_attr) != 0) {
perror("terminal: tcsetattr() failed");
close(fd);
return(-1);
}
return (fd);
}
int main(int argc, char** argv)
{
char rfid_num[14];
int i;
int fd;
if((fd = setupRS232()) == -1) {
return(-1);
}
puts("Waiting for transponder...");
read_rfid(rfid_num, fd);
for(i=0;i<20;i++) {
printf("%x\n",rfid_num[i]);
}
return 0;
}
Now your code is ready to be compiled, at least in my machine I could compile with no errors.
Related
I coded a little tool to show the number of logical blocks of a file and the physical blocks mapped. Using ictl FIBMAP system call, I'm looking on logical-to-physicaal block mapping. So I used an old FIBMAP ictl syscall. My question is : what are the differences between FIBMAP and FIEMAP ? Do you have some tips to deep further into log-phy mapping from my code ? Furthermore, many logical blocks dont seem to map physical blocks. What is the reason ?
ÉDIT :
So I just learned that FIBMAP needs CAP_SYS_RAWIO, so only for root.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#define UNLESS(X) if (!(X))
#define ARRAY_NUM(X) sizeof(X)/sizeof(*(X))
#define ERROR(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
#define RETURN(msg) do { perror(msg); return errno; } while (0)
#define XFREE(X) (X) do { free(X); X = NULL; } while (0)
int get_blck(int fd, int log_block){
int res;
res = ioctl(fd, FIBMAP, &log_block);
if (res < 0) {
ERROR("ioctl FIBMAP failed !\n");
}
return log_block;
}
/* we get the number of logical blocks */
int get_nbr_blcks(int fd){
struct stat buff;
int res;
res = fstat(fd, &buff);
if (res < 0) {
ERROR("fstat error !\n");
}
return buff.st_blocks;
}
/* We print the physical blocks sorted */
void print_blcks(int fd){
int nbr_blcks;
nbr_blcks = get_nbr_blcks(fd);
if (nbr_blcks < 0) {
ERROR("get_nbr_blcks failed!\n");
}
if (nbr_blcks == 0) {
ERROR("no allocated blocks\n");
} else if (nbr_blcks == 1) {
printf("1 block\n\n");
} else {
printf("%d blocks\n\n", nbr_blcks);
}
for (int i = 0; i < nbr_blcks; i++) {
int phy_blck;
phy_blck = get_blck(fd, i);
if (phy_blck < 0) {
ERROR("get_blck failed!\n");
}
/* many [%d, 0] in my case... Where are they */
//if (!phys_block)
//continue;
printf("[%u, %u] ", i, phy_blck);
}
putchar('\n');
}
int main(int argc, char *argv[])
{
int fd;
UNLESS(argc == 2) {
printf("usage: %s file\n", argv[0]);
return 1;
}
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
RETURN("open failed !\n");
}
print_blcks(fd);
return 0;
}
I have a working code with performs asynchronous DNS resolution with c-ares library calls. The program uses select to monitor file descriptors up to a maximum of FD_SETSIZE which is 1024 on my system. I want to use many more file descriptors so want to rewrite the code to use epoll instead of select.
Here is the select based function of my current program:
static void
wait_ares(ares_channel channel)
{
struct timeval *tvp, tv;
fd_set read_fds, write_fds;
int nfds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
nfds = ares_fds(channel, &read_fds, &write_fds);
if (nfds > 0) {
tvp = ares_timeout(channel, NULL, &tv);
select(nfds, &read_fds, &write_fds, NULL, tvp);
ares_process(channel, &read_fds, &write_fds);
}
}
I've done some googling before posting my question and I've found out that to implement this with epoll I can no longer use ares_fds, ares_timeout and ares_process but must use ares_getsock() and ares_process_fd() instead. But further than that I have no idea how to do this and can't find any example codes using epoll with c-ares. Can anyone modify the code provided below to use epoll instead of select? Or at least give me some pointers to get me started?
#include <ares.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#define MAXWAITING 1000 /* Max. number of parallel DNS queries */
#define MAXTRIES 3 /* Max. number of tries per domain */
#define TIMEOUT 3000 /* Max. number of ms for first try */
#define SERVERS "1.0.0.1,8.8.8.8" /* DNS server to use (Cloudflare & Google) */
static int nwaiting;
static void
state_cb(void *data, int s, int read, int write)
{
//printf("Change state fd %d read:%d write:%d\n", s, read, write);
}
static void
callback(void *arg, int status, int timeouts, struct hostent *host)
{
nwaiting--;
if(!host || status != ARES_SUCCESS){
fprintf(stderr, "Failed to lookup %s\n", ares_strerror(status));
return;
}
char ip[INET6_ADDRSTRLEN];
if (host->h_addr_list[0] != NULL){
inet_ntop(host->h_addrtype, host->h_addr_list[0], ip, sizeof(ip));
printf("%s\n%s\n", host->h_name, ip);
}
}
static void
wait_ares(ares_channel channel)
{
struct timeval *tvp, tv;
fd_set read_fds, write_fds;
int nfds;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
nfds = ares_fds(channel, &read_fds, &write_fds);
if (nfds > 0) {
tvp = ares_timeout(channel, NULL, &tv);
select(nfds, &read_fds, &write_fds, NULL, tvp);
ares_process(channel, &read_fds, &write_fds);
}
}
int
main(int argc, char *argv[])
{
FILE * fp;
char domain[128];
size_t len = 0;
ssize_t read;
ares_channel channel;
int status, done = 0;
int optmask;
status = ares_library_init(ARES_LIB_INIT_ALL);
if (status != ARES_SUCCESS) {
printf("ares_library_init: %s\n", ares_strerror(status));
return 1;
}
struct ares_options options = {
.timeout = TIMEOUT, /* set first query timeout */
.tries = MAXTRIES /* set max. number of tries */
};
optmask = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES;
status = ares_init_options(&channel, &options, optmask);
if (status != ARES_SUCCESS) {
printf("ares_init_options: %s\n", ares_strerror(status));
return 1;
}
status = ares_set_servers_csv(channel, SERVERS);
if (status != ARES_SUCCESS) {
printf("ares_set_servers_csv: %s\n", ares_strerror(status));
return 1;
}
fp = fopen(argv[1], "r");
if (!fp)
exit(EXIT_FAILURE);
do {
if (nwaiting >= MAXWAITING || done) {
do {
wait_ares(channel);
} while (nwaiting > MAXWAITING);
}
if (!done) {
if (fscanf(fp, "%127s", domain) == 1) {
ares_gethostbyname(channel, domain, AF_INET, callback, NULL);
nwaiting++;
} else {
fprintf(stderr, "done sending\n");
done = 1;
}
}
} while (nwaiting > 0);
ares_destroy(channel);
ares_library_cleanup();
fclose(fp);
return 0;
}
The program requires a file with a domain name on each line to work.
This is what I ended up coming up with.
#include <ares.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <errno.h>
#define MAXWAITING 1000 /* Max. number of parallel DNS queries */
#define MAXTRIES 3 /* Max. number of tries per domain */
#define TIMEOUT 3000 /* Max. number of ms for first try */
#define DNS_MAX_EVENTS 10000
#define DNS_MAX_SERVERS 2
#define SERVERS "1.0.0.1,8.8.8.8" /* DNS server to use (Cloudflare & Google) */
static int nwaiting;
ares_socket_t dns_client_fds[ARES_GETSOCK_MAXNUM] = {0};
struct epoll_event ev, events[DNS_MAX_EVENTS];
int i,bitmask,nfds, epollfd, timeout, fd_count, ret;
static void
state_cb(void *data, int s, int read, int write)
{
//printf("Change state fd %d read:%d write:%d\n", s, read, write);
}
static void
callback(void *arg, int status, int timeouts, struct hostent *host)
{
nwaiting--;
if(!host || status != ARES_SUCCESS){
fprintf(stderr, "Failed to lookup %s\n", ares_strerror(status));
return;
}
char ip[INET6_ADDRSTRLEN];
if (host->h_addr_list[0] != NULL){
inet_ntop(host->h_addrtype, host->h_addr_list[0], ip, sizeof(ip));
printf("%s\n%s\n", host->h_name, ip);
}
}
static void
wait_ares(ares_channel channel)
{
nfds=0;
bitmask=0;
for (i =0; i < DNS_MAX_SERVERS ; i++) {
if (dns_client_fds[i] > 0) {
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, dns_client_fds[i], NULL) < 0) {
continue;
}
}
}
memset(dns_client_fds, 0, sizeof(dns_client_fds));
bitmask = ares_getsock(channel, dns_client_fds, DNS_MAX_SERVERS);
for (i =0; i < DNS_MAX_SERVERS ; i++) {
if (dns_client_fds[i] > 0) {
ev.events = 0;
if (ARES_GETSOCK_READABLE(bitmask, i)) {
ev.events |= EPOLLIN;
}
if (ARES_GETSOCK_WRITABLE(bitmask, i)) {
ev.events |= EPOLLOUT;
}
ev.data.fd = dns_client_fds[i];
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, dns_client_fds[i], &ev) < 0) {
if(errno == EEXIST) {
nfds++;
continue;
}
continue;
}
nfds++;
}
}
if(nfds==0)
{
return;
}
timeout = 1000;//millisecs
fd_count = epoll_wait(epollfd, events, DNS_MAX_EVENTS, timeout);
if (fd_count < 0) {
return;
}
if (fd_count > 0) {
for (i = 0; i < fd_count; ++i) {
ares_process_fd(channel, ((events[i].events) & (EPOLLIN) ? events[i].data.fd:ARES_SOCKET_BAD), ((events[i].events) & (EPOLLOUT)? events[i].data.fd:ARES_SOCKET_BAD));
}
} else {
ares_process_fd(channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
}
}
int
main(int argc, char *argv[])
{
FILE * fp;
char domain[128];
size_t len = 0;
ssize_t read;
ares_channel channel;
int status, done = 0;
int optmask;
status = ares_library_init(ARES_LIB_INIT_ALL);
if (status != ARES_SUCCESS) {
printf("ares_library_init: %s\n", ares_strerror(status));
return 1;
}
struct ares_options options = {
.timeout = TIMEOUT, /* set first query timeout */
.tries = MAXTRIES /* set max. number of tries */
};
optmask = ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES;
status = ares_init_options(&channel, &options, optmask);
if (status != ARES_SUCCESS) {
printf("ares_init_options: %s\n", ares_strerror(status));
return 1;
}
status = ares_set_servers_csv(channel, SERVERS);
if (status != ARES_SUCCESS) {
printf("ares_set_servers_csv: %s\n", ares_strerror(status));
return 1;
}
fp = fopen(argv[1], "r");
if (!fp)
exit(EXIT_FAILURE);
memset(dns_client_fds, 0, sizeof(dns_client_fds));
memset((char *)&ev, 0, sizeof(struct epoll_event));
memset((char *)&events[0], 0, sizeof(events));
epollfd = epoll_create(DNS_MAX_SERVERS);
if (epollfd < 0) {
perror("epoll_create: ");
}
do {
if (nwaiting >= MAXWAITING || done) {
do {
wait_ares(channel);
} while (nwaiting > MAXWAITING);
}
if (!done) {
if (fscanf(fp, "%127s", domain) == 1) {
ares_gethostbyname(channel, domain, AF_INET, callback, NULL);
nwaiting++;
} else {
fprintf(stderr, "done sending\n");
done = 1;
}
}
} while (nwaiting > 0);
ares_destroy(channel);
ares_library_cleanup();
fclose(fp);
return 0;
}
I'v written a simple C shared object library which calls v4l2(Video for Linux two) API e.g. v4l2_open(). Then I'm trying to poll() on the returned device handle but it always return POLLERR in the revents. I tried different parameters with timeout but it does not help. Here is the complete code.
/*
* libwebcam.h
*
* Created on: 13.04.2016
* Author: max
*/
#ifndef LIBWEBCAM_H_
#define LIBWEBCAM_H_
#include <stdint.h>
struct webcam
{
int fd;
uint32_t width;
uint32_t height;
uint32_t sizeimage;
uint32_t bytesperline;
uint8_t *image_buffer;
void *priv_data;
};
int webcam_open(struct webcam *w);
int webcam_close(struct webcam *w);
int webcam_take_image(struct webcam *w);
int webcam_poll(struct webcam *w);
#endif /* LIBWEBCAM_H_ */
/*
* libwebcam.c
*
* Created on: 13.04.2016
* Author: max
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <libv4l2.h>
#include <poll.h>
#include "libwebcam.h"
int webcam_open(struct webcam *w)
{
struct v4l2_capability caps;
struct v4l2_format fmt;
int dev_index;
int dev;
char buffer[255];
for (dev_index = 0; dev_index < 64; dev_index++) {
memset(&buffer, 0, sizeof(buffer));
sprintf(buffer, "/dev/video%d", dev_index);
#ifdef DEBUG
printf("libwebcam: Probing %s\n", buffer);
#endif
dev = v4l2_open(buffer, O_RDWR | O_NONBLOCK, 0);
if (dev != -1) {
memset(&caps, 0, sizeof(caps));
if (v4l2_ioctl(dev, VIDIOC_QUERYCAP, &caps) == -1) {
return -1;
}
if (caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
#ifdef DEBUG
printf("libwebcam: %s is video capture device\n", buffer);
#endif
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if(v4l2_ioctl(dev, VIDIOC_G_FMT, &fmt) == -1) {
return -1;
}
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
if(v4l2_ioctl(dev, VIDIOC_S_FMT, &fmt) == -1) {
return -1;
}
if(v4l2_ioctl(dev, VIDIOC_G_FMT, &fmt) == -1) {
return -1;
}
if(w)
{
w->fd = dev;
w->bytesperline = fmt.fmt.pix.bytesperline;
w->height = fmt.fmt.pix.height;
w->sizeimage = fmt.fmt.pix.sizeimage;
w->width = fmt.fmt.pix.width;
w->image_buffer = calloc(fmt.fmt.pix.sizeimage, sizeof(uint8_t));
if(w->image_buffer == NULL)
return -1;
w->priv_data = calloc(1, sizeof(struct pollfd));
if(w->priv_data == NULL)
return -1;
return 0;
}
else
{
errno = EINVAL;
return -1;
}
}
}
}
errno = ENODEV;
return -1;
}
int webcam_close(struct webcam *w)
{
if(w)
{
if(w->image_buffer != NULL){
free(w->image_buffer);
w->image_buffer = NULL;
}
if(w->priv_data != NULL) {
free(w->priv_data);
w->priv_data = NULL;
}
if(w->fd != -1)
if(v4l2_close(w->fd) == -1)
return -1;
return 0;
}
errno = EINVAL;
return -1;
}
int webcam_take_image(struct webcam *w)
{
if(w)
{
return v4l2_read(w->fd, w->image_buffer, w->sizeimage * sizeof(uint8_t));
}
errno = EINVAL;
return -1;
}
int webcam_poll(struct webcam *w)
{
if(w)
{
((struct pollfd *)w->priv_data)->events = POLLIN;
((struct pollfd *)w->priv_data)->revents = 0;
((struct pollfd *)w->priv_data)->fd = w->fd;
if(poll(((struct pollfd*)w->priv_data), 1, -1) == -1)
{
return -1;
}
if(((struct pollfd*)w->priv_data)->revents & POLLIN) {
#ifdef DEBUG
printf("libwebcam: Data is available...\n");
#endif
return 1;
}
if(((struct pollfd*)w->priv_data)->revents & POLLERR) {
#ifdef DEBUG
printf("libwebcam: Error in poll...\n");
#endif
return -1;
}
#ifdef DEBUG
printf("libwebcam: Timeout...\n");
#endif
return 0;
}
#ifdef DEBUG
printf("libwebcam: Struct not valid...\n");
#endif
errno = EINVAL;
return -1;
}
/*
* test.c
*
* Created on: 14.04.2016
* Author: max
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libwebcam.h>
int main(int argc, char **argv)
{
struct webcam w;
int polled;
memset(&w, 0, sizeof(w));
if(webcam_open(&w) == -1)
{
perror("Unable to find webcam");
return EXIT_FAILURE;
}
while(1)
{
polled = webcam_poll(&w);
if(polled == -1)
{
perror("Error in poll");
return EXIT_FAILURE;
}
if(polled == 1)
{
webcam_take_image(&w);
}
}
if(webcam_close(&w) == -1)
{
perror("Unable to close webcam");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Can anyone tell me what is going on in the code?
I tested your code, and on my system the poll call is returning 0. From the man page, "A value of 0 indicates that the call timed out and no file descriptors were ready." So you should test for 0 in addition to -1 and 1.
I don't know why it fills in revents with POLLERR, but I would only check the resulting revents field if poll returned 1.
Also, not all V4L2 devices support read(), so you should check that your device supports it by testingcaps.capabilities & V4L2_CAP_READWRITE. My laptop webcam where I tested this does not support read/write.
See this example program for reference.
I want to open my door with a RFID Transponder. For this I use a Raspberry Pi and an 125Khz RFID Reader with UART. So now I have written a little C programm, wich sets up the RS232 ('ttyAMA0'). This works all fine, and I can read the Transponder, but it reads some sh**
Here is my Code:
char read_rfid(char* rfid_num)
{
fd_set input_fdset;
ssize_t length;
while(1)
{
FD_ZERO(&input_fdset);
FD_SET(fd,&input_fdset);
if(select(fd+1 ,&input_fdset, NULL,NULL,NULL)==-1)
perror("Terminal select() failed");
if(FD_ISSET(fd,&input_fdset))
{
if((length = read(fd,rfid_num,14)) ==-1)
perror("Terminal: read() failed");
else
{
write(STDOUT_FILENO,rfid_num,length);
return;
}
}
}
}
int setupRS232()
{
struct termios term_attr;
if((fd = open(RFID,O_RDWR)) == -1)
{
perror("Can't open Device");
return(1);
}
if(tcgetattr(fd,&term_attr) != 0)
{
perror("terminal: tcgetattr() failed");
return(1);
}
term_attr.c_cflag = BAUD|CS8|CRTSCTS|CLOCAL|CREAD;
term_attr.c_iflag = 0;
term_attr.c_oflag = 0;
term_attr.c_lflag = 0;
if(tcsetattr(fd,TCSAFLUSH,&term_attr) != 0)
{
perror("terminal: tcsetattr() failed");
return(1);
}
}
int main(int argc, char** argv)
{
MYSQL *mysql = NULL;
char rfid_num[14];
int i;
if(init_mysql(mysql) == 1)
return(1);
if(setupRS232() == 1)
return(1);
puts("Warte auf Transponder...");
read_rfid(rfid_num);
for(i=0;i<20;i++)
{
printf("%x\n",rfid_num[i]);
}
}
PS: Sorry for my bad English
Minimal approach to buffering. You should probably check the contents of the buffer before returning valid (is there a final \n ? )
char read_rfid(char* rfid_num) {
fd_set input_fdset;
ssize_t length;
int done;
for(done=0; done < 14; ) {
FD_ZERO(&input_fdset);
FD_SET(fd,&input_fdset);
if(select(fd+1 ,&input_fdset, NULL,NULL,NULL) == -1) {
if (errno == EAGAIN) continue;
perror("Terminal select() failed");
return -1;
}
if(FD_ISSET(fd,&input_fdset)) {
if((length = read(fd,rfid_num+done,14-done)) == -1) {
if (errno == EAGAIN) continue;
perror("Terminal: read() failed");
return -1;
}
write(STDOUT_FILENO,rfid_num+done,length);
done += length;
}
}
return 0;
}
Note: I don't understand why this function returns char.
I am in the middle of writing a user level C program, that reads a SPI device and translate the results to a keyboard event.
I am now trying to pass emulate key event to /dev/uinput. A weird thing is happening, file operation is failing.
my_kbd.c
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <fcntl.h>
#define PROG_NAME "c2h2_spi_kbd"
int fire_key(__u16);
int setup_uinputfd(const char *);
int close_uinputfd();
void write_uinput(__u16, __u16, __s32);
/*fd for uinput, we do need kernel to support uinput */
static int uinputfd = -1;
int main(int argc, char **argv){
puts("Welcome to use SPI keyboard program v0.1!");
uinputfd = setup_uinputfd(PROG_NAME);
if(uinputfd != -1){
fire_key(KEY_A);
}else{
puts("where is uinput ? do you have permission?\n");
}
close_uinputfd();
exit(0);
}
int fire_key(__u16 key){
write_uinput(EV_KEY, key, 1);
return 0;
}
void write_uinput(__u16 type, __u16 code, __s32 value){
struct input_event ie;
sleep(1);
memset(&ie, 0, sizeof(ie));
ie.type = type;
ie.code = code;
ie.value = value;
if(write(uinputfd, &ie, sizeof(ie)) != sizeof(ie)) puts("ERR1");
memset(&ie, 0, sizeof(ie));
ie.type = EV_SYN;
ie.code = SYN_REPORT;
ie.value = 0;
if(write(uinputfd, &ie, sizeof(ie)) != sizeof(ie)) puts("ERR2");
}
int close_uinputfd(){
close(uinputfd);
return 0;
}
int setup_uinputfd(const char *name){
int fd;
int key;
struct uinput_user_dev dev;
fd = open("/dev/input/uinput", O_RDWR);
if (fd == -1) {
fd = open("/dev/uinput", O_RDWR);
if (fd == -1) {
fd = open("/dev/misc/uinput", O_RDWR);
if (fd == -1) {
fprintf(stderr, "could not open %s\n", "uinput");
perror(NULL);
return -1;
}
}
}
memset(&dev, 0, sizeof(dev));
strncpy(dev.name, name, sizeof(dev.name));
dev.name[sizeof(dev.name) - 1] = 0;
if (write(fd, &dev, sizeof(dev)) != sizeof(dev) ||
ioctl(fd, UI_SET_EVBIT, EV_KEY) != 0
|| ioctl(fd, UI_SET_EVBIT, EV_REP) != 0) {
goto setup_error;
}
for (key = KEY_RESERVED; key <= KEY_UNKNOWN; key++) {
if (ioctl(fd, UI_SET_KEYBIT, key) != 0) {
goto setup_error;
}
}
if (ioctl(fd, UI_DEV_CREATE) != 0) {
goto setup_error;
}
return fd;
setup_error:
fprintf(stderr, "could not setup %s\n", "uinput");
perror(NULL);
close(fd);
return -1;
}
gcc -Wall my_kbd.c && sudo ./a.out
without sleep(1); I never have uinput event happen. with sleep(1);, this works perfect. (emulate keys output to focused program)
I do suspect this could be a cache problem, but fsync(fd); did not help. Please help.