Raspberry error write in i2c socket - sockets

I'm trying to control my domotic house by smartphone, the smartphone sends 3-4 byte to Raspberry via Internet(Wi-Fi) and Raspberry send all those bytes to the corresponding Arduino throught I2C bus(I've got two Arduinos).
When I send the commands to Raspberry it shows "Failed to write to the i2c bus"
Anyone can help me please?
int i2csend(msg_t *pmsg)
{
int fd;
/* Open I2C device */
if ((fd = open(device, O_RDWR)) < 0) error ("Can't open I2C device");
if (ioctl(fd, I2C_SLAVE, arduino_addr) < 0) error ("Can't talk to slave");
if (write(fd, (char *)pmsg, n) < n ) printf ("Failed to write to the i2c bus [1]\n");
else
{
read(fd, (char *)pmsg, n);
printf("Ricevuto il messaggio: %c%c %d %d\n", pmsg->tipo, pmsg->gruppo, pmsg->dato[0], pmsg->dato[1]);
}
close(fd);
return 0;
}

When I've used I2C on the raspi, I've never used the 'open' function in an if statement (like you have in the i2csend() function). Here's a sample from a (working) project of mine:
//open file for i2c interface
int fh=open("/dev/i2c-1",O_RDWR);
if (ioctl(fh, I2C_SLAVE, UIBC_ADDR) < 0){
printf("Couldn't establish contact with the UIBC\n");
}

Related

STM32 I2C scan returns different addresses than Arduino

Good day
The goal is to use the LSM9DS0 with a ST chip.
The situation is that the I2C address as returned by the scanner (ST environment) is not the same to that of Arduino I2C scanner. I am using a STM32 Nucleo-F429 and ESP32 devkit.
When I scan for I2C addresses using the below code, it returns the following four addresses:
0x3A
0x3B
0xD6
0xD7
However I have used this very IMU breakout on a ESP32 before and I noticed that the addresses are not the same. When I run the I2C scanning code I get the following addresses.
0x1D
0x6B
STM32 code: Src files were generated by CubeMX. Let me know if the i2c.h/c are required. But they should be pretty standard.
for (uint16_t i = 0; i < 255; i++)
{
if (HAL_I2C_IsDeviceReady(&hi2c1, i, 5, 50) == HAL_OK)
{
HAL_GPIO_TogglePin(LED_RED_PORT, LED_RED_PIN);
char I2cMessage[10];
sprintf(I2cMessage, "%d , 0x%X\r\n", i, i);
HAL_UART_Transmit(&huart2, (uint8_t *)I2cMessage, strlen(I2cMessage), 10);
}
}
Arduino code:
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(115200);
while (!Serial); // Leonardo: wait for serial monitor
Serial.println("\nI2C Scanner");
}
void loop()
{
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ )
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16)
Serial.print("0");
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Unknown error at address 0x");
if (address<16)
Serial.print("0");
Serial.println(address,HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
delay(5000); // wait 5 seconds for next scan
}
Does anyone know why this is and is it a problem?
I found the answer in the description of the HAL API. The API requires the 7bt address to be bit shifted to the left by 1bit.
Within the file: stm32F4xx_hal_i2c.c the description of the HAL_I2C_IsDeviceReady() API says the following:
* #param DevAddress Target device address: The device 7 bits address value
* in datasheet must be shifted to the left before calling the interface
Thus, change the IsDeviceReady arguments as follows and it will work.
for (uint16_t i = 0; i < 255; i++)
{
if (HAL_I2C_IsDeviceReady(&hi2c1, i<<1, 5, 10) == HAL_OK)
{
// Do crazy stuff
}
}
This worked for me. Hope it helps anyone with the same issue
one can find I2C devices on an ESP32 using the code below:
void I2Cscanner() {
Serial.println ();
Serial.println ("I2C scanner. Scanning ...");
byte count = 0;
Wire.begin();
for (byte i = 8; i < 120; i++)
{
Wire.beginTransmission (i); // Begin I2C transmission Address (i)
if (Wire.endTransmission () == 0) // Receive 0 = success (ACK response)
{
Serial.print ("Found address: ");
Serial.print (i, DEC);
Serial.print (" (0x");
Serial.print (i, HEX); // PCF8574 7 bit address
Serial.println (")");
count++;
}
}
Serial.print ("Found ");
Serial.print (count, DEC); // numbers of devices
Serial.println (" device(s).");
}

Problem in reading packets from tunnel using read()

