I2C-dev: Change write and read parameters - c++

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
thanks in advanced

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.

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.)

Related

How do I fix error "C++ requires a type specifier for all declarations?"

I am on macOS right now, XCode Version 12.5.1.
I've encountered an error I haven't ever seen before, and I've searched all over for solutions however none have made sense.
Here's my code:
#include <iostream>
#include <cstdint>
#include <dlfcn.h>
std::uintptr_t rebase(const std::uintptr_t address, const std::uintptr_t base) {
return address - base + reinterpret_cast<std::uintptr_t>(dlopen(NULL, NULL));
}
typedef void(__cdecl* def_print)(const char*, void*);
def_print r_print = reinterpret_cast<def_print>(rebase(0x0069fa14, 0x0));
r_print("hi", nullptr); // Error: C++ requires a type specifier for all declarations.
Thanks for your time!
You cannot call functions outside of a method, unless you're initializing globals. You need to put your function call inside a method.
I.e.
int main() {
r_print("hi", nullptr);
}

Associate POSIX::open function to a namespace

I'm developing a control c++ library that needs to expose controller::open() function. However inside this function I have to call to the POSIX::open() function to open a file descriptor. The compiler complains I send Invalid Arguments to the controller function and doesn't understand I would like to call to the POSIX open() file function.
This is my code:
class declaration:
class PosixReadController {
int open();
}
implementation:
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
int PosixReadController::open()
{
int fd = open("/dev/ttyf1", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
/*
* Could not open the port.
*/
perror("open_port: Unable to open /dev/ttyf1 - ");
}
else
fcntl(fd, F_SETFL, 0);
return fd;
}
Error message (eclipse):
Invalid Arguments: 'Candidates are: int open()'
Changing the call to open to the global namespace with ::open doesn't help. Because I see the library already contains open function and I get the following error:
Invalid Arguments: 'Candidates are: int open(const char*, int, ...)
ImageCtrl* open(image) ''
Any idea?
Invalid Arguments: 'Candidates are: int open(char*, int, ...)
This is extremely suspicious. From where did you get this declaration of open? Did you include <fcntl.h>?
The prototype should actually look like this:
int open(const char *, int, ...);
const char * would have matched the string literal you passed, but char * obviously does not because a string literal is not writable.

C++ callback to class function

