Why are i2c_smbus function not available? (I2C – Embedded Linux) - c++

There are many references to using i2c_smbus_ functions when developing embedded Linux software to communicate on the I2C bus. When i2c_smbus functions such as i2c_smbus_read_word_data are referenced in software project for ARM8 processor errors such as ‘i2c_smbus_read_word_data’ was not declared in this scope are generated at compile.
Investigation of the following header files indicate the absence of most i2c_smbus function definition.
/usr/arm-linux-gnueabi/include/linux/i2c.h
/usr/arm-linux-gnueabi/include/linux/i2c-dev.h
Also in that following reference i2c.h file has all the i2c_smbus defined.
How can this problem be resolved?
Research references
Using I2C from userspace in Linux
I2C Communication from Linux Userspace – Part II
I2C dev interface

Because you are using a wrong header file for your application.
If you see an extern on the function i2c_smbus_read_word_data() in your header, it's a header file for your kernel, but not for your application. The Linux kernel has i2c_smbus_read_word_data() and other i2c smbus functions for its internal use. But they are a) not system calls, or b) not accessible from your application.
Instead, get i2c-tools from Linux Kernel Wiki and install it. If you are using Debian, just
sudo apt-get install libi2c-dev
and use i2c_smbus_read_word_data() or any other interfaces they offer.
Version Notes
i2c-dev, untill version 3.x, used be a header only package, meaning that there was no library to link to. All functions were inline functions defined using ioctl().
e.g.)
static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command,
int size, union i2c_smbus_data *data)
{
struct i2c_smbus_ioctl_data args;
args.read_write = read_write;
args.command = command;
args.size = size;
args.data = data;
return ioctl(file,I2C_SMBUS,&args);
}
:
static inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
{
union i2c_smbus_data data;
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
I2C_SMBUS_WORD_DATA,&data))
return -1;
else
return 0x0FFFF & data.word;
}
But since v4.0, it start to be a standard shared library with libi2c.so.0 and i2c/smbus.h. You have to include the header file in your source code
#include <i2c/smbus.h>
And link libi2c.so.0 with -li2c
gcc -o a.out main.o -li2c

I ran into this today. The i2c_smbus_* functions are defined in:
/usr/include/linux/i2c-dev.h
...but when I would try to cross-compile for ARM on an older version of Ubuntu, I was running into errors such:
i2c_smbus_read_block_data was not declared in this scope
Turns out the functions are not defined in the equivalent ARM-specific location:
/usr/arm-linux-gnueabi/include/linux/i2c-dev.h
When cross-compiling, this 2nd older header file is the one used. Had to re-declare locally a few of the inline i2c_smbus_... functions to get around the problem.

Based on https://unix.stackexchange.com/questions/621854/usr-include-linux-i2c-dev-h-does-not-contain-i2c-smbus-read-word-data-functio, I have found this fixes the function not defined errors:
#include <i2c/smbus.h>
I am currently working with legacy code that references various i2c_smbus functions. It has:
#include <linux/i2c-dev-user.h>
and it fails to compile. Surely, this include used to work, but it seems the lib's header files changed at some point. I did refresh/reinstall libi2c-dev recently.
Note that I added the above include. I can't remove the original include. It is still needed.
FYI: I have not tried cross-compiling yet.

From the i2c Linux kernel documentation:
Please note that there are two files named "i2c-dev.h" out there, one is distributed with the Linux kernel and is meant to be included from kernel driver code, the other one is distributed with i2c-tools and is meant to be included from user-space programs. You obviously want the second one here.
So you need to include the i2c-dev.h from i2c-tools not from the Linux kernel.

Related