I have been trying to receive and process the packets from tunnel. There are separate blocks for processing v4 and v6 packets. If the packet does not fall under the either of the categories, they will be dropped. For me, every packets are being dropped during execution. When I used wireshark to capture the packets from the tunnel, I noticed the difference in packet size, i.e., length of the packet. For example, when the length of a received packet in Wireshark is 60 whereas the program prints it 64 as length. I noticed the 4 bytes difference in all packets. I am unable to find out, what I am doing wrong here? Would anyone help me. I also attached the screen of wireshark and program execution for perusal.
Image: Captured packets from tunnel through wireshark and program
#define MTU 1600
void processPacket(const uint8_t *packet, const size_t len) {
//1st octet identifies the IP version
uint8_t version = (*packet) >> 4;
//...
printf("IP version - %d\n", version);
if (version == 4 ) {
//ipv4 packet process ...
} else if (version == 6) {
//ipv6 packet process ...
} else {
//drop packet
printf("Unknown IP version, drop packet\n");
}
}
int main() {
struct ifreq ifr;
int fd;
uint8_t *buffer = (uint8_t *)(malloc(MTU));
ssize_t len;
if ( (fd = open("/dev/net/tun", O_RDWR)) == -1 ) {
perror("Unable to open /dev/net/tun");
exit(EXIT_FAILURE);
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN;
strncpy(ifr.ifr_name, "tun0", IFNAMSIZ);
if ( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) == -1 ) {
perror("Error encountered during ioctl TUNSETIFF");
close(fd);
exit(EXIT_FAILURE);
}
printf("Device tun0 opened\n");
while(1) {
len = read(fd, buffer, MTU);
printf("Read %lu bytes from tun0\n", len);
processPacket(buffer, len);
}
printf("\nPress any key to exit...");
getchar();
close(fd);
}
The tunnel device pre-pends the IP packet with additional information, so the first byte is not the IP version. If you don't need it, you can add IFF_NO_PI to ifr_flags. See kernel documentation.

Linux socket hardware timestamping

I'm working on a project researching about network synchronisation. Since I want to achieve the best performance I'm trying to compare software timestamping results with hardware timestamping ones.
I have followed this previously commented issue: Linux kernel UDP reception timestamp but after several tests I got some problems when trying to get hardware reception timestamps.
My scenario is composed of 2 devices, a PC and a Gateworks Ventana board, both devices are supposed to be waiting for packets to be broadcasted in their network and timestamping their reception times, I have tried this code (some parts have been omitted):
int rc=1;
int flags;
flags = SOF_TIMESTAMPING_RX_HARDWARE
| SOF_TIMESTAMPING_RAW_HARDWARE;
rc = setsockopt(sock, SOL_SOCKET,SO_TIMESTAMPING, &flags, sizeof(flags));
rc = bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
struct msghdr msg;
struct iovec iov;
char pktbuf[2048];
char ctrl[CMSG_SPACE(sizeof(struct timespec))];
struct cmsghdr *cmsg = (struct cmsghdr *) &ctrl;
msg.msg_control = (char *) ctrl;
msg.msg_controllen = sizeof(ctrl);
msg.msg_name = &serv_addr;
msg.msg_namelen = sizeof(serv_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
iov.iov_base = pktbuf;
iov.iov_len = sizeof(pktbuf);
//struct timeval time_kernel, time_user;
//int timediff = 0;
FILE *f = fopen("server.csv", "w");
if (f == NULL) {
error("Error opening file!\n");
exit(1);
}
fprintf(f, "Time\n");
struct timespec ts;
int level, type;
int i;
for (i = 0; i < 10; i++) {
rc = recvmsg(sock, &msg, 0);
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg))
{
level = cmsg->cmsg_level;
type = cmsg->cmsg_type;
if (SOL_SOCKET == level && SO_TIMESTAMPING == type) {
//ts = (struct timespec *) CMSG_DATA(cmsg);
memcpy(&ts, CMSG_DATA(cmsg), sizeof(ts));
printf("HW TIMESTAMP %ld.%09ld\n", (long)ts.tv_sec, (long)ts.tv_nsec);
}
}
}
printf("COMPLETED\n");
fclose(f);
close(sock);
return 0;
}
In both devices the output I get after receiving a packet:
HW TIMESTAMP 0.000000000
On the other hand if with the same code my flags are:
flags = SOF_TIMESTAMPING_RX_HARDWARE
| SOF_TIMESTAMPING_RX_SOFTWARE
| SOF_TIMESTAMPING_SOFTWARE;
I get proper timestamps:
HW TIMESTAMP 1551721801.970270543
However, they seem to be software-timestamping ones. What would be the correct solution / method to handle hardware timestamping for packets received?
First of all, use ethtool -T "your NIC" to make sure your hardware supports the hardware timestamping feature.
You need to explicitly tell the Linux to enable the hardware timestamping feature of your NIC. In order to to that, you need to have a ioctl() call.
What you have to do is to call it with SIOCSHWTSTAMP, which is a device request code to indicate which device you want to handle as well as what you want to do. For example, there is a code called CDROMSTOP to stop the cdrom drive.
You also need to use a ifreq struct to configure your NIC.
You need something like this:
struct ifreq ifconfig;
strncpy(config.ifr_name, "your NIC name", sizeof(ifconfig.ifr_name));
ioctl("your file descriptor" , SIOCSHWTSTAMP, &ifconfig);
Here are some pages that you can look up to:
ioctl manual page,
ifreq manual page,
Read part 3.