I'm using the Arduino IDE and the things network arduino library to create a LoRa mote.
I have created a class which should handle all the LoRa related functions. In this class I need to handle a callback if i receive a downlink message.
The ttn library has the onMessage function which I want to setup in my init function and parse another function, which are a class member, called message.
I'm getting the error "invalid use of non-static member function".
// File: LoRa.cpp
#include "Arduino.h"
#include "LoRa.h"
#include <TheThingsNetwork.h>
TheThingsNetwork ttn(loraSerial,debugSerial,freqPlan);
LoRa::LoRa(){
}
void LoRa::init(){
// Set the callback
ttn.onMessage(this->message);
}
// Other functions
void LoRa::message(const uint8_t *payload, size_t size, port_t port)
{
// Stuff to do when reciving a downlink
}
and the header file
// File: LoRa.h
#ifndef LoRa_h
#define LoRa_h
#include "Arduino.h"
#include <TheThingsNetwork.h>
// Define serial interface for communication with LoRa module
#define loraSerial Serial1
#define debugSerial Serial
// define the frequency plan - EU or US. (TTN_FP_EU868 or TTN_FP_US915)
#define freqPlan TTN_FP_EU868
class LoRa{
// const vars
public:
LoRa();
void init();
// other functions
void message(const uint8_t *payload, size_t size, port_t port);
private:
// Private functions
};
#endif
I have tried:
ttn.onMessage(this->message);
ttn.onMessage(LoRa::message);
ttn.onMessage(message);
However none of them worked as I had expected.
You're trying to call a member function (that means, a function belonging to a member of a class type) without using a class member. That means, what you'd usually do is instantiate a member of your class LoRa first, then call it like:
LoRa loraMember;
loraMember.message();
Since you're trying to call that function from inside the class itself, without a member of the class calling the init(), you have to make the function static like:
static void message(const uint8_t *payload, size_t size, port_t port);
Then you can use LoRa::message() from anywhere as long as it's public, but calling it just like that will give you another compiler error, since the interface of message asks for "const uint8_t *payload, size_t size, port_t port". So what you'd have to do is call message like:
LoRa::message(payloadPointer, sizeVar, portVar);`
When you call ttn.onMessage(functionCall) what happens is that the function call gets evaluated, then what is returned by that function gets put into the parentheses and ttn.onMessage is called with that. Since your LoRa::message function returns nothing (void) you'll get another error here.
I suggest a good book on C++ basics to get you started - book list
Good luck!
I Solved the problem by making the message function a normal function outside the class. Not sure if it is good practice - but it works.
// File: LoRa.cpp
#include "Arduino.h"
#include "LoRa.h"
#include <TheThingsNetwork.h>
TheThingsNetwork ttn(loraSerial,debugSerial,freqPlan);
void message(const uint8_t *payload, size_t size, port_t port)
{
// Stuff to do when reciving a downlink
}
LoRa::LoRa(){
}
void LoRa::init(){
// Set the callback
ttn.onMessage(message);
}
You should pass arguments to massage as indicated by its prototype:
void message(const uint8_t *payload, size_t size, port_t port);
Since massage returns void, it should not be used as an argument to other functions.

Error request for member getName which is of non-class type 'char'

I'm trying to make a program involving files assign2.cpp, Player.h, Player.cpp, Team.h, Team.cpp which reads data from a txt file on player info (like hits, atBat, position, name and number) and displays it out into assign2.cpp. assign2.cpp is what contains int main() and is suppose to contain very little code because relies on the other files to do the work.
The error:
request for member getName which is of non-class type ‘char’...
Please help, I've been trying to find the issue and can never do so. The compilation failure :
In file included from Team.cpp:1:0:
Team.h:34:11: warning: extra tokens at end of #endif directive [enabled by default]
Team.cpp: In constructor ‘Team::Team()’:
Team.cpp:15:5: warning: unused variable ‘numPlayers’ [-Wunused-variable]
Team.cpp: In member function ‘void Team::sortByName()’:
Team.cpp:49:56: error: request for member ‘getName’ in ‘((Team*)this
-> Team::playerObject[(j + -1)]’, which is of non-class type ‘char’
Team.cpp:49:74: error: request for member ‘getName’ in ‘bucket’, which is of non-class type ‘int’
Team.cpp: In member function ‘void Team::print()’:
Team.cpp:63:18: error: request for member ‘print’ in ‘((Team*)this)- >Team::playerObject[i]’, which is of non-class type ‘char’
make: *** [Team.o] Error 1
Team.h
#ifndef TEAM_H
#define TEAM_H
#include "Player.h"
class Team
{
private:
char playerObject[40];
int numPlayers; // specifies the number of Player objects
// actually stored in the array
void readPlayerData();
void sortByName();
public:
Team();
Team(char*);
void print();
};
#endif / *Team.h* /
Team.cpp
#include "Team.h"
#include <cstring>
#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <string.h>
#include <fstream>
#include <cstdlib>
using namespace std;
Team::Team()
{
strcpy (playerObject,"");
int numPlayers = 0;
}
Team::Team(char* newPlayerObject)
{
strncpy(playerObject, newPlayerObject, 40);
readPlayerData();
}
void Team::readPlayerData()
{
ifstream inFile;
inFile.open("gamestats.txt");
if (!inFile){
cout << "Error, couldn't open file";
exit(1);
}
inFile.read((char*) this, sizeof(Team));
inFile.close();
}
void Team::sortByName()
{
int i, j;
int bucket;
for (i = 1; i < numPlayers; i++)
{
bucket = playerObject[i];
for (j = i; (j > 0) && (strcmp(playerObject[j-1].getName(), bucket.getName()) > 0); j--)
playerObject[j] = playerObject[j-1];
playerObject[j] = bucket;
}
}
Player.h (incase anyone needs it)
#ifndef PLAYER_H
#define PLAYER_H
class Player
{
// Data members and method prototypes for the Player class go here
private:
int number;
char name[26];
char position[3];
int hits;
int atBats;
double battingAverage;
public:
Player();
Player(int, char*, char*, int, int);
char* getName();
char* getPosition();
int getNumber();
int getHits();
int getAtBats();
double getBattingAverage();
void print();
void setAtBats(int);
void setHits(int);
};
#endif
I'm very stuck, Thanks in advance.
In the Team constructor on this line
playerObject = newPlayerObject;
you're trying to assign a value of type char* to a member of type char[40], which doesn't work, since they are two different types. In any case, you probably would need to copy the data from the input instead of just trying to hold the pointer internally. Something like
strncpy(playerObject, newPlayerObject, 40);
Generally, you will always be able to assign a char[N] to a char*, but not the other way around, but that's just because C++ will automatically convert the char[N] to a char*, they are still different types.
Your declaration is:
char playerObject[40];
And your constructor reads:
Team::Team(char* newPlayerObject)
{
playerObject = newPlayerObject;
The error message you referenced in the title of this question obviously comes from here, and it is self explanatory. An array and a pointer are two completely different, incompatible types, when it comes to this kind of an assignment.
What you need to do depends entirely on what you expect to happen, and what your specifications are.
A) You could be trying to initialize the array from the character pointer, in which case you'll probably want to use strcpy(). Of course, you have to make sure that the string, including the null byte terminator, does not exceed 40 bytes, otherwise this will be undefined behavior.
Incidently, this is what you did in your default constructor:
Team::Team()
{
strcpy (playerObject,"");
}
B) Or, your playerObject class member should, perhaps, be a char * instead, and should be either assigned, just like that, or perhaps strdup()ed. In which case your default constructor will probably need to do the same.
Whichever one is the right answer for you depends entirely on your requirements, that you will have to figure out yourself.

Using DYLD interposing to interpose class functions

I have succesfully using dyld -macosx- to interpose standard C functions to a third party application, getting important information about the workarounds it does. But what I really need is to replace a certain function of a certain class.
The function I want to override is QString::append(..., ..., ...), so each time a string is appended to another -the whole application uses qstring-, i find out.
Is there a way? Here's the code I already have.
// libinterposers.c
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdarg.h>
#include <dlfcn.h>
#include <stdlib.h>
typedef struct interpose_s {
void *new_func;
void *orig_func;
} interpose_t;
int my_open(const char *, int, mode_t);
int my_close(int);
void* my_malloc(size_t);
static const interpose_t interposers[] \
__attribute__ ((section("__DATA, __interpose"))) = {
{ (void *)my_open, (void *)open },
{ (void *)my_close, (void *)close },
{ (void *)my_malloc, (void *)malloc },
};
int
my_open(const char *path, int flags, mode_t mode)
{
int ret = open(path, flags, mode);
printf("--> %d = open(%s, %x, %x)\n", ret, path, flags, mode);
return ret;
}
int
my_close(int d)
{
int ret = close(d);
printf("--> %d = close(%d)\n", ret, d);
return ret;
}
void*
my_malloc(size_t size)
{
void *ret = malloc(size);
//fprintf(stderr, "Reserva de memoria");
return ret;
}
Thank you very much
C++ does name mangling. This means member function QString::mid() looks something like __ZNK7QString3midEii to the linker. Run the nm(1) command on the library you are interposing on to see the symbols.
It is going to be much easier that this. QString uses memcpy to concatenate and work with Strings, and I can easily override memcpy, and apply a regular expression to the result, logging only the strings I want. Piece of cake. No need for magic voodo-hoodo :)