Reputation: 107
I'm currently working on I2C between a Raspberry Pi 3 and a PsoC 4. I'm using the I2C-dev library to handle the I2C communication. So the I2C bus is up and running, and the read and write function has been implemented correctly. I want however to make functions pointer the read and write functions hence the to functions uses the same types of arguments (atleast it looks like) I have the following main code called I
2Ctest-tools.cpp:
#include <unistd.h> //Needed for I2C port
#include <fcntl.h> //Needed for I2C port
#include <sys/ioctl.h> //Needed for I2C port
#include <linux/i2c-dev.h> //Needed for I2C port
#include <stdio.h>
#include "i2c.h"
#include "functions.h"
int main() {
int addr = 0x49;
int cmd = 2; //Write
int length = 5;
int file_i2c = 0;
I2C myI2C;
unsigned char buffer[5];
buffer[0] = 0x01;
buffer[1] = 0x02;
buffer[2] = 0x20;
buffer[3] = 0x00;
buffer[4] = 0x17;
i2c_init(&myI2C, cmd, addr, &file_i2c);
i2c_exe(&myI2C, file_i2c, buffer, length);
return 0;
}
As shown in the code, im using a object of the struct called myI2C which is passed in the two functions i2c_init, i2c_exe. The source code for functions.cpp is in the following:
#include <unistd.h> //Needed for I2C port
#include <fcntl.h> //Needed for I2C port
#include <sys/ioctl.h> //Needed for I2C port
#include <linux/i2c-dev.h> //Needed for I2C port
#include <stdio.h>
#include "i2c.h"
#include "functions.h"
int i2c_init(I2C *cthis, int cmd, int addr, int *ptrFile_i2c ) {
char *filename = (char*)"/dev/i2c-1";
if ((*ptrFile_i2c = open(filename, O_RDWR)) < 0)
{
//ERROR HANDLING: you can check errno to see what went wrong
printf("Failed to open the i2c bus");
return 0;
}
if (ioctl(*ptrFile_i2c, I2C_SLAVE, 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 0;
}
switch(cmd) {
case 1:
//cthis->WR = write;
break;
case 2:
cthis->WR = read;
break;
}
return 0;
}
int i2c_exe(I2C *cthis, int file_i2c, unsigned char *buffer, size_t length) {
cthis->WR(file_i2c, buffer, length);
return 0;
}
So the important thing to note here is that in the function i2c_init im switching on the varialbe cmd, which dictates whether the function pointer will point on the write or read function. Now the failure part comes in. The functions pointer is declared in its own .h file called i2c.h and looks like this:
struct I2C {
ssize_t (*WR)(int, const void *, size_t);
};
As you can see the function pointer has to point on a function with the parameters (int, const void*, size_t) this works like a charm when the function points on the write function BUT when it points on the read function im getting and error, the error says:
functions.cpp: In function ‘int i2c_init(I2C*, int, int, int*)’: functions.cpp:30:14: error: invalid conversion from ‘ssize_t ()(int, void, size_t) {aka int ()(int, void, unsigned int)}’ to ‘ssize_t ()(int, const void, size_t) {aka int ()(int, const void, unsigned int)}’ [-fpermissive] cthis->WR = read;
I have studied the error and concluded that it's because the read and write function somehow does not take the same arguments, which is weird because im passing the same arguments in them (int i2s_file, int buffer, int length) so if i change the function pointer to
ssize_t (*WR)(int, void *, size_t);
the function works with read but not with write.. So my question is: can i somehow change the write or read function to take the same argument by changing the i2c-dev library or is there anything else i could do to solve this problem?
here's a link to the i2c-dev library, which i have completely giving up to understand http://textuploader.com/5yioi
Upvotes: 3
Views: 2092
Reputation: 213306
Obviously the read
function cannot take a pointer to const
since, unlike the write
function, it has to modify that parameter.
So you cannot switch functionality with a function pointer, because the function pointers are of different types.
The best work-arounds seem to be either moving the "cmd" parameter to the i2c_exe
function, or alternatively create a private variable containing cmd
(inside struct I2C
would be ideal). And then in i2c_exe
either call read or write.
A worse solution is to change the struct to a union, like:
union I2C {
ssize_t (*WR)(int, const void *, size_t);
ssize_t (*read)(int, void*, size_t);
};
Then in case of reads, use the read member to assign to the struct. But please note that this is kind of a "dirty hack", it is poorly-specified behavior in theory. In practice, it will most likely work on any given system. (It is very unlikely that const correctness would ever affect calling convention.)
Upvotes: 0
Reputation: 18410
You can cast the functions explicitly to the correct type:
typedef ssize_t (*I2CCMD)(int, void *, size_t);
cthis->WR = (I2CCMD)write;
cthis->WR = (I2CCMD)read;
This should eliminate the error.
Upvotes: 1