Kernel driver i2c Develop

On my board I have an I2C device that sets some register.
g_I2cDevFd = open("/dev/" UMAP_DEVNAME_I2C, O_RDWR, 0);
if (g_I2cDevFd < 0)
{
HI_FATAL_I2C("open I2C err.\n");
HI_I2C_UNLOCK();
return HI_ERR_I2C_OPEN_ERR;
}
How can I do that?
Best Regards
Your question is not clear much. But for I2C communication in Linux Os, Please refer this link Interfacing_with_I2C_Devices
Please use your device path in define UMAP_DEVNAME_I2C itself. ie, #define UMAP_DEVNAME_I2C "/dev/your_i2c_device"
Or use sprintf if you cant edit UMAP_DEVNAME_I2C ie,
char buff[100] = {0}; // size you can change according to your requirement
sprintf(buff,"/dev/%s",UMAP_DEVNAME_I2C);
g_I2cDevFd = open(buff, O_RDWR, 0);
/* Error check for open here*/
int addr = 0xFF; // 0xFF is Invalid, Give I2C address of your device
if (ioctl(g_I2cDevFd, 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 */
exit(1);
}
/* Write or Read*/

Bluetooth connection refused

I am working on a Bluetooth project involving one Arduino (with Seeed bluetooth shield v2.0) and one ubuntu laptop. Basically, I want message exchanges between the Arduino and the laptop. I paired the Arduino bluetooth shield with the laptop. Then I use the code below (on the laptop) to test. The Arduino is set as a Slave. And the laptop sends a test message.
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>
int main(int argc, char **argv){
struct sockaddr_rc addr = {0};
int s, status;
char buf[1024] = {0};
char dest[18] = "00:0E:EA:CF:1E:62";
for (size_t i = 1; i <= 30; i++) {
addr.rc_channel = i;
str2ba(dest, &addr.rc_bdaddr);
// connect to server
s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
status = connect(s, (struct sockaddr *)&addr, sizeof(addr));
if(status == 0) {
status = send(s, "Hello!", 6, 0);
status = recv(s, buf, sizeof(buf), 0);
if(status > 0)
printf("received %s\n", buf);
break;
}
}
if(status < 0)
perror("send error");
close(s);
return 0;
}
Below is the test code at Arduino side.
#include <SoftwareSerial.h> //Software Serial Port
#define RxD 7
#define TxD 6
SoftwareSerial bt(RxD,TxD);
char buf[100];
size_t idx;
void setup() {
Serial.begin(9600);
bt.begin(9600);
pinMode(RxD, INPUT);
pinMode(TxD, OUTPUT);
setupBlueToothConnection();
}
void loop() {
Serial.println("Waiting ...");
idx = 0;
memset(buf, sizeof(buf), 0);
while(bt.available()){
buf[idx] = bt.read();
idx++;
}
while(idx >= 0){
bt.write(buf[idx]);
idx--;
}
delay(1000);
}
void setupBlueToothConnection() {
bt.print("AT");
delay(400);
bt.print("AT+DEFAULT"); // Restore all setup value to factory setup
delay(2000);
bt.print("AT+LADD?"); // Restore all setup value to factory setup
delay(2000);
bt.print("AT+NAMEProver"); // set the bluetooth name as "SeeedBTSlave"
delay(400);
bt.print("AT+PIN0000"); // set the pair code to connect
delay(400);
bt.print("AT+ROLE?");
delay(400);
bt.print("AT+AUTH0");
delay(400);
bt.flush();
}
I receive error message: "send error: Connection refused". What is the problem? Can some help me with this? Thanks!
Update: I guess it might be the problem with port number. But I checked the datasheet for Seeed Bluetooth shield v2.0 and has not found any clue regarding to setup port number.
Most common problem with Bluetooth on Arduino except for code is having Arduino connected to your PC over USB cable and trying to use Bluetooth, as far as I am aware most of the shields connect directly to hardware RX and TX of the Arduino board, which are the same ports used for USB communication to your PC.
So is your Arduino connected over a USB port to your PC?