I have build custom image for Raspberry Pi 4 using Yocto. I connected microswitch to GPIO17 and I want to read its state in user space application. The event occures when I press switch, which I'm 100% sure because I patched gpio-keys driver adding custom log messages:
[ 185.053346] <gpio_keys_gpio_isr>
[ 185.076626] <gpio_keys_gpio_report_event> type: 1 | code: 777 | state: 0
[ 185.265685] <gpio_keys_gpio_isr>
[ 185.268975] <gpio_keys_gpio_isr>
[ 185.292253] <gpio_keys_gpio_report_event> type: 1 | code: 777 | state: 1
But for some reason I cannot read button state from user space application:
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include <string.h>
#define DP_EVENT_INPUT "/dev/input/event0"
int main(int argc, char **argv) {
unsigned int key_states[2];
struct input_event evt;
int fd;
memset(key_states, 0, sizeof(key_states));
if ((fd = open(DP_EVENT_INPUT, O_RDONLY)) < 0)
{
if (errno == EACCES && getuid() != 0) {
fprintf(stderr, "You do not have access to %s. Try "
"running as root instead.\n",
DP_EVENT_INPUT);
exit(EXIT_FAILURE);
}
}
while(1) {
ioctl(fd, EVIOCGKEYCODE, key_states);
if(read(fd, &evt, sizeof(struct input_event)) > 0) {
if(evt.type == EV_KEY) {
printf("EVENT type: EV_KEY\n");
}
else {
printf("No event!\n");
}
}
}
}
Application hangs on read() call...
From here I read that to read button state I need to use ioctl with EVIOCG* value so I used EVIOCGKEYCODE which means: "get keycode".
Bellow I attaching my device tree overlay:
/dts-v1/;
/plugin/;
#include <dt-bindings/pinctrl/bcm2835.h>
#include <dt-bindings/gpio/gpio.h>
#include "dt-bindings/input/linux-event-codes.h"
/ {
compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
fragment#0 {
target = <&gpio>;
__overlay__ {
// Configure the gpio pin controller
buttonpin: button-gpio {
brcm,pins = <17>;
brcm,function = <BCM2835_FSEL_GPIO_IN>;
brcm,pull = <BCM2835_PUD_UP>;
};
};
};
fragment#1 {
target-path = "/";
__overlay__ {
gpio-keys {
compatible = "gpio-keys";
pinctrl-names = "default";
pinctrl-0 = <&buttonpin>;
status = "okay";
sw1 {
label = "GPIO Key USER1";
linux,code = <777>;
linux,input-type = <EV_KEY>;
debounce-interval = <20>;
gpios = <&gpio 17 GPIO_ACTIVE_LOW>;
};
};
};
};
};
Can anyone tell me what I'm doing wrong?
Thanks
I have tested my RF96W LoRa boards with the Lolin Boards, it is working fine, But when I started to interface these Lora boards with stm32f030r8t6 based controller, I cant receive any data. Though I have tried to kept SPI configuration according to Lolin boards.
Board Wiring is same as SPI requirements.
Lolin working Code:
#include <SPI.h>
#include <RH_RF95.h>
#define RFM95_CS 15
#define RFM95_RST 16
#define RFM95_INT 5
RH_RF95 rf95(RFM95_CS, RFM95_INT);
void setup()
{
Serial.begin(9600);
while (!Serial) ; // Wait for serial port to be available
rf95.setModemConfig(RH_RF95::Bw125Cr48Sf4096);
while (!rf95.init()) {
Serial.println("LoRa radio init failed");
}
}
void loop()
{
Serial.println("Sending to rf95_server");
uint8_t data[] = "Hello World!";
rf95.send(data, sizeof(data));
rf95.waitPacketSent();
// Now wait for a reply
uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
uint8_t len = sizeof(buf);
if (rf95.waitAvailableTimeout(3000)) {
// Should be a reply message for us now
if (rf95.recv(buf, &len)) {
Serial.print("got reply: ");
Serial.println((char*)buf);
// Serial.print("RSSI: ");
// Serial.println(rf95.lastRssi(), DEC);
} else {
Serial.println("recv failed");
}
} else {
Serial.println("No reply, is rf95_server running?");
}
// delay(400);
}
STM32F030R8T6 Controller not working code:
#include <stdio.h>
#include <RF95.h>
uint8_t init_failed = 0;
uint8_t Tx_buff[] = "Hello World!";
uint8_t Rx_buff[RH_RF95_MAX_MESSAGE_LEN];
uint8_t rssi_value = 0;
uint16_t len = 0;
void SystemClock_Config(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI1_Init();
// RF95_setModemConfig(Bw125Cr48Sf4096);
if(!RF95_Init()) {
init_failed = 1;
}
while (1) {
// RF95_send(Tx_buff);
// RF95_waitPacketSent();
// if(RF95_available_Timeout(3000)){
// RF95_receive(Rx_buff);
// }
if (RF95_available()) {
if (RF95_receive(Rx_buff)) {
len = sizeof(Rx_buff);
}
if (len) {
uint8_t data[] = "And hello back to you";
RF95_send(data);
RF95_waitPacketSent();
}
}
}
}
For Lolin board library is also from GitHub.
For ST I'm using RFM95 library from GitHub.
I am using rs485 to communicate between two Arduino nano. I have connected a 4 bit I2C display to one of the Arduino nano. When the nano receives data via Rs485 from the master nano, the data is displayed on the I2C display. But the issue is that I am only able to use one of those things i.e. if I am receiving data I am not able to display it on the I2C display and if I am displaying, then I am not able to receive the data.
Has someone tried doing it together?
Code for master nano
// rs485 master
void setup() {
Serial.begin(115200);
pinMode(2,OUTPUT); //DE/RE pin
}
int i;
String s = "s1b01n01";
void loop() {
digitalWrite(2,HIGH); // high for transmiting
for(i=0;i<=8;i++) {
Serial.print(s[i]);
}
digitalWrite(2,LOW);
}
Code for Slave nano
#include <TM1637Display.h>
#define CLK 4
#define DIO 16
#define ExtEnable 2 //DE/RE pin
TM1637Display display = TM1637Display(CLK, DIO); // Create display object of type TM1637Display:
const uint8_t data[] = {0xff, 0xff, 0xff, 0xff};// Create array that turns all segments on:
const uint8_t blank[] = {0x00, 0x00, 0x00, 0x00}; // Create array that turns all segments off:
int i = 0;
char add[8], c;
char address[] = {'s', '1', 'b', '0', '1', 'n', '0', '1'};
void setup() {
Serial.begin(115200);
pinMode(ExtEnable, OUTPUT); //DE/RE pin
display.clear();
delay(1000);
display.setBrightness(7); // Set the brightness:
}
void loop() {
digitalWrite(ExtEnable, LOW); // low for receiving
if (Serial.available()) {
c = Serial.read();
Serial.print(c);
add[i] = c;
i++;
digitalWrite(ExtEnable, HIGH);
//display.showNumberDec(3); //print on display
}
Serial.print("add");
Serial.println(add);
if(add == address) { // to check
display.showNumberDec(3); //print on display
}
}
This program is intended to communicate over an unreliable serial channel via a PL2303 usb converter with a distant microcontroller. The main loop uses g_io_add_watch to listen for data from the micro. It then calls g_io_read_chars to read the data and g_io_write_chars to send a one-byte acknowledge. The micro echos this back. The read and write are called from within ReadStationMessage. If the micro is slow to respond, the ReadStationMessage() function is called twice, once to read the data and again to receive the echo. However, if it responds immediately, ReadStationMessage() is called only once and the echo byte is appended to the data. I don't understand how this is possible when g_io_write_chars does not send the acknowledge until after g_io_read_chars returns and the micro does nothing until it receives the acknowledge.
#include <gtk/gtk.h>
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
int set_interface_attribs(int fd, int speed)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
g_print("Error from tcgetattr: %s\n", strerror(errno));
return -1; }
cfmakeraw(&tty);
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cc[VMIN] = 0; tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
g_print("Error from tcsetattr: %s\n", strerror(errno));
return -1; }
return 0;
}
static gboolean ReadStationMessage( GIOChannel *channel, GIOCondition condition, guchar* user_data )
{
guchar buf[128];
gsize bytes_read, bytes_written;
gint i;
g_print("\nentering ReadStationMessage\n");
g_io_channel_read_chars( channel, buf, 128, &bytes_read, NULL );
for( i=0; i<bytes_read; i++ ) g_print("%u ", buf[i]);
buf[0] = 0;
g_io_channel_write_chars( channel, buf, 1, &bytes_written, NULL );
return TRUE;
}
int main( int argc, char *argv[] )
{
char *portname = "/dev/ttyUSB0";
gint fd;
GIOChannel *channel;
static guchar user_data[128];
GError *error=NULL;
guint EventSource_id;
fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC );
set_interface_attribs(fd, B9600);
channel = g_io_channel_unix_new(fd);
g_io_channel_set_encoding(channel, NULL, &error); // raw data, no encoding
GIOCondition condition = G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
gtk_init (&argc, &argv);
EventSource_id = g_io_add_watch( channel, condition, (GIOFunc) ReadStationMessage, user_data );
return 0;
}
Fixed! I need to g-io-channel-flush after write.
I referenced C code on this website: https://gist.github.com/austinmarton/2862515
Here is a image to explain:
I edit it at two parts, one pat is for ethertype(change 0x0800 to a custom-protocol 0x1234)
and another part is deleting code for IP header processing (because original code is based on IP, but I need a raw ethernet frame).
I used wireshark to detect packets, and I can receive the packets I sent(in left of image),and I can see send.out exactly sending packets(bottom right of image). But recv.out cannot receive packet !?(upper right of image).
However, if I use 0x0800 for protocol, recv.out can receive packets from outside, but still cannot receive the packets I sent.
Is there any mistake for setting socket
Here is my code:
send.c
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
#define MY_DEST_MAC0 0xbc
#define MY_DEST_MAC1 0xee
#define MY_DEST_MAC2 0x7b
#define MY_DEST_MAC3 0x75
#define MY_DEST_MAC4 0x56
#define MY_DEST_MAC5 0x2a
#define DEFAULT_IF "eth0"
#define BUF_SIZ 1024
int main(int argc, char *argv[])
{
int sockfd;
struct ifreq if_idx;
struct ifreq if_mac;
int tx_len = 0;
char sendbuf[BUF_SIZ];
struct ether_header *eh = (struct ether_header *) sendbuf; /*structure*/
struct iphdr *iph = (struct iphdr *) (sendbuf + sizeof(struct ether_header));
struct sockaddr_ll socket_address;
char ifName[IFNAMSIZ];
unsigned short proto = 0x1234;
/* Get interface name *//*eth0*/
if (argc > 1)
strcpy(ifName, argv[1]);
else
strcpy(ifName, DEFAULT_IF);
/* Open RAW socket to send on *//*IPv4*/
if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(proto))) == -1) {
perror("socket");
}
/* Get the index of the interface to send on *//*0*/
memset(&if_idx, 0, sizeof(struct ifreq));
strncpy(if_idx.ifr_name, ifName, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0)/*save INDEX info into if_idx*/
perror("SIOCGIFINDEX");
/* Get the MAC address of the interface to send on *//*local*//*save MAC info into if_mac*/
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, ifName, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0)
perror("SIOCGIFHWADDR");
/* Construct the Ethernet header */
memset(sendbuf, 0, BUF_SIZ);
/* Ethernet header */
eh->ether_shost[0] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0];
eh->ether_shost[1] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1];
eh->ether_shost[2] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2];
eh->ether_shost[3] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3];
eh->ether_shost[4] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4];
eh->ether_shost[5] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5];
eh->ether_dhost[0] = MY_DEST_MAC0;
eh->ether_dhost[1] = MY_DEST_MAC1;
eh->ether_dhost[2] = MY_DEST_MAC2;
eh->ether_dhost[3] = MY_DEST_MAC3;
eh->ether_dhost[4] = MY_DEST_MAC4;
eh->ether_dhost[5] = MY_DEST_MAC5;
/* Ethertype field */
eh->ether_type = htons(proto);
tx_len += sizeof(struct ether_header);
/* Packet data */
sendbuf[tx_len++] = "h";
sendbuf[tx_len++] = "e";
sendbuf[tx_len++] = "l";
sendbuf[tx_len++] = "l";
sendbuf[tx_len++] = "o";
/* Index of the network device */
socket_address.sll_ifindex = if_idx.ifr_ifindex;
/* Address length*/
socket_address.sll_halen = ETH_ALEN;
/* Destination MAC */
socket_address.sll_addr[0] = MY_DEST_MAC0;
socket_address.sll_addr[1] = MY_DEST_MAC1;
socket_address.sll_addr[2] = MY_DEST_MAC2;
socket_address.sll_addr[3] = MY_DEST_MAC3;
socket_address.sll_addr[4] = MY_DEST_MAC4;
socket_address.sll_addr[5] = MY_DEST_MAC5;
/* Send packet */
int cnt=0;
while(cnt<5){
if (sendto(sockfd, sendbuf, tx_len, 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0)
printf("Send failed\n");
else
printf("success!\n");
cnt++;
}
return 0;
}
recv.c
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
#define DEST_MAC0 0xbc
#define DEST_MAC1 0xee
#define DEST_MAC2 0x7b
#define DEST_MAC3 0x75
#define DEST_MAC4 0x56
#define DEST_MAC5 0x2a
#define ETHER_TYPE 0x1234
#define DEFAULT_IF "eth0"
#define BUF_SIZ 1024
int main(int argc, char *argv[])
{
char sender[INET6_ADDRSTRLEN];
int sockfd, ret, i;
int sockopt;
ssize_t numbytes;
struct ifreq ifopts; /* set promiscuous mode */
struct sockaddr_storage their_addr;
uint8_t buf[BUF_SIZ];
char ifName[IFNAMSIZ];
/* Get interface name *//*eth0*/
if (argc > 1)
strcpy(ifName, argv[1]);
else
strcpy(ifName, DEFAULT_IF);
/* Header structures */
struct ether_header *eh = (struct ether_header *) buf;
/* Open PF_PACKET socket, listening for EtherType ETHER_TYPE *//*0x1234*/
if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE))) == -1) {
perror("listener: socket");
return -1;
}
/* Set interface to promiscuous mode - do we need to do this every time? *//*cpy ifname into ifr_name*/
strncpy(ifopts.ifr_name, ifName, IFNAMSIZ-1);
ioctl(sockfd, SIOCGIFFLAGS, &ifopts); /*set promisc mode*/
ifopts.ifr_flags |= IFF_PROMISC;
ioctl(sockfd, SIOCSIFFLAGS, &ifopts);
/* Allow the socket to be reused - incase connection is closed prematurely */
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) {
perror("setsockopt");
close(sockfd);
exit(EXIT_FAILURE);
}
/* Bind to device */
if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, IFNAMSIZ-1) == -1) {
perror("SO_BINDTODEVICE");
close(sockfd);
exit(EXIT_FAILURE);
}
repeat: printf("listener: Waiting to recvfrom...\n");
numbytes = recvfrom(sockfd, buf, BUF_SIZ, 0, NULL, NULL);
printf("listener: got packet %lu bytes\n", numbytes);
/* Check the packet is for me */
if (eh->ether_dhost[0] == DEST_MAC0 &&
eh->ether_dhost[1] == DEST_MAC1 &&
eh->ether_dhost[2] == DEST_MAC2 &&
eh->ether_dhost[3] == DEST_MAC3 &&
eh->ether_dhost[4] == DEST_MAC4 &&
eh->ether_dhost[5] == DEST_MAC5) {
printf("Correct destination MAC address\n");
} else {
printf("Wrong destination MAC: %x:%x:%x:%x:%x:%x\n",
eh->ether_dhost[0],
eh->ether_dhost[1],
eh->ether_dhost[2],
eh->ether_dhost[3],
eh->ether_dhost[4],
eh->ether_dhost[5]);
ret = -1;
goto done;
}
/* Print packet */
printf("\tData:");
for (i=0; i<numbytes; i++) printf("%02x:", buf[i]);
printf("\n");
done: goto repeat;
close(sockfd);
return ret;
}
you can get All frames from your target with below changes in your receive code :
please replace line :
if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE))) == -1) {
with this line :
if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
Because in your original code you changed normal ethernet header type then OS can not detect its process listener(your program) and get it to you but when you set this line, OS can get you all results so you can get your special answers.
I'm starting to do socket programming so someone should confirm this.
I'm pretty sure the interface will drop the packet because the source and destination mac are the same... try using another PC and change the destination mac on each side to confirm this (virtual machines work as well)
I have also used a similar code to transfer Ethernet frames. This type of socket does not work locally. As #Goncalo suggested use a different PC or if you have two NICs on your PC you should use them. Here is the Code I used to receive Frames.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <sys/ioctl.h>
union ethframe
{
struct
{
struct ethhdr header;
unsigned char data[ETH_DATA_LEN];
} field;
unsigned char buffer[ETH_FRAME_LEN];
};
int main(int argc, char **argv) {
char *iface = "eth1";
unsigned char dest[ETH_ALEN]
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
unsigned short proto = 0x1234;
int recv_result,i;
char buff[ETH_FRAME_LEN];
unsigned short data_len;
int s;
if ((s = socket(AF_PACKET, SOCK_RAW, htons(proto))) < 0) {
printf("Error: could not open socket\n");
return -1;
}
struct ifreq buffer;
int ifindex;
memset(&buffer, 0x00, sizeof(buffer));
strncpy(buffer.ifr_name, iface, IFNAMSIZ);
if (ioctl(s, SIOCGIFINDEX, &buffer) < 0) {
printf("Error: could not get interface index\n");
close(s);
return -1;
}
ifindex = buffer.ifr_ifindex;
unsigned char source[ETH_ALEN];
if (ioctl(s, SIOCGIFHWADDR, &buffer) < 0) {
printf("Error: could not get interface address\n");
close(s);
return -1;
}
memcpy((void*)source, (void*)(buffer.ifr_hwaddr.sa_data),
ETH_ALEN);
struct sockaddr_ll saddrll;
memset((void*)&saddrll, 0, sizeof(saddrll));
saddrll.sll_family = PF_PACKET;
saddrll.sll_ifindex = ifindex;
saddrll.sll_halen = ETH_ALEN;
memcpy((void*)(saddrll.sll_addr), (void*)dest, ETH_ALEN);
socklen_t sll_len = (socklen_t)sizeof(saddrll);
if (recv_result = recvfrom(s, buff, ETH_FRAME_LEN, 0,
(struct sockaddr *)&saddrll, &sll_len) > 0)
printf("Success!\n");
else
printf("Error, could not send\n");
data_len=sizeof(buff);
printf("\tData:");
for (i=0; i<data_len; i++) printf("%c", buff[i]);
printf("\tDone: \n");
close(s);
return 0;
}