I'm trying to detect when a gpio pin goes from low to high and am having trouble. From what I've read I should be able to configure the pin as input this way:
# echo in > /sys/class/gpio/gpio51/direction
# echo rising > /sys/class/gpio/gpio51/edge
Next I try running a c program that waits for the rising edge using select. The code looks like this (notice I commented out an attempt to just read the file, since reading is supposed to block if you don't set O_NONBLOCK):
#include<stdio.h>
#include<fcntl.h>
#include <sys/select.h>
int main(void) {
int fd = open("/sys/class/gpio/gpio51/value", O_RDONLY & ~O_NONBLOCK);
//int fd = open("/sys/class/gpio/gpio51/value", O_RDONLY | O_NONBLOCK);
//unsigned char buf[2];
//int x = read(fd, &buf, 2);
//printf("%d %d: %s\n", fd, x, buf);
fd_set exceptfds;
int res;
FD_ZERO(&exceptfds);
FD_SET(fd, &exceptfds);
//printf("waiting for %d: %s\n", exceptfds);
res = select(fd+1,
NULL, // readfds - not needed
NULL, // writefds - not needed
&exceptfds,
NULL); // timeout (never)
if (res > 0 && FD_ISSET(fd, &exceptfds)) {
printf("finished\n");
}
return 0;
}
The program exits immediately no matter what the state of the pin (high or low). Can anyone see something wrong with the way I'm doing this?
PS. I have a python library that uses poll() to do just this, and the python works as expected. I pull the pin low, call the python, it blocks, pull the pin high and the code continues. So I don't think it is a problem with the linux gpio driver.
https://bitbucket.org/cswank/gadgets/src/590504d4a30b8a83143e06c44b1c32207339c097/gadgets/io/poller.py?at=master
I figured it out. You must read from the file descriptor before the select call returns. Here is an example that works:
#include<stdio.h>
#include<fcntl.h>
#include <sys/select.h>
#define MAX_BUF 64
int main(void) {
int len;
char *buf[MAX_BUF];
int fd = open("/sys/class/gpio/gpio51/value", O_RDONLY);
fd_set exceptfds;
int res;
FD_ZERO(&exceptfds);
FD_SET(fd, &exceptfds);
len = read(fd, buf, MAX_BUF); //won't work without this read.
res = select(fd+1,
NULL, // readfds - not needed
NULL, // writefds - not needed
&exceptfds,
NULL); // timeout (never)
if (res > 0 && FD_ISSET(fd, &exceptfds)) {
printf("finished\n");
}
return 0;
}
Related
What's the difference between level triggered and edge triggered mode, when EPOLLONESHOT specified?
There's a similar question already here. The answer by "Crouching Kitten" doesn't seem to be right (and as I understand, the other answer doesn't answer my question).
I've tried the following:
server sends 2 bytes to a client, while client waits in epoll_wait
client returns from epoll_wait, then reads 1 byte.
client re-arms the event (because of EPOLLONESHOT)
client calls epoll_wait again. Here, for both cases (LT & ET), epoll_wait doesn't wait, but returns immediately (contrary to the answer by "Crouching Kitten")
client can read the second byte
Is there any difference between LT & ET, when EPOLLONESHOT specified?
I think the bottom line answer is "there is not difference".
Looking at the code, it seems that the fd remembers the last set bits before being disabled by the one-shot. It remembers it was one shot, and it remembers whether it was ET or not.
Which is futile, because the fd is disabled until modified, and the next call to EPOLL_CTL_MOD will erase all of that, and replace with whatever the new MOD says.
Having said that, I do not understand why anyone would want both EPOLLET and EPOLLONESHOT. To me, the whole point of EPOLLET is that, unders certain programming models (namely, microthreads), it follows the semantics perfcetly. This means that I can add the fd to the epoll at the very start, and then never have to perform another epoll related system call.
EPOLLONESHOT, on the other hand, is used by people who want to keep a very strict control over when the fd is watched and when it isn't. That, by definition, is the opposite of what EPOLLET is used for. I just don't think the two are conceptually compatible.
The other poster said "I do not understand why anyone would want both EPOLLET and EPOLLONESHOT." Actually, according to epoll(7), there is a use case for that:
Since even with edge-triggered epoll, multiple events can be generated upon receipt of multiple chunks of data, the caller has the option to specify the EPOLLONESHOT flag, to tell epoll to disable the associated file descriptor after the receipt of an event with epoll_wait(2).
The key point is that whether EPOLL will treat the combination of EPOLLET | EPOLLONESHOT and EPOLLLT | EPOLLONESHOT as special case. As I known, it is not. EPOLL just care them seperately. To EPOLLET and EPOLLLT, the different kindly only is in function ep_send_events, if the EPOLLET is set, then the function will call list_add_tail to add the epitem into the ready list in epoll_fd/eventepoll object.
To the EPOLLONESHOT, the role is to disable the fd. So I think the different between them is the different between ET and LT. You can check the result using below codes I think
// server.cc
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <pthread.h>
#define MAX_EVENT_NUMBER 1024
int setnonblocking(int fd)
{
int old_option = fcntl(fd, F_GETFL);
int new_option = old_option | O_NONBLOCK;
fcntl(fd, F_SETFL, new_option);
return old_option;
}
void addfd(int epollfd, int fd, bool oneshot)
{
epoll_event event;
event.data.fd = fd;
event.events = EPOLLIN | EPOLLET;
if(oneshot)
event.events |= EPOLLONESHOT;
epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
setnonblocking(fd);
}
// reset the fd with EPOLLONESHOT
void reset_oneshot(int epollfd, int fd)
{
epoll_event event;
event.data.fd = fd;
event.events = EPOLLIN | EPOLLET | EPOLLONESHOT;
epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &event);
}
int main(int argc, char** argv)
{
if(argc <= 2)
{
printf("usage: %s ip_address port_number\n", basename(argv[0]));
return 1;
}
const char* ip = argv[1];
int port = atoi(argv[2]);
int ret = 0;
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET, ip, &address.sin_addr);
address.sin_port = htons(port);
int listenfd = socket(PF_INET, SOCK_STREAM, 0);
assert(listenfd >= 0);
ret = bind(listenfd, (struct sockaddr*)&address, sizeof(address));
assert(ret != -1);
ret = listen(listenfd, 5);
assert(ret != -1);
epoll_event events[MAX_EVENT_NUMBER];
int epollfd = epoll_create(5);
addfd(epollfd, listenfd, false);
while(1)
{
printf("next loop: -----------------------------");
int ret = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, -1);
if(ret < 0)
{
printf("epoll failure\n");
break;
}
for(int i = 0; i < ret; i++)
{
int sockfd = events[i].data.fd;
if(sockfd == listenfd)
{
printf("into listenfd part\n");
struct sockaddr_in client_address;
socklen_t client_addrlength = sizeof(client_address);
int connfd = accept(listenfd, (struct sockaddr*)&client_address,
&client_addrlength);
printf("receive connfd: %d\n", connfd);
addfd(epollfd, connfd, true);
// reset_oneshot(epollfd, listenfd);
}
else if(events[i].events & EPOLLIN)
{
printf("into linkedfd part\n");
printf("start new thread to receive data on fd: %d\n", sockfd);
char buf[2];
memset(buf, '\0', 2);
// just read one byte, and reset the fd with EPOLLONESHOT, check whether still EPOLLIN event
int ret = recv(sockfd, buf, 2 - 1, 0);
if(ret == 0)
{
close(sockfd);
printf("foreigner closed the connection\n");
break;
}
else if(ret < 0)
{
if(errno == EAGAIN)
{
printf("wait to the client send the new data, check the oneshot memchnism\n");
sleep(10);
reset_oneshot(epollfd, sockfd);
printf("read later\n");
break;
}
}
else {
printf("receive the content: %s\n", buf);
reset_oneshot(epollfd, sockfd);
printf("reset the oneshot successfully\n");
}
}
else
printf("something unknown happend\n");
}
sleep(1);
}
close(listenfd);
return 0;
}
the Client is
from socket import *
import sys
import time
long_string = b"this is a long content which need two time to fetch"
def sendOneTimeThenSleepAndClose(ip, port):
s = socket(AF_INET, SOCK_STREAM);
a = s.connect((ip, int(port)));
print("connect success: {}".format(a));
data = s.send(b"this is test");
print("send successfuly");
time.sleep(50);
s.close();
sendOneTimeThenSleepAndClose('127.0.0.1', 9999)
I want to trigger an event whenever there is a rising edge on one of the pins of Beaglebone Black.
Problem is, even though I havent connected that pin to anything, the output just goes on printing, interrupt occured, interrupt occured. I came across question Interrupts in Beaglebone
on stackoverflow and tried to follow the steps. There was a link to a Program which implements the functionality.
I read about poll() and I made slight changes in the program since I want to monitor just one pin. The changed code is :
int main(int argc, char **argv, char **envp)
{
struct pollfd fdset[1]; // fdset[2] changed to fdset[1] since I will monitor just 1 pin
int nfds = 1; // nfds changed from 2 to 1
int gpio_fd, timeout, rc;
char *buf[MAX_BUF];
unsigned int gpio;
int len;
if (argc < 2) {
printf("Usage: gpio-int <gpio-pin>\n\n");
printf("Waits for a change in the GPIO pin voltage level or input on stdin\n");
exit(-1);
}
gpio = atoi(argv[1]);
gpio_export(gpio);
gpio_set_dir(gpio, 0);
gpio_set_edge(gpio, "rising");
gpio_fd = gpio_fd_open(gpio);
timeout = POLL_TIMEOUT;
while (1) {
memset((void*)fdset, 0, sizeof(fdset));
fdset[0].fd = gpio_fd; // This is the pin to be monitored
fdset[0].events = POLLIN;
//fdset[1].fd = gpio_fd; // commented since I do not need this
//fdset[1].events = POLLPRI;
rc = poll(fdset, nfds, timeout);
if (rc < 0) {
printf("\npoll() failed!\n");
return -1;
}
if (rc == 0) {
printf(".");
}
if (fdset[0].revents & POLLIN) {
len = read(fdset[0].fd, buf, MAX_BUF);
printf("\npoll() GPIO %d interrupt occurred\n", gpio);
}
// ****Commented block****
//if (fdset[0].revents & POLLIN) {
// (void)read(fdset[0].fd, buf, 1);
// printf("\npoll() stdin read 0x%2.2X\n", (unsigned int) buf[0]);
//}
fflush(stdout);
}
gpio_fd_close(gpio_fd);
return 0;
}
Running Angstrom on Beaglebone black.
https://www.kernel.org/doc/Documentation/gpio/sysfs.txt
If the pin can be configured as interrupt-generating interrupt
and if it has been configured to generate interrupts (see the
description of "edge"), you can poll(2) on that file and
poll(2) will return whenever the interrupt was triggered. If
you use poll(2), set the events POLLPRI and POLLERR. If you
use select(2), set the file descriptor in exceptfds. After
poll(2) returns, either lseek(2) to the beginning of the sysfs
file and read the new value or close the file and re-open it
to read the value.
You have not set events POLLPRI and POLLERR.
struct pollfd fdset[1];
memset((void*)fdset, 0, sizeof(fdset));
fdset[0].fd = fd;
fdset[0].events = POLLPRI | POLLERR;
...
poll()
...
lseek(fdset[0].fd, 0, SEEK_SET);
const ssize_t rc = read(fdset[0].fd, buf, MAX_BUF);
The above works on a BeagleBone Black Rev. C running Debian with linux 3.8.13-bone47.
Since you "havent connected that pin to anything", if it isn't internally tied low or high then it's just a floating input, which could cause the apparent interrupts you're seeing.
I'm using Linux Ubuntu and try to get serial communication to work.
Ok, what am I using...
I use a Raspberry Pi and connected it via USB/Serial-Adapter with an Inserial Measurement Unit (mulifunction sensor).
Just to clarify what i'm trying to do:
Establishing a connection betwenn Raspberry Pi and IMU.
To run IMU there are given steps i have to follow.
Power-on Sequence:
(a) power-on.
(b) Wait 800ms.
(c) Wait until NOT_READY bit goes to 0. NOT_READY is GLOB_CMD[3Eh]'s bit[10].
TXdata={0x3E,0x00,0x0d}. /* GLOB_CMD read command */
TXdata={0x3E,MSByte,LSByte,0x0d}. /* get response */
Confirm NOT_READY bit.
When NOT_READY becomes 0, it ends. Otherwise , please repeat (c).
(d) Confirm HARD_ERR bits. HARD_ERR is DIAG_STAT[3Ch]'s bit[6:5].
TXdata={0x3C,0x00,0x0d}. /* DIAG_STAT read command */
TXdata={0x3C,MSByte,LSByte,0x0d}. /* get response */
Confirm HARD_ERR is 00.
If HARD_ERR is 00, the IMU is OK. Otherwise, the IMU is faulty.
Register read and write:
[Read Example]
To read a 16bit-data from a register(addr=0x38).
TXdata={0x38,0x00,0x0d}. /* command */
RXdata={0x38,0x04,0x04,0x0d} /* response */
0x04 in 2nd byte of RXdata is Configuration mode.
0x04 in 3rd byte of RXdata is TAP=16.
Please note that read data unit is 16bit, and Most Significant Byte first.
-------------------------------------------------------------
[Write Example]
To write a 8bit-data into a register(addr=0x39).
TXdata={0xB9,0x01,0x0d}. /* command */
RXdata= w/o response
By sending this command, the IMU moves to Sampling mode.
Please note that write data unit is 8bit.
On my Linux Ubuntu there is a ttyUSB0 device given after connecting IMU.
So i tried to set Baudrate, Databits, Stopbits, Parity, flowcontrol.
First via stty-command, later with a simple c++-code.
I'm using this c++-code:
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <stdlib.h>
#include <cstdlib>
void SleepMs(int);
int main(int argc, char** argv)
{
int fd; // port file descriptor
char port[20] = "/dev/ttyUSB0"; // port to connect to
fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY); // connect to port
if(fd == -1)
{
printf("Error while opening the port.\n");
return 1;
}
printf("Port opened successfully.\n");
fcntl(fd, F_SETOWN, getpid());
struct termios settings;
tcgetattr(fd, &settings);
settings.c_cflag &= ~(CBAUD | CSIZE | CREAD);
settings.c_cflag |= B230400;
settings.c_cflag |= CS8;
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &settings); // apply the settings
int len = 7;
unsigned char bytes[len];
bytes[0] = 0x3E;
bytes[1] = 0x00;
bytes[2] = 0x0D;
bytes[3] = 0x3E;
bytes[4] = 0x00;
bytes[5] = 0x00;
bytes[6] = 0x0D;
int wr = write(fd, bytes, len);
unsigned char answer[32];
SleepMs(350);
int rd = -1;
int i;
while (rd==-1)
{
if(wr != 7)
{
printf("Error while sending!\n");
}
for(i=0; i<len; i++)
{
printf("%X sent\n", (unsigned int)bytes[i]);
SleepMs(350);
}
printf("\n");
printf("%d bytes sent.\n", wr);
printf("\n");
printf("Trying to read...\n");
printf("\n");
rd = read(fd, answer, 32);
SleepMs(350);
printf("%d\n", rd);
for(i=0; i<rd; i++)
{
printf("%X ", (unsigned int)answer[i]);
}
printf("\n\n");
}
close(fd);
return 0;
}
void SleepMs(int ms) {
usleep(ms*1000); //convert to microseconds
return;
}
If i start program, it tells me "Port open successfully" and writes given bytes in program.
But it receives no data.
I transmit 0x3E 0x00 0x0D to activate GLOB_CMD read command.
I have to confirm "Not Ready"-Bit is 0 but i dont get an answer with my serial connection.
So this is where i need your help, maybe someone got a hint for me.
How can i communicate with my IMU or via serialcommunication properly with Linux?
int wr = write(fd, bytes, len);
Your bytes array only needs to be 3 bytes long, so len should be 3. (The 0x3e is what the IMU should respond with, so it shouldn't be in your program except when checking the response.) When you read, you should only read the expected size of the answer (len=4). You don't need to sleep after writing, and probably not after reading.
I am trying to set a read timeout on a file descriptor representing a PTY. I have set VMIN = 0 and VTIME = 10 in termios, which I expect to return when a character is available, or after a second if no characters are available. However, my program sits forever in the read call.
Is there something special about PTY that makes this not work? Are there other TERMIOS settings that cause this to work? I tried this same configuration on the stdin file descriptor and it worked as expected.
#define _XOPEN_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <fcntl.h>
#define debug(...) fprintf (stderr, __VA_ARGS__)
static void set_term (int fd)
{
struct termios termios;
int res;
res = tcgetattr (fd, &termios);
if (res) {
debug ("TERM get error\n");
return;
}
cfmakeraw (&termios);
termios.c_lflag &= ~(ICANON);
termios.c_cc[VMIN] = 0;
termios.c_cc[VTIME] = 10; /* One second */
res = tcsetattr (fd, TCSANOW, &termios);
if (res) {
debug ("TERM set error\n");
return;
}
}
int get_term (void)
{
int fd;
int res;
char *name;
fd = posix_openpt (O_RDWR);
if (fd < 0) {
debug ("Error opening PTY\n");
exit (1);
}
res = grantpt (fd);
if (res) {
debug ("Error granting PTY\n");
exit (1);
}
res = unlockpt (fd);
if (res) {
debug ("Error unlocking PTY\n");
exit (1);
}
name = ptsname (fd);
debug ("Attach terminal on %s\n", name);
return fd;
}
int main (int argc, char **argv)
{
int read_fd;
int bytes;
char c;
read_fd = get_term ();
set_term (read_fd);
bytes = read (read_fd, &c, 1);
debug ("Read returned\n");
return 0;
}
From the linux pty (7) manpage (italics are mine):
A pseudoterminal (sometimes abbreviated "pty") is a pair of virtual character devices that
provide a bidirectional communication channel. One end of the channel is called the
master; the other end is called the slave. The slave end of the pseudoterminal provides
an interface that behaves exactly like a classical terminal
Your program, however, is reading from the master, which cannot be expected to behave exactly like a terminal device
If you change/expand the last few lines of get_term thusly ...
int slave_fd = open (name, O_RDWR); /* now open the slave end..*/
if (slave_fd < 0) {
debug ("Error opening slave PTY\n");
exit (1);
}
return slave_fd; /* ... and use it instead of the master..*/
... your example program will work as expected.
I am writing code for implementing a simple i2c read/write function using the general linux i2c driver linux/i2c-dev.h
I am confused about the ioctl : I2C_SLAVE
The kernel documentation states as follows :
You can do plain i2c transactions by using read(2) and write(2) calls.
You do not need to pass the address byte; instead, set it through
ioctl I2C_SLAVE before you try to access the device
However I am using the ioctl I2C_RDWR where I again set the slave address using i2c_msg.addr.
The kernel documentation also mentions the following :
Some ioctl() calls are for administrative tasks and are handled by
i2c-dev directly. Examples include I2C_SLAVE
So is it must to use the ioctl I2C_SLAVE? If so do I need to set it just once or every time I perform a read and write?
If I had an i2c device I could have just tested the code on the device and would not have bothered you guys but unfortunately I don't have one right now.
Thanks for the help.
There are three major methods of communicating with i2c devices from userspace.
1. IOCTL I2C_RDWR
This method allows for simultaneous read/write and sending an uninterrupted sequence of message. Not all i2c devices support this method.
Before performing i/o with this method, you should check whether the device supports this method using an ioctl I2C_FUNCS operation.
Using this method, you do not need to perform an ioctl I2C_SLAVE operation -- it is done behind the scenes using the information embedded in the messages.
2. IOCTL SMBUS
This method of i/o is more powerful but the resulting code is more verbose. This method can be used if the device does not support the I2C_RDWR method.
Using this method, you do need to perform an ioctl I2C_SLAVE operation (or, if the device is busy, an I2C_SLAVE_FORCE operation).
3. SYSFS I/O
This method uses the basic file i/o system calls read() and write(). Uninterrupted sequential operations are not possible using this method. This method can be used if the device does not support the I2C_RDWR method.
Using this method, you do need to perform an ioctl I2C_SLAVE operation (or, if the device is busy, an I2C_SLAVE_FORCE operation).
I can't think of any situation when this method would be preferable to others, unless you need the chip to be treated like a file.
Full IOCTL Example
I haven't tested this example, but it shows the conceptual flow of writing to an i2c device.-- automatically detecting whether to use the ioctl I2C_RDWR or smbus technique.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#define I2C_ADAPTER "/dev/i2c-0"
#define I2C_DEVICE 0x00
int i2c_ioctl_write (int fd, uint8_t dev, uint8_t regaddr, uint16_t *data, size_t size)
{
int i, j = 0;
int ret;
uint8_t *buf;
// the extra byte is for the regaddr
size_t buff_size = 1 + size;
buf = malloc(buff_size);
if (buf == NULL) {
return -ENOMEM;
}
buf[j ++] = regaddr;
for (i = 0; i < size / sizeof(uint16_t); i ++) {
buf[j ++] = (data[i] & 0xff00) >> 8;
buf[j ++] = data[i] & 0xff;
}
struct i2c_msg messages[] = {
{
.addr = dev,
.buf = buf,
.len = buff_size,
},
};
struct i2c_rdwr_ioctl_data payload = {
.msgs = messages,
.nmsgs = sizeof(messages) / sizeof(messages[0]),
};
ret = ioctl(fd, I2C_RDWR, &payload);
if (ret < 0) {
ret = -errno;
}
free (buf);
return ret;
}
int i2c_ioctl_smbus_write (int fd, uint8_t dev, uint8_t regaddr, uint16_t *data, size_t size)
{
int i, j = 0;
int ret;
uint8_t *buf;
buf = malloc(size);
if (buf == NULL) {
return -ENOMEM;
}
for (i = 0; i < size / sizeof(uint16_t); i ++) {
buf[j ++] = (data[i] & 0xff00) >> 8;
buf[j ++] = data[i] & 0xff;
}
struct i2c_smbus_ioctl_data payload = {
.read_write = I2C_SMBUS_WRITE,
.size = I2C_SMBUS_WORD_DATA,
.command = regaddr,
.data = (void *) buf,
};
ret = ioctl (fd, I2C_SLAVE_FORCE, dev);
if (ret < 0)
{
ret = -errno;
goto exit;
}
ret = ioctl (fd, I2C_SMBUS, &payload);
if (ret < 0)
{
ret = -errno;
goto exit;
}
exit:
free(buf);
return ret;
}
int i2c_write (int fd, uint8_t dev, uint8_t regaddr, uint16_t *data, size_t size)
{
unsigned long funcs;
if (ioctl(fd, I2C_FUNCS, &funcs) < 0) {
return -errno;
}
if (funcs & I2C_FUNC_I2C) {
return i2c_ioctl_write (fd, dev, regaddr, data, size);
} else if (funcs & I2C_FUNC_SMBUS_WORD_DATA) {
return i2c_ioctl_smbus_write (fd, dev, regaddr, data, size);
} else {
return -ENOSYS;
}
}
int parse_args (uint8_t *regaddr, uint16_t *data, size_t size, char *argv[])
{
char *endptr;
int i;
*regaddr = (uint8_t) strtol(argv[1], &endptr, 0);
if (errno || endptr == argv[1]) {
return -1;
}
for (i = 0; i < size / sizeof(uint16_t); i ++) {
data[i] = (uint16_t) strtol(argv[i + 2], &endptr, 0);
if (errno || endptr == argv[i + 2]) {
return -1;
}
}
return 0;
}
void usage (int argc, char *argv[])
{
fprintf(stderr, "Usage: %s regaddr data [data]*\n", argv[0]);
fprintf(stderr, " regaddr The 8-bit register address to write to.\n");
fprintf(stderr, " data The 16-bit data to be written.\n");
exit(-1);
}
int main (int argc, char *argv[])
{
uint8_t regaddr;
uint16_t *data;
size_t size;
int fd;
int ret = 0;
if (argc < 3) {
usage(argc, argv);
}
size = (argc - 2) * sizeof(uint16_t);
data = malloc(size);
if (data == NULL) {
fprintf (stderr, "%s.\n", strerror(ENOMEM));
return -ENOMEM;
}
if (parse_args(®addr, data, size, argv) != 0) {
free(data);
usage(argc, argv);
}
fd = open(I2C_ADAPTER, O_RDWR | O_NONBLOCK);
ret = i2c_write(fd, I2C_DEVICE, regaddr, data);
close(fd);
if (ret) {
fprintf (stderr, "%s.\n", strerror(-ret));
}
free(data);
return ret;
}
If you use the read() and write() methods, calling ioctl with I2C_SLAVE once is enough. You can also use I2C_SLAVE_FORCE if the device is already in use.
However I haven't yet found a consistent way to read specific registers for every device using the read()/write() methods.
I'm not too sure if this helps because I don't use ioctl I2C_RDWR but I've been using the following code with success:
int fd;
fd = open("/dev/i2c-5", O_RDWR);
ioctl(fd, I2C_SLAVE_FORCE, 0x20);
i2c_smbus_write_word_data(fd, ___, ___);
i2c_smbus_read_word_data(fd, ___);
All I do is set I2C_SLAVE_FORCE once at the beginning and I can read and write as much as I want to after that.
PS - This is just a code sample and obviously you should check the returns of all of these functions. I'm using this code to communicate with a digital I/O chip. The two i2c_* functions are just wrappers that call ioctl(fd, I2C_SMBUS, &args); where args is a struct i2c_smbus_ioctl_data type.
For the interested, SLAVE_FORCE is used when the device in question is already being managed by a kernel driver. (i2cdetect will show UU for that address)