Undefined Reference to `pcap_init' - Libpcap

I'm currently trying to set up a simple packet sniffer with libpcap and facing a lot of confusion over this linker error.
I cloned the most recent version from github (1.11.0-PRE-GIT) and successfully did the configure, make and make install steps outlined in the installation instructions.
My script is as follows:
#include <iostream>
#include <pcap/pcap.h>
#include <string>
#include <cstdlib>
using namespace std;
int main(int argc, char *argv[])
{
//Set up error buffer
char errbuf[PCAP_ERRBUF_SIZE];
// Check Libpcap version number
cout << pcap_lib_version() << endl << endl;
//Initialize the library for local charactr encoding
pcap_init(PCAP_CHAR_ENC_LOCAL, errbuf);
return 0;
}
But when I try to compile with the command below I get the error:
g++ csniff.cc -o csniff -lpcap
/usr/bin/ld: /tmp/ccAPLFoh.o: in function `main':
csniff.cc:(.text+0x79): undefined reference to `pcap_init'
collect2: error: ld returned 1 exit status
I've also checked the pcap.h files present in both usr/include and usr/local/include and they both contain a prototype for the pcap_init function that looks like this:
#define PCAP_CHAR_ENC_LOCAL 0x00000000U /* strings are in the local
character encoding */
#define PCAP_CHAR_ENC_UTF_8 0x00000001U /* strings are in UTF-8 */
PCAP_AVAILABLE_1_10
PCAP_API int pcap_init(unsigned int, char *);
One thing I have noticed though is that when I comment out the line with pcap_init and use the script to print the version number I get
libpcap version 1.9.1 (with TPACKET_V3)
Any pointers would be much appreciated!
Edit: runnning Ubuntu 20.04.3 LTS
Your operating system already comes with libpcap - version 1.9.1. Most Linux distributions do, as do the *BSDs, macOS, and some commercial UN*Xes.
You compiled and installed a newer version of libpcap, so you had two versions of the library file - the 1.9.1 that comes with the system, in the system library directory, because it comes with the OS, and the 1.11.0-PRE-GIT and you compiled and installed, probably in /usr/local/lib.
You also had one version of the libpcap header files - the 1.11.0-PRE-GIT version - in /usr/local/include/pcap, because you installed it. You did not have the 1.9.1 version of the header files, because, like many Linux distributions, a separate "development" package has to be installed in order to get the header files.
When you compiled your program, you didn't tell it where to look for header files or libraries. It found the header files in /usr/local/include/pcap - i.e., the 1.11.0-PRE-GIT header files - and found the library in the system library directory - i.e., the 1.9.1 library.
This causes problems, because the header files included a declaration of pcap_init(), so the compiler didn't print a warning about pcap_init() not being declared, but the library file doesn't include the pcap_init() function, so the linker printed an error about pcap_init() not being found in libpcap.
Removing the call to pcap_init() meant that the linker didn't try to find pcap_init(), and thus didn't fail.
If you hadn't built and installed libpcap 1.11.0-PRE-GIT, and you had installed the libpcap-dev package, your system would have the headers and library for 1.9.1, and compiling your program - without the call to pcap_init() - would find the headers for 1.9.1, so it can compile, and the library for 1.9.1, so it will link.
If, however, you want to build with 1.11.0-PRE-GIT, then you will need to tell the compiler where to find the libraries; you might also have to tell it where to find the headers.
If you don't have the libpcap-dev package installed, then you don't need to tell it where to find the headers, as it will find the 1.11.0-PRE-GIT ones you installed; however, if the libpcap-dev package is installed, you may have to add the flag -I /usr/local/include to the compiler command, to make sure it finds the headers in /usr/local/include rather than the system include directory.
To make sure it finds the 1.11.0-PRE-GIT version of the libraries, you will have to add the flag -L /usr/local/lib to the compiler command as well - or set LD_LIBRARY_PATH so that the linker finds the 1.11.0-PRE-GIT version.
If you build with 1.11.0-PRE-GIT, you can use pcap_init(). You don't need to use pcap_init() unless you want to run the program on some UN*X and on Windows and you want all strings to be in UTF-8 (on Windows, strings would, by default, be treated as being in the "local code page"). To quote the DESCRIPTION section of the pcap_init() man page:
pcap_init() is used to initialize the Packet Capture library. opts
specifies options for the library; currently, the options are:
PCAP_CHAR_ENC_LOCAL
Treat all strings supplied as arguments, and return all strings
to the caller, as being in the local character encoding.
PCAP_CHAR_ENC_UTF_8
Treat all strings supplied as arguments, and return all strings
to the caller, as being in UTF‐8.
On UNIX‐like systems, the local character encoding is assumed to be
UTF‐8, so no character encoding transformations are done.
On Windows, the local character encoding is the local ANSI code page.
If pcap_init() is not called, strings are treated as being in the local
ANSI code page on Windows, pcap_lookupdev(3PCAP) will succeed if there
is a device on which to capture, and pcap_create(3PCAP) makes an
attempt to check whether the string passed as an argument is a UTF‐16LE
string ‐ note that this attempt is unsafe, as it may run past the end
of the string ‐ to handle pcap_lookupdev() returning a UTF‐16LE string.
Programs that don’t call pcap_init() should, on Windows, call
pcap_wsockinit() to initialize Winsock; this is not necessary if
pcap_init() is called, as pcap_init() will initialize Winsock itself on
Windows.

ImageMagick pthread.h multiple definition

When trying to compile more recent versions of ImageMagick (v6.8.7-2 or later, v6.8.7-1 is fine), I get a bunch of:
CCLD magick/libMagickCore-6.Q16.la
magick/.libs/magick_libMagickCore_6_Q16_la-animate.o: In function `__pthread_cleanup_routine':
/usr/include/pthread.h:581: multiple definition of `__pthread_cleanup_routine'
magick/.libs/magick_libMagickCore_6_Q16_la-accelerate.o:/usr/include/pthread.h:581: first defined here
magick/.libs/magick_libMagickCore_6_Q16_la-annotate.o: In function `__pthread_cleanup_routine':
/usr/include/pthread.h:581: multiple definition of `__pthread_cleanup_routine'
magick/.libs/magick_libMagickCore_6_Q16_la-accelerate.o:/usr/include/pthread.h:581: first defined here
magick/.libs/magick_libMagickCore_6_Q16_la-artifact.o: In function `__pthread_cleanup_routine':
/usr/include/pthread.h:581: multiple definition of `__pthread_cleanup_routine'
magick/.libs/magick_libMagickCore_6_Q16_la-accelerate.o:/usr/include/pthread.h:581: first defined here
magick/.libs/magick_libMagickCore_6_Q16_la-attribute.o: In function `__pthread_cleanup_routine':
/usr/include/pthread.h:581: multiple definition of `__pthread_cleanup_routine'
magick/.libs/magick_libMagickCore_6_Q16_la-accelerate.o:/usr/include/pthread.h:581: first defined here
... goes on for quite a bit longer, all the same.
The pertinent area of /usr/include/pthread.h (from glibc-headers 2.5-118.el5_10.2) is:
/* Function called to call the cleanup handler. As an extern inline
function the compiler is free to decide inlining the change when
needed or fall back on the copy which must exist somewhere else. */
extern __inline void
__pthread_cleanup_routine (struct __pthread_cleanup_frame *__frame)
{
if (__frame->__do_it) // <======= this is :581
__frame->__cancel_routine (__frame->__cancel_arg);
}
I've been posting on ImageMagick's forum without response.
Even if you can't say exactly what's happening, how do I start figuring out whether the issue is with ImageMagick or pthread.h? Where do I go from there?
grep pthread_cleanup_routine -r * only shows matches against the binary object files -- none of ImageMagick's source code has pthread_cleanup_routine in it. A few of the sources include "pthread.h" of course.
That's leading me to believe that this is a glibc issue, not an ImageMagick issue... but, again, previous versions of ImageMagick compile just fine. (I have diff'ed the svn sources between versions where it broke. Lots of configuration/makefile changes, but nothing sticks out to me as to why it would cause this.)
I'm on CentOS 5, kernel 2.6.18-308.24.1.el5, gcc v4.9.0, ld v2.24, glibc-headers 2.5-118.el5_10.2
I've seen a lot of people posting similar issues with other packages than ImageMagick. Hopefully others will find this useful.
Changing pthread.h, just before __pthread_cleanup_routine :
extern __inline void
to
if __STDC__VERSION__ < 199901L
extern
#endif
__inline void
Fixes the issue. Older versions of glibc had an issue when -fexceptions was used, and inline non-C99 conformance (see http://gcc.gnu.org/ml/gcc-patches/2006-11/msg01030.html.) More recent glibc's would fix the issue too, but this should be a temp fix for those who don't want to / shouldn't upgrade it.
ImageMagick svn 13539 (which later became v6.8.7-2) began using -fexceptions.
I faced this error with a newer gcc compiler (4.9.3)
The ImageMagick(6.8.9_7) configure script was checking if compiler supports gnu99 standard. If yes, the configure script sets standard to gnu99 and also enables openmp.
Inline semantics change with C standard gnu99 causing multiple definition of the extern inline function
https://gcc.gnu.org/onlinedocs/gcc-4.9.3/gcc/Inline.html#Inline.
So, I added compiler flag -fgnu89-inline to use older semantics for inline and it fixed the issue.

How do I use arduino libraries with standard C code

I am using Eclipse kepler for AVR development.
The code that I have is C (Open Source), and I've gotten it adjusted so it runs perfectly. My target is an ATmega2560, in the form of an arduino mega2560.
Using the arduino board is strictly for hardware convenience; we are developing the hardware to be a custom board with most of the core arduino mega2560 components.
I need to use several libraries with this project that are only available as arduino libraries, namely libraries for an e-paper screen (from seeedstudio) and Nordic's BLE nRF8001.
If I create a new arduino project using the plugin in eclipse, I can build and run the tests for the arduino libraries perfectly.
When I try to merge the 2 code bases together, I can't seem to call the functions in the added arduino libraries - if I call them the compiler throws a linking error.
Building target: Virgin2ManualArdInsert.elf
Invoking: AVR C Linker
avr-gcc -Wl,-Map,Virgin2ManualArdInsert.map -mmcu=atmega2560 -o "Virgin2ManualArdInsert.elf" ./avr/adc.o ./avr/eeprom.o ./avr/lcd_and_input.o ./avr/main.o ./avr/strings.o ./avr/unimplemented.o ./avr/usart.o ./aes.o ./baseconv.o ./bignum256.o ./ecdsa.o ./endian.o ./fft.o ./fix16.o ./hash.o ./hmac_sha512.o ./messages.pb.o ./p2sh_addr_gen.o ./pb_decode.o ./pb_encode.o ./pbkdf2.o ./prandom.o ./ripemd160.o ./sha256.o ./statistics.o ./stream_comm.o ./test_helpers.o ./transaction.o ./wallet.o ./xex.o
./avr/main.o: In function `main':
main.c:(.text.startup.main+0xc): undefined reference to `writeEink'
collect2: error: ld returned 1 exit status
makefile:53: recipe for target 'Virgin2ManualArdInsert.elf' failed
make: *** [Virgin2ManualArdInsert.elf] Error 1
As a test, I'm just trying to call a basic "write to display" call in eInk.cpp from main.c:
extern "C"{
void writeEink()
{
EPAPER.begin(EPD_SIZE); // setup epaper, size
EPAPER.setDirection(DIRNORMAL); // set display direction
eSD.begin(EPD_SIZE);
GT20L16.begin();
// int timer1 = millis();
EPAPER.drawString("testing", 10, 10);
EPAPER.drawNumber(12345, 60, 40);
EPAPER.drawFloat(-1.25, 2, 80, 65);
EPAPER.display(); // use only once
}
Is a static library built from the arduino cores the way to go here? I've tried it (though it seems most of the procedures are outdated) and the libraries do not want to link/be called.
What is the correct procedure for including C++/Arduino calls in my C code?
I've tried using extern "C" {function()}; in my .cpp files and .h files but to no use.
Thank you for any help or pointers to where I can figure it out for myself.
You can try to compile your C code as C++ by simply renaming the files to *.CPP, but chances are that you have to modify your code to make it compile as C++ code. There are things that are allowed for C, but not for C++ (like calling functions that are not declared).
The other solution is to wirte wrappers around the C++ functions that you want to use from C.
You have to consider two limitations of C against C++:
C is not object oriented
C does not support overloading of functions
This example for Serial.print() shows how you can handle this with a wrapper:
extern "C" void SerialPrintInteger( int value )
{
Serial.print( value );
}
In this example you would write similar functions like SerialPrintFloat(), SerialPrintString() etc.
The extern "C" prefix tells the compiler to create the function in a way that makes it callable from C.
The error you received above isn't a compiler error, it's a linker error. I haven't used Eclipse for Arduino development, I just stick with the Arduino IDE, but the standard Arduino projects expect all of your code to be in a single source file, which it compiles and then links with the Arduino libraries. Arduino programs don't have a C/UNIX-style "main" function, the standard functions are "setup" and "loop."
I recommend going back to one of the Arduino example programs, blink for instance, and watching the console log as Eclipse compiles and links the program. What's happening here is:
The C/C++ compiler compiles your source code, including setup(), loop(), and any other functions you have created, into an object file.
The Linker links this single object file with the Arduino runtime, and any Arduino libraries you have specified. The output of this is an image of the program, in your example above it's trying to make 'Virgin2ManualArdInsert.elf'.
The uploader (probably avrdude) loads this image into your Arduino and resets it.
The Arduino comes out of reset and runs your new code.
If your program is reasonably small, say not more than a few hundred lines, just put all the functions in the one source file, then you won't have to learn how to drive the linker.
If you need, for some reason, to have the sources in a separate file (maybe they're shared with another program, or another platform), then you'll have to learn how to get Eclipse to link the object files from your multiple source files. This may just involve adding the sources into your Eclipse project properly, or you may have to write a Makefile or something similar.
As for C vs C++ source code, you can usually drop a C function into a C++ source file and compile it. There are a few differences, but this way you don't need to worry about "C" linkage or any of that silliness.

extern function call under windows make undefined reference

There is my problem:
All the code is in C++11.
Part 1
I've build a library (named socket).
somwhere in the code, I declare a function:
namespace ntw {
extern int dispatch(int id,Socket& request));
}
This function is user defined (most of the case, simply a big switch)) and by this way the body of it, is not define in the socket lib.
I use this function in server.cpp (which is part of the socket lib).
All is fine under linux, it build the .so perfectly.
But under windows it create a
undefined reference to ntw::dispatch(int,Socket&)
So the .dll is not build.
Part2
I create the main program that use the socket lib.
And in this code, I make :
namespace ntw {
int dispatch(int id,Socket& request)){
/// some code
return ...;
}
}
finaly
So now, that i want is:
the user define int dispatch(int id,Socket& request)) have to be call by the socket libary.
Under Ubuntu, all is fine (coppilation, adn run),
but under windows .... it's the hell.
What can I do to make it work under windows xp and over ?
linux
Ubuntu 12.04, gcc 4.8.1
windows
windows xp, mingw 4.8.1
code
github: https://github.com/Krozark/cpp-Socket
It use cmake (if someone want to try).
What you are attempting won't work on Windows which has a quite different linking model from Linux. You need run time binding. I think you want the function to be provided by the host executable. In which case you need the host to export it with either a .def file or __declspec(dllexport). And then run time binding like this:
HMODULE hMod = GetModuleHandle(NULL); // gets host executable module handle
void *fn = GetProcAddress(hMod, FunctionName);
You can then cast fn to an appropriately declared function pointer before calling the function.
This is probably a reasonable approximation to how your Linux code operates. But it's not a very natural way to operate on Windows. More normal would be for the host to register callback functions or interfaces with the library. Once the host has informed the library of its callbacks, the library can use them.

compiling c++ code using gnu/c getline() on mac osx?

I'm trying to compile a pre-existing c++ package on my mac osx leopard machine, and get the following error:
error: no matching function for call to 'getline(char**, size_t*, FILE*&)'
This is probably because getline() is a GNU specific extension.
Can I somehow make the osx default g++ compiler recognize such GNU specific extensions?
(if not, I could always supply my own implementation or GNUs original one, but I prefer to have a "cleaner" solution if possible)
getline is defined in stdio.h in glibc version 2.10 and later, but not in earlier versions, nor (so far; added 10.5 definitely didn't have getline, and 10.7 definitely does) in the BSD derived libc.
The change in the GNU libraries came about because of a change in the POSIX 2008 standard, which now includes getline.
Presumably, this will propogate to other libc over time. In the mean time, I understand that it is causing trouble for a lot of projects.
You can download a stand alone version from GNU.
Generally, the solution is to use autoconf or some similar tool to determine whether the current platform already has getline or not, and supply your own definition only when needed.
Example:
# configure.ac
AC_CHECK_FUNCS([getline])
// compat.h
#include "config.h"
#ifndef HAVE_GETLINE
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
#endif
// getline.c
ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
/* definition */
}
# Makefile.am
program_LDADD = $(if $(HAVE_GETLINE),,getline.o)
or something along those lines, you'll have to adjust it to match your own program.
I'm not sure I've ever seen that specific definition of 'getline' here is the one I know of which uses c++ streams+strings.
http://www.cplusplus.com/reference/string/getline/