Full Code of thomasfla/Linux-ESPNOW for AI

master 7ca8af0b1cb5 cached
28 files
60.1 KB
23.2k tokens
38 symbols
1 requests
Download .txt
Repository: thomasfla/Linux-ESPNOW
Branch: master
Commit: 7ca8af0b1cb5
Files: 28
Total size: 60.1 KB

Directory structure:
gitextract_42a6adbu/

├── .gitignore
├── ESP32-Test/
│   ├── ESP32-Test.ino
│   ├── PYTHON_serial/
│   │   └── serial_logger.py
│   ├── p_histogram.ino
│   ├── t_callbacks.ino
│   └── z_setup_loop.ino
├── ESP8266-Test/
│   ├── ESP8266-Test.ino
│   └── serial_logger.py
├── ESP8266_Echo/
│   └── ESP8266_Echo.ino
├── ESPNOW_lib/
│   ├── Makefile
│   ├── README.MD
│   └── src/
│       ├── ESPNOW_manager.cpp
│       ├── ESPNOW_types.cpp
│       ├── Includes/
│       │   ├── ESPNOW_manager.h
│       │   └── ESPNOW_types.h
│       └── main.cpp
├── LICENSE
├── Lab/
│   └── EspNowPacket/
│       ├── EspNowPacket.c
│       └── Makefile
├── README.md
├── wifiRawEcho/
│   ├── Includes/
│   │   └── ESPNOW_packet.h
│   ├── Makefile
│   └── src/
│       ├── ESPNOW_packet.c
│       └── main.c
├── wifiRawReceiver/
│   ├── Makefile
│   └── main.c
└── wifiRawSender/
    ├── Makefile
    └── main.c

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Prerequisites
*.d

# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
*.pch

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Fortran module files
*.mod
*.smod

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app

wifiRawReceiver/bin/

wifiRawEcho/bin/

ESPNOW_lib/bin/

ESP32-Test/PYTHON_serial/test\.txt

*.txt

*.pyc

*.png

*.pcapng

ESP32-Test/PYTHON_serial/channel_study\.py

ESP32-Test/PYTHON_serial/datarate_study\.py

ESP32-Test/PYTHON_serial/trash


================================================
FILE: ESP32-Test/ESP32-Test.ino
================================================
#include <esp_now.h>
#include <WiFi.h>
#include <esp_wifi_internal.h>

#include <Ticker.h>  //Ticker Library

#define CHANNEL 9
#define DATARATE WIFI_PHY_RATE_24M

#define N_BATCH 1000

static byte dest_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; //broadcast
//static byte dest_mac[6] = {0xf8, 0x1a, 0x67, 0xb7, 0xeb, 0x0b}; //computers
//static byte dest_mac[6] ={0x84, 0xF3, 0xEB, 0x73, 0x55, 0x1E}; //ESP8266 (2) Echo mode

esp_now_peer_info_t peer;
wifi_config_t wifi_config;

Ticker blinker;

#define DATA_LEN 127
uint8_t txData[DATA_LEN];

void init_data() {
  for(int i=0;i<DATA_LEN;i++) {
    txData[i] = 0x14;
  }
}


================================================
FILE: ESP32-Test/PYTHON_serial/serial_logger.py
================================================
import serial
import sys
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator

base = "0123456789+/abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

log_file = None
ser = None

n_plot = 0

if(len(sys.argv)==3):
	log_file = open(sys.argv[2],"a+")
	ser = serial.Serial(sys.argv[1], 115200)
	ser.flushInput()

elif(len(sys.argv)==2):
	ser = open(sys.argv[1],"r")


assert(len(sys.argv)==2 or len(sys.argv)==3)


print "Serial opened : " + str(sys.argv[1])


def read(display=True):
	line = ser.readline().rstrip()
	if(log_file != None):
		log_file.write(line + '\n')
	if(display):
		print('\t' + line)
	return line

def read_int(i):
	return int(read().split('\t')[i])

def decode_histo():
	units = read().split('\t')[1]
	bounds = list(map(int, read().split('\t')[1:]))
	nb_values = read_int(1)
	histo = list(map(int, read(False).split('\t')[1:]))
	avg = read_int(1)
	recv = read_int(1)
	sent = read_int(1)
	recv_detail = read(False)

	overtimed = histo[-1]
	histo = histo[:-1]
	nb_values = nb_values-1

	bounds = list(map(lambda x : x/1000., bounds))
	x_axis = [(x+0.5)*(bounds[1]-bounds[0])/nb_values+bounds[0] for x in range(nb_values)]
	

	histo_cumulate = [0 for i in range(len(histo))]
	histo_cumulate[0] = histo[0]
	for i in range(1, len(histo)):
		histo_cumulate[i] = histo_cumulate[i-1] + histo[i]

	histo = list(map(lambda x:x*100./sent, histo))
	histo_cumulate = list(map(lambda x: x*100./sent, histo_cumulate))


	histo_loss = [0 for _ in range(20)]
	current_serie = 0

	for i in range(len(recv_detail)):
		word = base.index(recv_detail[i])
		for j in range(6):
			if(word&(1<<j) == 0):
				current_serie += 1
			else:
				histo_loss[current_serie] += 1
				current_serie = 0


	x_axis_loss = [i for i in range(len(histo_loss))]
	total = 0
	for h in histo_loss:
		total+=h
	print(total)

	plt.ion()

	fig = plt.figure(2*n_plot)
	ax1 = fig.add_subplot(111)
	ax2 = ax1.twinx()

	plt.title('(' + str(n_plot) + ')' + 'Overall receive ' + str(recv*100./sent) + '% ; Sent : ' + str(sent) + ' ; Longer than ' + str(bounds[1]) + units + ' : ' + str(overtimed))

	ax1.plot(x_axis, histo, color='tab:blue')
	ax1.set_ylabel('% packets', color='tab:blue')
	ax1.tick_params(axis='y', labelcolor='tab:blue')
	ax1.set_yticks([i*0.5  for i in range(int(max(histo)+1)*2)])

	ax1.set_xticks([i*(bounds[1]-bounds[0])/10.+bounds[0]  for i in range(11)])


	ax2.plot(x_axis, histo_cumulate, color='tab:red')
	ax2.set_ylabel('% packets', color='tab:red')
	ax2.tick_params(axis='y', labelcolor='tab:red')
	ax2.set_yticks([i*10  for i in range(11)])

	ax2.plot([x_axis[0], x_axis[-1]], [95, 95], color='tab:orange')

	ax1.set_xlabel('Delay ( 1000' + units + ') ; Avg = ' + str(avg) + units)

	fig.tight_layout()
	fig.legend(["histogram", "cumulated", "95%", "hello"])
	plt.grid()

	plt.plot()




	plt.ion()

	fig = plt.figure(2*n_plot+1)
	ax = fig.add_subplot(111)

	plt.title('(' + str(n_plot) + ')' + 'Detail receive ')

	plt.bar(x_axis_loss,histo_loss)
	ax.set_ylabel('# groups')
	ax.set_xlabel('group size')
	ax.set_xticks(x_axis_loss)

	plt.grid()

	plt.plot()


while n_plot < 3:
	line = read(False)
	if("----------" in line):
		n_plot+=1
		print("\033[31mHisto " + str(n_plot) + " \033[31mreceived\033[0m")
		decode_histo()
	else:
		print("\033[34mLine not recognized \033[0m >> \033[33m" + line + "\033[0m")
	
try :
	raw_input("Press [enter] to continue.")
except:
	pass

================================================
FILE: ESP32-Test/p_histogram.ino
================================================
#define HISTO_INF 0
#define HISTO_SUP 10000
#define HISTO_N_STEP 100

#define recv_list_len N_BATCH/6
#define packet_received(p) recv_list[p/6] |= 1<<p%6

char base[64] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
byte recv_list[recv_list_len];
int histogram[HISTO_N_STEP];
int histogram_higher;
int histogram_lower;
int error_recv;
int receiveNb;
int error_send;
double avg;

long batchStart =0;

unsigned long n_sent;

void init_histo() {
  for(int i=0;i<recv_list_len;i++) {
    recv_list[i] = 0;
  }
  for(int i=0;i<HISTO_N_STEP;i++) {
    histogram[i] = 0;
  }
  histogram_higher = 0;
  histogram_lower = 0;
  error_recv=0;
  error_send=0;
  receiveNb=0;
  avg=0;
}

int fill_histo(long value, int packet_nb) {
  int index = (value-HISTO_INF) * HISTO_N_STEP / (HISTO_SUP - HISTO_INF);
  if(index >= HISTO_N_STEP) {
    histogram_higher++;
  } else if(index < 0) {
    histogram_lower++;
  } else {
    histogram[index]++;
  }

  packet_received(packet_nb);
  receiveNb++;
  avg += value;
}

void print_histo() {
  Serial.println("----------");
  Serial.printf("Units :\tus");
  Serial.println();
  Serial.printf("Bounds :\t%d\t%d", HISTO_INF, HISTO_SUP);
  Serial.println();
  Serial.printf("Nb_values :\t%d", HISTO_N_STEP);
  Serial.println();
  for(int i=0;i<HISTO_N_STEP;i++) {
    Serial.printf("%d\t", histogram[i]);
  }
  Serial.printf("%d",histogram_higher);
  
  Serial.println();
  Serial.printf("Average :\t%d\t", receiveNb != 0 ? int(avg/receiveNb) : -1);
  Serial.println();
  Serial.printf("Received :\t%d", receiveNb);
  Serial.println();
  Serial.printf("Sent :\t%d", n_sent-error_send);
  Serial.println();
  for(int i=0;i<recv_list_len;i++) {
    Serial.printf("%c",base[recv_list[i]]);
  }
  Serial.println();
}


================================================
FILE: ESP32-Test/t_callbacks.ino
================================================
void sendData() {
  if(n_sent < N_BATCH) {
    long mytime = micros();
    int packet_nb = n_sent - error_send;
    memcpy(txData, &mytime, sizeof(mytime));
    memcpy(txData+sizeof(mytime), &packet_nb, sizeof(packet_nb));
    esp_now_send(peer.peer_addr, txData, sizeof(txData[0])*DATA_LEN);
    n_sent++;
  }
}


void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  if(status != ESP_OK) {
    error_send++;
  }
}


void OnDataRecv(const uint8_t *mac, const uint8_t *rxData, int len) {
  long receiveTime = micros();
  long sendTime;
  int packet_nb;
      
    if(len>sizeof(sendTime)) {
      memcpy(&sendTime, rxData, sizeof(sendTime));
      memcpy(&packet_nb, rxData+sizeof(sendTime), sizeof(packet_nb));

      if(sendTime>batchStart) {
        fill_histo(receiveTime - sendTime, packet_nb);
      }
    } else {
      error_recv++;
    }
}


================================================
FILE: ESP32-Test/z_setup_loop.ino
================================================
#define TRY_ESP_ACTION(action, name) if(action == ESP_OK) {Serial.println("\t+ "+String(name));} else {Serial.println("----------Error while " + String(name) + " !---------------");}


void setup() {
  Serial.begin(115200);

  WiFi.disconnect();
  //Set device in STA mode to begin with

  WiFi.mode(WIFI_STA);
  
  Serial.println("ESPNow/Basic/Master Example");
  // This is the mac address of the Master in Station Mode
  Serial.print("STA MAC: "); Serial.println(WiFi.macAddress());

  TRY_ESP_ACTION( esp_wifi_stop(), "stop WIFI");
  
  TRY_ESP_ACTION( esp_wifi_deinit(), "De init");

  wifi_init_config_t my_config = WIFI_INIT_CONFIG_DEFAULT();
  my_config.ampdu_tx_enable = 0;
  
  TRY_ESP_ACTION( esp_wifi_init(&my_config), "Disable AMPDU");
  
  TRY_ESP_ACTION( esp_wifi_start(), "Restart WiFi");

  TRY_ESP_ACTION( esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE), "Set channel");

  TRY_ESP_ACTION( esp_wifi_internal_set_fix_rate(ESP_IF_WIFI_STA, true, DATARATE), "Fixed rate set up");

  TRY_ESP_ACTION( esp_now_init(), "ESPNow Init");

  TRY_ESP_ACTION(  esp_now_register_send_cb(OnDataSent), "Attach send callback");
  
  TRY_ESP_ACTION( esp_now_register_recv_cb(OnDataRecv), "Attach recv callback");
  
  memset(&peer, 0, sizeof(peer));

  for (int ii = 0; ii < 6; ++ii ) {
    peer.peer_addr[ii] = (uint8_t) dest_mac[ii];
  }
  
  peer.channel = CHANNEL; // pick a channel
  peer.encrypt = 0; // no encryption
      
  TRY_ESP_ACTION( esp_now_add_peer(&peer), "Add peer");

  n_sent = 0;
  init_data();
  blinker.attach(0.001, sendData);
}

void loop() {
  if(n_sent >= N_BATCH) {
    delay(2000);
    
    print_histo();
    init_histo();
    
    n_sent=0;
    batchStart = micros();
    
  } else {
    yield();
  }
}


================================================
FILE: ESP8266-Test/ESP8266-Test.ino
================================================
/*
   19/02/2019 Mac adress modified : Dell laptop

  Master/Server:
    Sends a 100Byte ESPNOW data block, and awaits a response
    SLAVE ADDRESS[84:F3:EB:B3:66:CC]
    SELF=84:F3:EB:73:55:0D

    
*/


#include <ESP8266WiFi.h>
extern "C" {
#include <espnow.h>
}

#include <Ticker.h>  //Ticker Library

Ticker blinker;

#define WIFI_CHANNEL 1

//byte selfmac[6] = {0xf8, 0x1a, 0x67, 0xb7, 0xeb, 0x0b};
byte selfmac[6] = {0x84, 0xF3, 0xEB, 0x73, 0x55, 0x0D};

#define NB_TRIES 1000

#define HISTO_INF 0
#define HISTO_SUP 10000
#define HISTO_N_STEP 10

int histogram[HISTO_N_STEP];
int histogram_higher;
int histogram_lower;
int error_nb;
int receiveNb;
double avg;

long batchStart =0;

bool sendNew = true;

//MAC ADDRESS OF THE DEVICE YOU ARE SENDING TO
//byte remoteDevice[6] = {0x84, 0xF3, 0xEB, 0xB3, 0x66, 0xCC};
//byte remoteDevice[6] = {0x84, 0xF3, 0xEB, 0x73, 0x55, 0x0D};
//byte remoteDevice[6] = {0x00, 0x21, 0x6A, 0xAA, 0xC9, 0x8C};
///byte remoteDevice[6] = {0xf8, 0x1a, 0x67, 0xb7, 0xeb, 0x0b}; //computer
//byte remoteDevice[6] = {0x84, 0xF3, 0xEB, 0x73, 0x55, 0x1E}; //Deuxieme ESP8266
byte remoteDevice[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

const byte dataLength = 250;
byte txData[dataLength];
unsigned long n_sent;
int error;

void init_histo() {
  for(int i=0;i<HISTO_N_STEP;i++) {
    histogram[i] = 0;
  }
  histogram_higher = 0;
  histogram_lower = 0;
  error_nb=0;
  receiveNb=0;
  avg=0;
}

int fill_histo(long value) {
  int index = (value-HISTO_INF) * HISTO_N_STEP / (HISTO_SUP - HISTO_INF);
  if(index >= HISTO_N_STEP) {
    histogram_higher++;
  } else if(index < 0) {
    histogram_lower++;
  } else {
    histogram[index]++;
  }

  receiveNb++;
  avg += value;
}

void print_histo() {
  Serial.printf("Bounds\t%d\tµs\t%d\tµs", HISTO_INF, HISTO_SUP);
  Serial.println();
  Serial.printf("Nb out of bounds :");
  Serial.println();
  Serial.printf("Higher :\t%d\tLower :\t%d", histogram_higher, histogram_lower);
  Serial.println();
  Serial.printf("Histo :");
  Serial.println();
  for(int i=0;i<HISTO_N_STEP;i++) {
    Serial.printf("%d\t", histogram[i]);
  }
  Serial.println();
  Serial.printf("Average :\t%f\t", receiveNb != 0 ? avg/receiveNb : -1);
  Serial.println();
  Serial.printf("Received :\t%d", receiveNb);
  Serial.println();
  Serial.printf("Errors :\t%d", error_nb);
  Serial.println();
}

void send_test() {
  
  if(n_sent < NB_TRIES) {
    long mytime = micros();
    memcpy(txData, &mytime, sizeof(mytime));
    esp_now_send(remoteDevice, txData, dataLength);
    n_sent++;
  } else if (Serial) {
    print_histo();
    Serial.println();
    Serial.println("--------------------------");
    Serial.println();
    
    n_sent=0;

    
    Serial.println();
    Serial.println("------New test :----------");
    Serial.println();
    init_histo();
    batchStart = micros();
  }
}

void setup()
{
  for (int i = 0; i < dataLength; i++)
  {
    txData[i] = 0x12;
  }

  wifi_set_macaddr(STATION_IF,selfmac);


  
  pinMode(2, OUTPUT); //TX
  pinMode(0, OUTPUT); //RX
  Serial.begin(115200);
  while(!Serial) {delay(1);}
  Serial.print("\r\n\r\nDevice MAC: ");
  WiFi.mode(WIFI_STA);
  WiFi.begin();
  Serial.println(WiFi.macAddress());
  Serial.println("\r\nESP_Now Dual Mode Transmitter + Receiver [MASTER].\r\n");
  esp_now_init();
  delay(10);
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  //esp_now_add_peer(remoteDevice, ESP_NOW_ROLE_CONTROLLER, WIFI_CHANNEL, NULL, 0);
  esp_now_add_peer(NULL, ESP_NOW_ROLE_CONTROLLER, WIFI_CHANNEL, NULL, 0);

  error = esp_now_register_recv_cb([](uint8_t *mac, uint8_t *data, uint8_t len)
  {
    long receiveTime = micros();
    long sendTime;
    
    if(len>sizeof(sendTime)) {
      memcpy(&sendTime, data, sizeof(sendTime));

      if(sendTime>batchStart) {
        fill_histo(receiveTime - sendTime);
      }
    } else {
      error_nb++;
    }
    sendNew = true;
    
  });

    esp_now_register_send_cb([](uint8_t* mac, uint8_t sendStatus) {
    sendNew = sendStatus != 0;
  });
  
  Serial.println(error);// if ==0 is OK

  n_sent = 0;
  blinker.attach(0.01, send_test);
}

void loop()
{
  yield();
}


================================================
FILE: ESP8266-Test/serial_logger.py
================================================
import serial
import time
import csv
import sys

assert len(sys.argv)==3


ser = serial.Serial(sys.argv[1], 115200)
ser.flushInput()

print "Serial opened : " + str(sys.argv[1])

while True:
	try:
		ser_bytes = ser.readline()
		#print(ser_bytes)
		with open(sys.argv[2],"a") as f:
			f.write(ser_bytes)
	except:
		print("Keyboard Interrupt")
		break


================================================
FILE: ESP8266_Echo/ESP8266_Echo.ino
================================================
/*
   19/02/2019 Mac adress modified : Dell laptop

  Master/Server:
    Sends a 100Byte ESPNOW data block, and awaits a response
    SLAVE ADDRESS[84:F3:EB:B3:66:CC]
    SELF=84:F3:EB:73:55:0D

    
*/


#include <ESP8266WiFi.h>
extern "C" {
#include <espnow.h>
}

#include <Ticker.h>  //Ticker Library

Ticker blinker;

#define WIFI_CHANNEL 1

//byte selfmac[6] = {0xf8, 0x1a, 0x67, 0xb7, 0xeb, 0x0b};
byte selfmac[6] = {0x84, 0xF3, 0xEB, 0x73, 0x55, 0x1E};

//MAC ADDRESS OF THE DEVICE YOU ARE SENDING TO
//byte remoteDevice[6] = {0x84, 0xF3, 0xEB, 0xB3, 0x66, 0xCC};
//byte remoteDevice[6] = {0x84, 0xF3, 0xEB, 0x73, 0x55, 0x0D};
//byte remoteDevice[6] = {0x00, 0x21, 0x6A, 0xAA, 0xC9, 0x8C};
///byte remoteDevice[6] = {0x84, 0xF3, 0xEB, 0x73, 0x55, 0x0D};
//byte remoteDevice[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //broadcast
byte remoteDevice[6] {0xB4,0xE6,0x2D,0xB5,0x9F,0x85}; //ESP32

const byte dataLength = 250;
byte txData[dataLength];
int error;

void send_echo(byte *rxpacket) {
    memcpy(txData, rxpacket, 8);
    esp_now_send(remoteDevice, txData, dataLength);
}

void setup()
{
  for (int i = 0; i < dataLength; i++)
  {
    txData[i] = 0x13;
  }

  wifi_set_macaddr(STATION_IF,selfmac);

  Serial.begin(115200);
  while(!Serial) {delay(1);}
  Serial.print("\r\n\r\nDevice MAC: ");
  WiFi.mode(WIFI_STA);
  WiFi.begin();
  Serial.println(WiFi.macAddress());
  Serial.println("\r\nESP_Now Dual Mode Transmitter + Receiver [MASTER].\r\n");
  esp_now_init();
  delay(10);
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  //esp_now_add_peer(remoteDevice, ESP_NOW_ROLE_CONTROLLER, WIFI_CHANNEL, NULL, 0);
  esp_now_add_peer(NULL, ESP_NOW_ROLE_CONTROLLER, WIFI_CHANNEL, NULL, 0);


  error = esp_now_register_recv_cb([](uint8_t *mac, uint8_t *data, uint8_t len)
  {
    if(len>8) {
      send_echo(data);
    }
  });
  
  Serial.println(error);// if ==0 is OK
}

void loop()
{
  yield();
}


================================================
FILE: ESPNOW_lib/Makefile
================================================

CC = g++
CFLAGS  = -g -Wall -std=c++11
INCLUDES = -I src/Includes/

default: all

%.o: src/%.cpp
	mkdir -p bin
	$(CC) $(CFLAGS) $(INCLUDES) -o bin/$@ -c $^

app: main.o ESPNOW_manager.o ESPNOW_types.o
	$(CC) $(CFLAGS) -o bin/exec $(addprefix bin/,$^) -pthread


all: clear clean app

clean: 
	$(RM) bin/*

clear:
	clear


================================================
FILE: ESPNOW_lib/README.MD
================================================
# Before using this code
Do not forget to turn on monitor mode and choose the right channel on your wireless interface card.

Here is a exmaple on how to do it : 
```
sudo ifconfig wlp5s0 down
sudo iwconfig wlp5s0 mode monitor
sudo ifconfig wlp5s0 up
sudo iwconfig wlp5s0 channel 1 
```



================================================
FILE: ESPNOW_lib/src/ESPNOW_manager.cpp
================================================

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <stdint.h>
#include <pthread.h>
#include <unistd.h>

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if_arp.h>
#include <arpa/inet.h>
#include <assert.h>

#include "ESPNOW_manager.h"

#include "ESPNOW_types.h"

#define MAC_2_MSBytes(MAC)  MAC == NULL ? 0 : (MAC[0] << 8) | MAC[1]
#define MAC_4_LSBytes(MAC)  MAC == NULL ? 0 : (((((MAC[2] << 8) | MAC[3]) << 8) | MAC[4]) << 8) | MAC[5]

void ESPNOW_manager::set_interface(char* interface) {
	this->interface = (char*) malloc(strlen(interface)*sizeof(char));	
	strcpy(this->interface, interface);
}

void ESPNOW_manager::set_recv_callback(void (*callback)(uint8_t src_mac[6], uint8_t *data, int len)) {
	recv_thread_params.callback = callback;
}

void ESPNOW_manager::unset_filter() {
	if(this->bpf.filter != NULL) {
		free(this->bpf.filter);
		this->bpf.filter = NULL;
	}
	this->bpf.len = 0;
}

void ESPNOW_manager::set_filter(uint8_t *src_mac, uint8_t *dst_mac) {
	//sudo tcpdump -i wlp5s0 'type 0 subtype 0xd0 and wlan[24:4]=0x7f18fe34 and wlan[32]=221 and wlan[33:4]&0xffffff = 0x18fe34 and wlan[37]=0x4 and wlan dst 11:22:33:44:55:66 and wlan src 77:88:99:aa:bb:cc' -dd
	unset_filter();

	this->bpf.len = 53;

	uint32_t MSB_dst = MAC_2_MSBytes(dst_mac);
	uint32_t LSB_dst = MAC_4_LSBytes(dst_mac);

	uint32_t MSB_src = MAC_2_MSBytes(src_mac);
	uint32_t LSB_src = MAC_4_LSBytes(src_mac);

	uint8_t jeq_dst = dst_mac == NULL ? 0x30 : 0x15; //0x30 jump if >=. 0x15 jump if ==.
	uint8_t jeq_src = src_mac == NULL ? 0x30 : 0x15;

	struct sock_filter temp_code[this->bpf.len] = {
			{ 0x30, 0, 0, 0x00000003 },
			{ 0x64, 0, 0, 0x00000008 },
			{ 0x7, 0, 0, 0x00000000 },
			{ 0x30, 0, 0, 0x00000002 },
			{ 0x4c, 0, 0, 0x00000000 },
			{ 0x2, 0, 0, 0x00000000 },
			{ 0x7, 0, 0, 0x00000000 },
			{ 0x50, 0, 0, 0x00000000 },
			{ 0x54, 0, 0, 0x000000fc },
			{ 0x15, 0, 42, 0x000000d0 },
			{ 0x40, 0, 0, 0x00000018 },
			{ 0x15, 0, 40, 0x7f18fe34 },
			{ 0x50, 0, 0, 0x00000020 },
			{ 0x15, 0, 38, 0x000000dd },
			{ 0x40, 0, 0, 0x00000021 },
			{ 0x54, 0, 0, 0x00ffffff },
			{ 0x15, 0, 35, 0x0018fe34 },
			{ 0x50, 0, 0, 0x00000025 },
			{ 0x15, 0, 33, 0x00000004 },
			{ 0x50, 0, 0, 0x00000000 },
			{ 0x45, 31, 0, 0x00000004 },
			{ 0x45, 0, 21, 0x00000008 },
			{ 0x50, 0, 0, 0x00000001 },
			{ 0x45, 0, 4, 0x00000001 },
			{ 0x40, 0, 0, 0x00000012 },
			{ jeq_dst, 0, 26, LSB_dst },
			{ 0x48, 0, 0, 0x00000010 },
			{ jeq_dst, 4, 24, MSB_dst },
			{ 0x40, 0, 0, 0x00000006 },
			{ jeq_dst, 0, 22, LSB_dst },
			{ 0x48, 0, 0, 0x00000004 },
			{ jeq_dst, 0, 20, MSB_dst },
			{ 0x50, 0, 0, 0x00000001 },
			{ 0x45, 0, 13, 0x00000002 },
			{ 0x45, 0, 4, 0x00000001 },
			{ 0x40, 0, 0, 0x0000001a },
			{ jeq_src, 0, 15, LSB_src },
			{ 0x48, 0, 0, 0x00000018 },
			{ jeq_src, 12, 13, MSB_src },
			{ 0x40, 0, 0, 0x00000012 },
			{ jeq_src, 0, 11, LSB_src },
			{ 0x48, 0, 0, 0x00000010 },
			{ jeq_src, 8, 9, MSB_src },
			{ 0x40, 0, 0, 0x00000006 },
			{ jeq_dst, 0, 7, LSB_dst },
			{ 0x48, 0, 0, 0x00000004 },
			{ jeq_dst, 0, 5, MSB_dst },
			{ 0x40, 0, 0, 0x0000000c },
			{ jeq_src, 0, 3, LSB_src },
			{ 0x48, 0, 0, 0x0000000a },
			{ jeq_src, 0, 1, MSB_src },
			{ 0x6, 0, 0, 0x00040000 },
			{ 0x6, 0, 0, 0x00000000 }
						};

	this->bpf.filter = (sock_filter*) malloc(sizeof(sock_filter)*this->bpf.len);
	memcpy(this->bpf.filter, temp_code, sizeof(struct sock_filter) * this->bpf.len);
}


void ESPNOW_manager::start() {
	struct sockaddr_ll s_dest_addr;
    struct ifreq ifr;
	
    int fd, 			//file descriptor
		ioctl_errno,	//ioctl errno
		bind_errno,		//bind errno
		filter_errno,	//attach filter errno
		priority_errno;	//Set priority errno

	bzero(&s_dest_addr, sizeof(s_dest_addr));
    bzero(&ifr, sizeof(ifr));
	
	
    fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    assert(fd != -1);

    strncpy((char *)ifr.ifr_name, this->interface, IFNAMSIZ); //interface

    ioctl_errno = ioctl(fd, SIOCGIFINDEX, &ifr);
    assert(ioctl_errno >= 0);	//abort if error

    s_dest_addr.sll_family = PF_PACKET;
    s_dest_addr.sll_protocol = htons(ETH_P_ALL);
    s_dest_addr.sll_ifindex = ifr.ifr_ifindex;
    
    bind_errno = bind(fd, (struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr));
    assert(bind_errno >= 0);	//abort if error
	
	
	if(bpf.len > 0) {
		filter_errno = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &(this->bpf), sizeof(bpf));
		assert(filter_errno >= 0);
	}


	priority_errno = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &(this->socket_priority), sizeof(this->socket_priority));
	assert(priority_errno ==0);
	
	this->sock_fd = fd;

	this->recv_thread_params.sock_fd = this->sock_fd;

	pthread_create (&recv_thd_id, NULL, &(ESPNOW_manager::sock_recv_thread), &recv_thread_params);
    
}

void ESPNOW_manager::stop() {
	if(recv_thd_id) {
		pthread_cancel(recv_thd_id);
	}
	if (this->sock_fd > 0)
    {
        close(this->sock_fd);
    }
}

void ESPNOW_manager::end() {
	stop();

	if(this->interface != NULL) {
		free(this->interface);
		this->interface = NULL;
	}
	
	if(this->bpf.filter != NULL) {
		free(this->bpf.filter);
		this->bpf.filter = NULL;
	}
}

void* ESPNOW_manager::sock_recv_thread (void *p_arg)
{
	int raw_bytes_len;
	uint8_t raw_bytes[LEN_RAWBYTES_MAX];

	uint8_t* res_mac;
	uint8_t* res_payload;
	int res_len;

	struct thread_args params = * ((struct thread_args *)p_arg);

	if(params.callback == NULL) {
		printf ("No callback for receive, receive thread exited\n");
    	return EXIT_SUCCESS;
	};

	while(1)
    {	
        raw_bytes_len = recvfrom (params.sock_fd, raw_bytes, LEN_RAWBYTES_MAX, MSG_TRUNC, NULL, 0);

        if( -1 == raw_bytes_len )
        {
            perror ("Socket receive failed");
            break;
        }
        else if( raw_bytes_len < 0 )
        {
            perror ("Socket receive, error ");
        }
        else
        {
        	res_mac = ESPNOW_packet::get_src_mac(raw_bytes,raw_bytes_len);
        	res_payload = ESPNOW_packet::get_payload(raw_bytes, raw_bytes_len);
        	res_len = ESPNOW_packet::get_payload_len(raw_bytes, raw_bytes_len);
        	if(res_mac != NULL && res_payload != NULL && res_len > 0) {
        		params.callback(res_mac, res_payload, res_len);
        	}
        }
    }

    printf ("Receive thread exited \n");
    return EXIT_SUCCESS;
}


/*
int ESPNOW_manager::send(ESPNOW_packet p) {
	uint8_t raw_bytes[LEN_RAWBYTES_MAX];
	int len = p.toBytes(raw_bytes, LEN_RAWBYTES_MAX);

	return sendto(this->sock_fd, raw_bytes, len, 0, NULL, 0);
}
*/


int ESPNOW_manager::send(uint8_t *payload, int len) {
	uint8_t raw_bytes[LEN_RAWBYTES_MAX];

	//Not the most fastest way to do this : 
	//	copy the payload in the packet array and then copy it back into the buffer...
	this->mypacket.wlan.actionframe.content.set_length(len); 
	memcpy(this->mypacket.wlan.actionframe.content.payload, payload, len);

	int raw_len = mypacket.toBytes(raw_bytes, LEN_RAWBYTES_MAX);

	return sendto(this->sock_fd, raw_bytes, raw_len, 0, NULL, 0);
}

int ESPNOW_manager::send() {
	uint8_t raw_bytes[LEN_RAWBYTES_MAX];

	int raw_len = mypacket.toBytes(raw_bytes, LEN_RAWBYTES_MAX);

	return sendto(this->sock_fd, raw_bytes, raw_len, 0, NULL, 0);
}



================================================
FILE: ESPNOW_lib/src/ESPNOW_types.cpp
================================================
#include "ESPNOW_types.h"

#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <assert.h>

void ESPNOW_packet::set_channel(uint16_t channel_freq) {
this->radiotap.channel_freq = channel_freq;
}

void ESPNOW_packet::set_datarate(uint8_t datarate) {
	this->radiotap.datarate = datarate;
}

void ESPNOW_packet::set_src_mac(uint8_t my_mac[6]) {
	memcpy(this->wlan.sa, my_mac, sizeof(uint8_t)*6);
}

void ESPNOW_packet::set_dst_mac(uint8_t dst_mac[6]) {
	memcpy(this->wlan.da, dst_mac, sizeof(uint8_t)*6);
	memcpy(this->wlan.bssid, dst_mac, sizeof(uint8_t)*6);
}

int ESPNOW_packet::toBytes(uint8_t *bytes, int max_len) {	
	int correct_len = sizeof(ESPNOW_packet) + this->wlan.actionframe.content.length - 0xff;
	
	assert(correct_len <= max_len); 

	memcpy(bytes, this, correct_len);	
	
	memcpy(bytes + correct_len - sizeof(this->wlan.fcs), &(this->wlan.fcs), sizeof(this->wlan.fcs));

	return correct_len;
}

int ESPNOW_packet::get_radiotap_len(uint8_t *raw_bytes, int len) {
	if(len < 4) return -1;
	return (int)raw_bytes[2] + ((int)raw_bytes[3] << 8);
}

uint8_t* ESPNOW_packet::get_src_mac(uint8_t *raw_bytes, int len) {
	int radiotap_len = get_radiotap_len(raw_bytes, len);

	if(len < radiotap_len + 10 + 6) return NULL;

	return raw_bytes + radiotap_len + 10;
}

int ESPNOW_packet::get_payload_len(uint8_t *raw_bytes, int len) {
	int radiotap_len = get_radiotap_len(raw_bytes, len);
	
	if(len < radiotap_len + WLAN_LEN + ACTIONFRAME_HEADER_LEN + 1) return -1;

	return raw_bytes[radiotap_len + WLAN_LEN + ACTIONFRAME_HEADER_LEN + 1] - 5;
}

uint8_t* ESPNOW_packet::get_payload(uint8_t *raw_bytes, int len) {
	int radiotap_len = get_radiotap_len(raw_bytes, len);

	if(len < radiotap_len + WLAN_LEN + ACTIONFRAME_HEADER_LEN + VENDORSPECIFIC_CONTENT_LEN) return NULL;
	
	return raw_bytes + radiotap_len + WLAN_LEN + ACTIONFRAME_HEADER_LEN + VENDORSPECIFIC_CONTENT_LEN;
}


================================================
FILE: ESPNOW_lib/src/Includes/ESPNOW_manager.h
================================================
#ifndef ESPNOW_manager_H
#define ESPNOW_manager_H

#include <stdint.h>
#include <linux/filter.h>
#include <string.h>
#include <sys/types.h>
#include <stdint.h>
#include <pthread.h>

#include "ESPNOW_types.h"


#define LEN_RAWBYTES_MAX 512

struct thread_args {
	int sock_fd;
	void (*callback)(uint8_t src_mac[6], uint8_t *data, int len);
};

class ESPNOW_manager {
	public:
		ESPNOW_manager() {
			default_values();
		}

		ESPNOW_manager(char* interface) {
			default_values();
			set_interface(interface);
		}

		ESPNOW_manager(char* interface, uint8_t datarate, uint16_t channel_freq, uint8_t src_mac[6], uint8_t dst_mac[6], bool filterOn) {
			default_values();
			set_interface(interface);
			set_channel(channel_freq);
			set_datarate(datarate);
			set_src_mac(src_mac);
			set_dst_mac(dst_mac);
			
			if(filterOn) {
				set_filter(dst_mac, src_mac);
			} else {
				set_filter(NULL, NULL);
			}
			
		}

		void unset_filter();
		void set_filter(uint8_t *src_mac, uint8_t *dst_mac);
		void set_interface(char* interface);
		void set_recv_callback(void (*callback)(uint8_t src_mac[6], uint8_t *data, int len));
		
		void start();
		void stop();
		void end();
		
		//int send(ESPNOW_packet p);
		int send(uint8_t *payload, int len);
		int send();
		
		void set_channel(uint16_t channel_freq) { mypacket.set_channel(channel_freq); }
		void set_datarate(uint8_t datarate) { mypacket.set_datarate(datarate); }
		void set_src_mac(uint8_t src_mac[6]) { mypacket.set_src_mac(src_mac); }
		void set_dst_mac(uint8_t dst_mac[6]) { mypacket.set_dst_mac(dst_mac); }
	

		ESPNOW_packet mypacket;
	private:
		int sock_fd;
		struct sock_fprog bpf;
		int socket_priority;
		char* interface;

		

		pthread_t recv_thd_id;
		struct thread_args recv_thread_params;
		static void* sock_recv_thread (void *p_arg);

		void default_values() {
			bpf.len = 0;
			socket_priority = 7; //Priority
			recv_thread_params.callback = NULL;
		}

};



#endif


================================================
FILE: ESPNOW_lib/src/Includes/ESPNOW_types.h
================================================
#ifndef ESPNOW_TYPES_H
#define ESPNOW_TYPES_H

#include <string.h>
#include <stdint.h>

#define DATARATE_1Mbps 0x02
#define DATARATE_2Mbps 0x04
#define DATARATE_6Mbps 0x0c
#define DATARATE_9Mbps 0x12
#define DATARATE_12Mbps 0x18
#define DATARATE_18Mbps 0x24
#define DATARATE_24Mbps 0x30
#define DATARATE_36Mbps 0x48
#define DATARATE_48Mbps 0x60
#define DATARATE_54Mbps 0x6c

#define CHANNEL_freq_1 2412
#define CHANNEL_freq_2 2417
#define CHANNEL_freq_3 2422
#define CHANNEL_freq_4 2427
#define CHANNEL_freq_5 2432
#define CHANNEL_freq_6 2437
#define CHANNEL_freq_7 2442
#define CHANNEL_freq_8 2447
#define CHANNEL_freq_9 2452
#define CHANNEL_freq_10 2457
#define CHANNEL_freq_11 2462
#define CHANNEL_freq_12 2467
#define CHANNEL_freq_13 2472

#define WLAN_LEN 24
#define ACTIONFRAME_HEADER_LEN 8
#define VENDORSPECIFIC_CONTENT_LEN 7

struct IEEE80211_radiotap {
	uint8_t version;
    uint8_t pad;
    uint16_t length;
    uint32_t present;
    uint8_t flags;
    uint8_t datarate;
    uint16_t channel_freq;
    uint16_t channel_flags_quarter;

	//Default values for ESPNOW
	IEEE80211_radiotap() {
		this->version = 0;
		this->pad = 0;
		this->length = sizeof(IEEE80211_radiotap);
		this->present = 0x0000000e;
		this->flags = 0x10;
		this->datarate = DATARATE_6Mbps;
		this->channel_freq = CHANNEL_freq_1;
		this->channel_flags_quarter = 0x00c0;
	}
} __attribute__((__packed__));


struct IEEE80211_vendorspecific {
	uint8_t elementID;
	uint8_t length;
	uint8_t	OUI[3];
	uint8_t type;
	uint8_t version;
	uint8_t payload[250];

	//Default values for ESPNOW
	IEEE80211_vendorspecific() {
		this->elementID = 0xdd;
		this->OUI[0] = 0x18;
		this->OUI[1] = 0xfe;
		this->OUI[2] = 0x34;
		this->type = 0x04;
		this->version = 0x01;
	}

	void set_length(int length) {this->length = length + 5;}
} __attribute__((__packed__));


struct IEEE80211_actionframe {
	uint8_t category_code;
    uint8_t OUI[3];
	uint8_t unknown_bytes[4];
	struct IEEE80211_vendorspecific content;

	//Default values for ESPNOW
	IEEE80211_actionframe() {
		this->category_code = 0x7f;
		this->OUI[0] = 0x18;
		this->OUI[1] = 0xfe;
		this->OUI[2] = 0x34;
		bzero(this->unknown_bytes, 4);
	}
} __attribute__((__packed__));


struct IEEE80211_wlan {
	uint8_t type;
    uint8_t flags;
    uint16_t duration;
    uint8_t da[6];
    uint8_t sa[6];
    uint8_t bssid[6];
    uint16_t seq;
	struct IEEE80211_actionframe actionframe;
    uint32_t fcs;

	//Default values for ESPNOW
	IEEE80211_wlan() {
		this->type = 0xd0;
		this->flags = 0x00;
		this->duration = 0x0000; //Will be recalculated by the hardware...
		this->seq = 0x0280;
		this->fcs = 0x00000000;	//Will be recalculated by the hardware...
	}
} __attribute__((__packed__));


typedef struct {
	struct IEEE80211_radiotap radiotap;
	struct IEEE80211_wlan wlan;

	void set_channel(uint16_t channel_freq);
	void set_datarate(uint8_t datarate);
	void set_src_mac(uint8_t my_mac[6]);
	void set_dst_mac(uint8_t dst_mac[6]);
	
	int toBytes(uint8_t *bytes, int max_len);

	static int get_radiotap_len(uint8_t *raw_bytes, int len);
	static uint8_t* get_src_mac(uint8_t *raw_bytes, int len);
	static int get_payload_len(uint8_t *raw_bytes, int len);
	static uint8_t* get_payload(uint8_t *raw_bytes, int len);

} __attribute__((__packed__)) ESPNOW_packet;

#endif


================================================
FILE: ESPNOW_lib/src/main.cpp
================================================
/*
Etienne Arlaud
*/

#include <stdint.h>
#include <stdio.h>

#include <assert.h>
#include <unistd.h>
#include <sys/time.h>

#include <thread>

#include "ESPNOW_manager.h"
#include "ESPNOW_types.h"

using namespace std;

static uint8_t my_mac[6] = {0xF8, 0x1A, 0x67, 0xb7, 0xEB, 0x0B};
static uint8_t dest_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static uint8_t ESP_mac[6] = {0xB4,0xE6,0x2D,0xB5,0x9F,0x85};

ESPNOW_manager *handler;

uint8_t payload[127];

void callback(uint8_t src_mac[6], uint8_t *data, int len) {
	handler->mypacket.wlan.actionframe.content.length = 127 + 5;
	memcpy(handler->mypacket.wlan.actionframe.content.payload, data, 6);
	//handler->set_dst_mac(dest_mac);
	handler->send();
}

int main(int argc, char **argv) {
	assert(argc > 1);

	nice(-20);

	handler = new ESPNOW_manager(argv[1], DATARATE_24Mbps, CHANNEL_freq_9, my_mac, dest_mac, false);

	handler->set_filter(ESP_mac, dest_mac);

	handler->set_recv_callback(&callback);

	handler->start();

	while(1) {
		std::this_thread::yield();
	}

	handler->end();
}


================================================
FILE: LICENSE
================================================
BSD 2-Clause License

Copyright (c) 2019, thomasfla
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: Lab/EspNowPacket/EspNowPacket.c
================================================
/*
Florenc Caminade
Thomas FLayols

Send ESP-NOW vendor specific action frame example
https://hackaday.io/project/161896
https://github.com/thomasfla/Linux-ESPNOW

Adapted from : 
https://stackoverflow.com/questions/10824827/raw-sockets-communication-over-wifi-receiver-not-able-to-receive-packets

1/Find your wifi interface:
$ iwconfig

2/Setup your interface in monitor mode :
$ sudo ifconfig wlp5s0 down
$ sudo iwconfig wlp5s0 mode monitor
$ sudo ifconfig wlp5s0 up

3/Run this code as root
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if_arp.h>
#include <arpa/inet.h>
#include <assert.h>

int packetSetUp(uint8_t* packet, uint8_t* mac_dest, uint8_t* mac_src, uint8_t* payload, int len );

static uint8_t mac_src[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static uint8_t mac_dest[6] = {0x84, 0xF3, 0xEB, 0x73, 0x55, 0x0D};
static uint8_t gu8a_dest_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

static uint8_t payload[20] = {0};
static int len = 20;
uint8_t esppacket[400] = {0};


int create_raw_socket(char *dev)
{
    struct sockaddr_ll s_dest_addr; //code from sender
    struct ifreq ifr;
    int fd, ifi, rb;

    bzero(&s_dest_addr, sizeof(s_dest_addr));
    bzero(&ifr, sizeof(ifr));

    (void)memset(&s_dest_addr, 0, sizeof(s_dest_addr));

    fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    assert(fd != -1); //abort if error

    strncpy((char *)ifr.ifr_name, dev, IFNAMSIZ);
    ifi = ioctl(fd, SIOCGIFINDEX, &ifr);
    assert(ifi != -1); //abort if error

    s_dest_addr.sll_family = PF_PACKET;
    //we don't use a protocol above ethernet layer, just use anything here
    s_dest_addr.sll_protocol = htons(ETH_P_ALL);
    s_dest_addr.sll_ifindex = ifr.ifr_ifindex;
    s_dest_addr.sll_hatype = ARPHRD_ETHER;
    s_dest_addr.sll_pkttype = PACKET_OTHERHOST; //PACKET_OUTGOING
    s_dest_addr.sll_halen = ETH_ALEN;
    //MAC - begin
    s_dest_addr.sll_addr[0] = gu8a_dest_mac[0];
    s_dest_addr.sll_addr[1] = gu8a_dest_mac[1];
    s_dest_addr.sll_addr[2] = gu8a_dest_mac[2];
    s_dest_addr.sll_addr[3] = gu8a_dest_mac[3];
    s_dest_addr.sll_addr[4] = gu8a_dest_mac[4];
    s_dest_addr.sll_addr[5] = gu8a_dest_mac[5];
    //MAC - end
    s_dest_addr.sll_addr[6] = 0x00; //not used
    s_dest_addr.sll_addr[7] = 0x00; //not used

    rb = bind(fd, (struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr));
    assert(rb != -1); //abort if error

    return fd;
}

int main(int argc, char **argv)
{
    char *dev = argv[1];

    int sock_fd = -1;
    int32_t s32_res = -1;

    sock_fd = create_raw_socket(dev); /* Creating the raw socket */

    if (-1 == sock_fd)
    {
        perror("Could not create the socket");
        goto LABEL_CLEAN_EXIT;
    }

    printf("Socket created\n");

    fflush(stdout);

    sleep(1);

    printf("******Sending data using raw socket over  %s \n", dev);

    while (1)
    {
        int length = packetSetUp(esppacket,mac_dest,mac_src,payload,len);

        s32_res = sendto(sock_fd,esppacket,length,0,NULL,0);

        if (-1 == s32_res)
        {
            perror("Socket send failed");
            goto LABEL_CLEAN_EXIT;
        }
        int i = 0;
        for (i = 0; i < length; i++)
            printf("%x ", esppacket[i]);

        printf("\n\n");

        usleep(100);
    }

LABEL_CLEAN_EXIT:
    if (sock_fd > 0)
    {
        close(sock_fd);
    }

    printf("***** Raw Socket test- end\n");

    return EXIT_SUCCESS;
}



struct ieee80211_radiotap_header
{
    uint8_t radiotap_version;                //= 0;
    uint8_t radiotap_pad;                    //= 0;
    uint16_t radiotap_lenght;                //= 0x00,0x26;
    uint32_t radiotap_present_1;             //= {0x2f, 0x40, 0x00, 0xa0};
    uint32_t radiotap_present_2;             //= {0x20, 0x08, 0x00, 0xa0};
    uint32_t radiotap_present_3;             //= {0x20, 0x08, 0x00, 0x00};
    uint8_t radiotap_flags;          //= 10;
    uint8_t radiotap_datarate;               //0x0c
    uint16_t radiotap_channel_freq;          //0x6c, 0x09
    uint16_t radiotap_channel_flags_quarter; //0xc0, 0x00

} __attribute__((__packed__));

struct ieee80211_wlan
{
    uint8_t wlan_fc_subtype;          //0xd0
    uint8_t wlan_fc_order;            //0x00
    uint16_t wlan_duration;           //0x3a, 0x01
    uint8_t wlan_da[6];               //0x84, 0xf3, 0xeb, 0x73, 0x55, 0x0d
    uint8_t wlan_sa[6];               //0xf8, 0x1a, 0x67, 0xb7, 0xeb, 0x0b
    uint8_t wlan_bssid[6];            //0x84, 0xf3, 0xeb, 0x73, 0x55, 0x0d
    uint16_t wlan_seq;                //0x70, 0x51
    uint8_t wlan_fiwed_category_code; //0x7f
    uint8_t wlan_tag_oui[3];          //0x18,0xfe, 0x34

    uint8_t espheader[11];

    uint8_t payload[261];

    uint32_t wlan_fcs; //0x1c, 0xd5, 0x35, 0xd3

} __attribute__((__packed__));

typedef struct
{
    struct ieee80211_radiotap_header rtap_header;
    struct ieee80211_wlan mypayload;

} espPacket;


int packetSetUp(uint8_t* packet, uint8_t* mac_dest, uint8_t* mac_src, uint8_t* payload, int len )
{
    /// packet should be at least x long todo calculate x check///
    espPacket mypacket; ///to do chage pypacket to packet_header

    mypacket.rtap_header.radiotap_version = 0;
    mypacket.rtap_header.radiotap_pad = 0;
    mypacket.rtap_header.radiotap_lenght = sizeof(mypacket.rtap_header);
    mypacket.rtap_header.radiotap_present_1 = 0xfe;

    mypacket.rtap_header.radiotap_flags = 0x10;
    mypacket.rtap_header.radiotap_datarate = 0x0c;
    mypacket.rtap_header.radiotap_channel_freq = 0x096c;
    mypacket.rtap_header.radiotap_channel_flags_quarter = 0x00c0;

    mypacket.mypayload.wlan_fc_subtype = 0xd0;
    mypacket.mypayload.wlan_fc_order = 0x00;
    mypacket.mypayload.wlan_duration = 0x013a;

    memcpy(mypacket.mypayload.wlan_da,mac_dest,6);

    memcpy(mypacket.mypayload.wlan_sa,mac_src,6);

    memcpy(mypacket.mypayload.wlan_bssid,mac_dest,6);

    mypacket.mypayload.wlan_seq = 0x5170;
    mypacket.mypayload.wlan_fiwed_category_code = 0x7f;
    mypacket.mypayload.wlan_tag_oui[0] = 0x18;
    mypacket.mypayload.wlan_tag_oui[1] = 0xfe;
    mypacket.mypayload.wlan_tag_oui[2] = 0x34;

    mypacket.mypayload.espheader[0] = 0xa2;//element ID
    mypacket.mypayload.espheader[1] = 0x03;//length of Organization Identifier
    mypacket.mypayload.espheader[2] = 0x92;
    mypacket.mypayload.espheader[3] = 0xb0;
    mypacket.mypayload.espheader[4] = 0xdd;
    mypacket.mypayload.espheader[5] = 0xff;
    mypacket.mypayload.espheader[6] = 0x18;//Organization ID
    mypacket.mypayload.espheader[7] = 0xfe;//Organization ID
    mypacket.mypayload.espheader[8] = 0x34;//Organization ID
    mypacket.mypayload.espheader[9] = 0x04;//type (should be 4)
    mypacket.mypayload.espheader[10] = 0x1;//version field

    memcpy(packet,&mypacket,sizeof(mypacket));
    memcpy(packet + sizeof(mypacket),payload,len);

    mypacket.mypayload.wlan_fcs = 0x00000000;

    printf("%lu\n", sizeof(mypacket.rtap_header));

    return sizeof(mypacket)+len;
}

================================================
FILE: Lab/EspNowPacket/Makefile
================================================
test:
	mkdir -p bin
	gcc EspNowPacket.c -Wall  -o bin/main

clean:
	rm -r bin


================================================
FILE: README.md
================================================
# Linux-ESPNOW
An attempt at implementing a direct link between a linux station and an ESP module using ESPNOW protocol for real time robot control

Project description here: https://hackaday.io/project/161896


================================================
FILE: wifiRawEcho/Includes/ESPNOW_packet.h
================================================
#ifndef ESPNOW_PACKET_H
#define ESPNOW_PACKET_H

#include <stdint.h>
#include <stdio.h>

struct IEEE80211_radiotap {
	uint8_t version;                //= 0;
    uint8_t pad;                    //= 0;
    uint16_t length;                //= 0x00,0x26;
    uint32_t present_1;             //= {0x2f, 0x40, 0x00, 0xa0};
    uint8_t flags;          		//= 10;
    uint8_t datarate;               //0x0c
    uint16_t channel_freq;          //0x6c, 0x09
    uint16_t channel_flags_quarter; //0xc0, 0x00
} __attribute__((__packed__));

struct IEEE80211_vendorspecific {
	uint8_t elementID;		//0xdd
	uint8_t length;			//0xff
	uint8_t	OUI[3];			//0x18,0xfe, 0x34
	uint8_t type;			//0x04
	uint8_t version;		//0x01
	uint8_t payload[127];
	
} __attribute__((__packed__));

struct IEEE80211_actionframe {
	uint8_t category_code;	//0x7f
    uint8_t OUI[3];			//0x18,0xfe, 0x34
	uint8_t unknown_bytes[4];
	struct IEEE80211_vendorspecific content;
} __attribute__((__packed__));

struct IEEE80211_wlan {
	uint8_t type;					//0xd0
    uint8_t flags;            		//0x00
    uint16_t duration;         //0x3a, 0x01
    uint8_t da[6];             //0x84, 0xf3, 0xeb, 0x73, 0x55, 0x0d
    uint8_t sa[6];             //0xf8, 0x1a, 0x67, 0xb7, 0xeb, 0x0b
    uint8_t bssid[6];          //0x84, 0xf3, 0xeb, 0x73, 0x55, 0x0d
    uint16_t seq;              //0x70, 0x51
	struct IEEE80211_actionframe actionframe;
    uint32_t fcs;				//Random values : will be recalculated by the hrdw.
} __attribute__((__packed__));

typedef struct {

	struct IEEE80211_radiotap radiotap;
	struct IEEE80211_wlan wlan;

} __attribute__((__packed__)) ESPNOW_packet;


void init_ESPNOW_packet(ESPNOW_packet *packet);

int packet_to_bytes(uint8_t *bytes, int max_length, ESPNOW_packet packet);

void print_raw_packet(uint8_t *data, int len);

#endif


================================================
FILE: wifiRawEcho/Makefile
================================================

CC = gcc
CFLAGS  = -g -Wall --std=c99
INCLUDES = -I Includes/

default: all

%.o: src/%.c
	$(CC) $(CFLAGS) $(INCLUDES) -o bin/$@ -c $^

app: main.o ESPNOW_packet.o
	$(CC) $(CFLAGS) -o bin/exec $(addprefix bin/,$^)


all: clear clean app

clean: 
	$(RM) bin/*

clear:
	clear


================================================
FILE: wifiRawEcho/src/ESPNOW_packet.c
================================================
#include "ESPNOW_packet.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/time.h>


void init_ESPNOW_packet(ESPNOW_packet *packet) {
	//radiotap header	
	packet->radiotap.version = 0x00;
	packet->radiotap.pad = 0x00;
	packet->radiotap.present_1 = 0x0000000e;
	packet->radiotap.flags = 0x10;
	packet->radiotap.datarate = 0x6c;
	packet->radiotap.channel_freq = 0x096c;
	packet->radiotap.channel_flags_quarter = 0x00c0;

	packet->radiotap.length = sizeof(packet->radiotap);
	
	
	//Wlan
	packet->wlan.type = 0xd0;
	packet->wlan.flags = 0x00;
	packet->wlan.duration = 0x3a01;
	packet->wlan.seq = 0x0280;//0x7051;
	

	//action frame
	packet->wlan.actionframe.category_code = 0x7f;
	packet->wlan.actionframe.OUI[0] = 0x18;
	packet->wlan.actionframe.OUI[1] = 0xfe;
	packet->wlan.actionframe.OUI[2] = 0x34;
	
	//vendor specific
	packet->wlan.actionframe.content.elementID = 0xdd;
	packet->wlan.actionframe.content.length = 0x80;//0xff;
	packet->wlan.actionframe.content.OUI[0] = 0x18;
	packet->wlan.actionframe.content.OUI[1] = 0xfe;
	packet->wlan.actionframe.content.OUI[2] = 0x34;
	packet->wlan.actionframe.content.type = 0x04;
	packet->wlan.actionframe.content.version = 0x01;

	//payload
	for(int i=0;i<127;i++) {
			packet->wlan.actionframe.content.payload[i] = 0x13;
	}
}


int packet_to_bytes(uint8_t *bytes, int max_length, ESPNOW_packet packet) {
	int len = sizeof(packet);	
	assert(max_length > len);	
	
	memcpy(bytes, &packet, len);
	
	return len;
}


void print_raw_packet(uint8_t *data, int len)
{
    printf("----------------------new packet (len : %d)---------------------------\n", len);
    int i;
    for (i = 0; i < len; i++)
    {
        if (i % 16 == 0)
            printf("\n");
		else if(i % 8 == 0)
			printf(" ");
        printf("0x%02x, ", data[i]);
    }
    printf("\n\n");
}


================================================
FILE: wifiRawEcho/src/main.c
================================================
/*
Etienne Arlaud
*/

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if_arp.h>
#include <arpa/inet.h>
#include <assert.h>
#include <linux/filter.h>
#include <sys/time.h>

#define PRIORITY_LVL -20
#define SOCKET_PRIORITY 7

#include "ESPNOW_packet.h"


#define MY_MAC 0xffffffffffff//0xf81a67b7eb0b
static uint8_t broadcast_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
static uint8_t src_mac[6] = {0xF8, 0x1A, 0x67, 0xb7, 0xEB, 0x0B};
//static uint8_t dest_mac[6] = {0x84, 0xf3, 0xeb, 0x73, 0x55, 0x0d}; //ESP8266
static uint8_t dest_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};//{0xB4, 0xE6, 0x2D, 0xB5, 0x9F, 0x85};// ESP32

#define MAX_PACKET_LEN 1000

#define FILTER_LENGTH 53//34
#define MAC_2_MSBytes(MAC)  ((uint64_t) MAC & (uint64_t) 0xffff00000000)>>(8*4)
#define MAC_4_LSBytes(MAC)  (uint64_t) MAC & (((uint64_t) 1<<(4*8))-1)
//generated with tcpdump -i wlp5s0 'type 0 subtype 0xd0 and wlan[24:4]=0x7f18fe34 and wlan[32]=221 and wlan[33:4]&0xffffff = 0x18fe34 and wlan[37]=0x4 and wlan dst f8:1a:67:b7:eb:0b' -dd
static struct sock_filter bpfcode[FILTER_LENGTH] = {
{ 0x30, 0, 0, 0x00000003 },
{ 0x64, 0, 0, 0x00000008 },
{ 0x7, 0, 0, 0x00000000 },
{ 0x30, 0, 0, 0x00000002 },
{ 0x4c, 0, 0, 0x00000000 },
{ 0x2, 0, 0, 0x00000000 },
{ 0x7, 0, 0, 0x00000000 },
{ 0x50, 0, 0, 0x00000000 },
{ 0x54, 0, 0, 0x000000fc },
{ 0x15, 0, 42, 0x000000d0 },
{ 0x40, 0, 0, 0x00000018 },
{ 0x15, 0, 40, 0x7f18fe34 },
{ 0x50, 0, 0, 0x00000020 },
{ 0x15, 0, 38, 0x000000dd },
{ 0x40, 0, 0, 0x00000021 },
{ 0x54, 0, 0, 0x00ffffff },
{ 0x15, 0, 35, 0x0018fe34 },
{ 0x50, 0, 0, 0x00000025 },
{ 0x15, 0, 33, 0x00000004 },
{ 0x50, 0, 0, 0x00000000 },
{ 0x45, 31, 0, 0x00000004 },
{ 0x45, 0, 21, 0x00000008 },
{ 0x50, 0, 0, 0x00000001 },
{ 0x45, 0, 4, 0x00000001 },
{ 0x40, 0, 0, 0x00000012 },
{ 0x15, 0, 26, 0xffffffff },
{ 0x48, 0, 0, 0x00000010 },
{ 0x15, 4, 24, 0x0000ffff },
{ 0x40, 0, 0, 0x00000006 },
{ 0x15, 0, 22, 0xffffffff },
{ 0x48, 0, 0, 0x00000004 },
{ 0x15, 0, 20, 0x0000ffff },
{ 0x50, 0, 0, 0x00000001 },
{ 0x45, 0, 13, 0x00000002 },
{ 0x45, 0, 4, 0x00000001 },
{ 0x40, 0, 0, 0x0000001a },
{ 0x15, 0, 15, 0x2db59f85 },
{ 0x48, 0, 0, 0x00000018 },
{ 0x15, 12, 13, 0x0000b4e6 },
{ 0x40, 0, 0, 0x00000012 },
{ 0x15, 0, 11, 0x2db59f85 },
{ 0x48, 0, 0, 0x00000010 },
{ 0x15, 8, 9, 0x0000b4e6 },
{ 0x40, 0, 0, 0x00000006 },
{ 0x15, 0, 7, 0xffffffff },
{ 0x48, 0, 0, 0x00000004 },
{ 0x15, 0, 5, 0x0000ffff },
{ 0x40, 0, 0, 0x0000000c },
{ 0x15, 0, 3, 0x2db59f85 },
{ 0x48, 0, 0, 0x0000000a },
{ 0x15, 0, 1, 0x0000b4e6 },
{ 0x6, 0, 0, 0x00040000 },
{ 0x6, 0, 0, 0x00000000 },


/*
  { 0x30, 0, 0, 0x00000003 },
  { 0x64, 0, 0, 0x00000008 },
  { 0x7, 0, 0, 0x00000000 },
  { 0x30, 0, 0, 0x00000002 },
  { 0x4c, 0, 0, 0x00000000 },
  { 0x2, 0, 0, 0x00000000 },
  { 0x7, 0, 0, 0x00000000 },
  { 0x50, 0, 0, 0x00000000 },
  { 0x54, 0, 0, 0x000000fc },
  { 0x15, 0, 23, 0x000000d0 },
  { 0x40, 0, 0, 0x00000018 },
  { 0x15, 0, 21, 0x7f18fe34 },
  { 0x50, 0, 0, 0x00000020 },
  { 0x15, 0, 19, 0x000000dd },
  { 0x40, 0, 0, 0x00000021 },
  { 0x54, 0, 0, 0x00ffffff },
  { 0x15, 0, 16, 0x0018fe34 },
  { 0x50, 0, 0, 0x00000025 },
  { 0x15, 0, 14, 0x00000004 },
  { 0x50, 0, 0, 0x00000000 },
  { 0x45, 12, 0, 0x00000004 },
  { 0x45, 0, 6, 0x00000008 },
  { 0x50, 0, 0, 0x00000001 },
  { 0x45, 0, 4, 0x00000001 },
  { 0x40, 0, 0, 0x00000012 },
  { 0x15, 0, 7, 0x67b7eb0b },
  { 0x48, 0, 0, 0x00000010 },
  { 0x15, 4, 5, 0x0000f81a },
  { 0x40, 0, 0, 0x00000006 },
  { 0x15, 0, 3, MAC_4_LSBytes(MY_MAC) },
  { 0x48, 0, 0, 0x00000004 },
  { 0x15, 0, 1, MAC_2_MSBytes(MY_MAC) },
  { 0x6, 0, 0, 0x00040000 },
  { 0x6, 0, 0, 0x00000000 },
*/
};

ESPNOW_packet echo_packet;
uint8_t raw_bytes[400];

int create_raw_socket(char *dev, struct sock_fprog *bpf)
{
    struct sockaddr_ll s_dest_addr;
    struct ifreq ifr;
	int priority;
	
    int fd, 			//file descriptor
		ioctl_errno,	//ioctl errno
		bind_errno,		//bind errno
		filter_errno,	//attach filter errno
		priority_errno;	//Set priority errno
	
	bzero(&s_dest_addr, sizeof(s_dest_addr));
    bzero(&ifr, sizeof(ifr));
	
	
    fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    assert(fd != -1); 			//abort if error

    strncpy((char *)ifr.ifr_name, dev, IFNAMSIZ); //interface

    ioctl_errno = ioctl(fd, SIOCGIFINDEX, &ifr);
    assert(ioctl_errno >= 0);	//abort if error

    s_dest_addr.sll_family = PF_PACKET;
    //we don't use a protocol above ethernet layer, just use anything here
    s_dest_addr.sll_protocol = htons(ETH_P_ALL);
    s_dest_addr.sll_ifindex = ifr.ifr_ifindex;
    s_dest_addr.sll_hatype = ARPHRD_ETHER;
    s_dest_addr.sll_pkttype = PACKET_OTHERHOST; //PACKET_OUTGOING
    s_dest_addr.sll_halen = ETH_ALEN;
	memcpy(&(s_dest_addr.sll_addr),dest_mac, sizeof(*src_mac)*6); //MAC

    bind_errno = bind(fd, (struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr));
    assert(bind_errno >= 0);	//abort if error
	
	filter_errno = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, sizeof(*bpf));
    assert(filter_errno >= 0);
	
	priority = SOCKET_PRIORITY;
	priority_errno = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority));
	assert(priority_errno ==0);

    return fd;
}


int main(int argc, char **argv)
{
	assert(argc == 2);
	
	nice(PRIORITY_LVL);
	
    char *dev = argv[1];

	int packets_received = 0;	
	
	uint8_t buff[MAX_PACKET_LEN] = {0};
    int sock_fd = -1;
    int s32_res = -1;
	
	struct sock_fprog bpf = {FILTER_LENGTH, bpfcode};

    sock_fd = create_raw_socket(dev, &bpf); /* Creating the raw socket */

    if (sock_fd < 0)
    {
        perror("Could not create the socket");
        goto LABEL_CLEAN_EXIT;
    } else {
		printf("Socket created\n");
	}

    fflush(stdout);

    sleep(1);
	
	//init answer packet
	init_ESPNOW_packet(&echo_packet);
	memcpy(echo_packet.wlan.da, dest_mac, sizeof(uint8_t)*6);
	memcpy(echo_packet.wlan.sa, src_mac, sizeof(uint8_t)*6);
	memcpy(echo_packet.wlan.bssid, dest_mac, sizeof(uint8_t)*6);
	

    while (1)
    {
		int len = recvfrom(sock_fd, buff, MAX_PACKET_LEN, MSG_TRUNC, NULL, 0);
			
		if (len < 0)
        {
            perror("Socket receive failed or error");
            goto LABEL_CLEAN_EXIT;
        }            
		else if(len > 77)
        {
            //printf("Receive packet number : %d\n", ++packets_received);
            //print_raw_packet(buff, len);
			
			//generate echo
			memcpy(echo_packet.wlan.actionframe.content.payload, buff+77, 16);
			int mypacket_len = packet_to_bytes(raw_bytes, 400, echo_packet);
            s32_res = sendto(sock_fd, raw_bytes, mypacket_len,0,NULL,0);

            if (-1 == s32_res)
            {
                perror("Socket send failed");
                goto LABEL_CLEAN_EXIT;
            } else {
              //printf("Echo sent\n\n\n");
            }
        }
    }

LABEL_CLEAN_EXIT:
    if (sock_fd > 0)
    {
        close(sock_fd);
    }

    printf("***** Raw Socket test- end\n");

    return EXIT_SUCCESS;
    
	
}


================================================
FILE: wifiRawReceiver/Makefile
================================================
test:
	mkdir -p bin
	gcc main.c -Wall -o bin/receiver


clean:
	rm -r bin


================================================
FILE: wifiRawReceiver/main.c
================================================
/*
Florenc Caminade
Thomas FLayols
Etienne Arlaud

Receive raw 802.11 packet and filter ESP-NOW vendor specific action frame using BPF filters.
https://hackaday.io/project/161896
https://github.com/thomasfla/Linux-ESPNOW

Adapted from :
https://stackoverflow.com/questions/10824827/raw-sockets-communication-over-wifi-receiver-not-able-to-receive-packets

1/Find your wifi interface:
$ iwconfig

2/Setup your interface in monitor mode :
$ sudo ifconfig wlp5s0 down
$ sudo iwconfig wlp5s0 mode monitor
$ sudo ifconfig wlp5s0 up

3/Run this code as root
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if_arp.h>
#include <arpa/inet.h>
#include <assert.h>
#include <linux/filter.h>

#define PACKET_LENGTH 400 //Approximate
#define MYDATA 18         //0x12
#define MAX_PACKET_LEN 1000


/*our MAC address*/
//{0xF8, 0x1A, 0x67, 0xB7, 0xeB, 0x0B};

/*ESP8266 host MAC address*/
//{0x84,0xF3,0xEB,0x73,0x55,0x0D};


//filter action frame packets
  //Equivalent for tcp dump :
    //type 0 subtype 0xd0 and wlan[24:4]=0x7f18fe34 and wlan[32]=221 and wlan[33:4]&0xffffff = 0x18fe34 and wlan[37]=0x4
//NB : There is no filter on source or destination addresses, so this code will 'receive' the action frames sent by this computer...
#define FILTER_LENGTH 20
static struct sock_filter bpfcode[FILTER_LENGTH] = {
  { 0x30, 0, 0, 0x00000003 },	// ldb [3]	// radiotap header length : MS byte
  { 0x64, 0, 0, 0x00000008 },	// lsh #8	// left shift it
  { 0x7, 0, 0, 0x00000000 },	// tax		// 'store' it in X register
  { 0x30, 0, 0, 0x00000002 },	// ldb [2]	// radiotap header length : LS byte
  { 0x4c, 0, 0, 0x00000000 },	// or  x	// combine A & X to get radiotap header length in A
  { 0x7, 0, 0, 0x00000000 },	// tax		// 'store' it in X
  { 0x50, 0, 0, 0x00000000 },	// ldb [x + 0]		// right after radiotap header is the type and subtype
  { 0x54, 0, 0, 0x000000fc },	// and #0xfc		// mask the interesting bits, a.k.a 0b1111 1100
  { 0x15, 0, 10, 0x000000d0 },	// jeq #0xd0 jt 9 jf 19	// compare the types (0) and subtypes (0xd)
  { 0x40, 0, 0, 0x00000018 },	// Ld  [x + 24]			// 24 bytes after radiotap header is the end of MAC header, so it is category and OUI (for action frame layer)
  { 0x15, 0, 8, 0x7f18fe34 },	// jeq #0x7f18fe34 jt 11 jf 19	// Compare with category = 127 (Vendor specific) and OUI 18:fe:34
  { 0x50, 0, 0, 0x00000020 },	// ldb [x + 32]				// Begining of Vendor specific content + 4 ?random? bytes : element id
  { 0x15, 0, 6, 0x000000dd },	// jeq #0xdd jt 13 jf 19		// element id should be 221 (according to the doc)
  { 0x40, 0, 0, 0x00000021 },	// Ld  [x + 33]				// OUI (again!) on 3 LS bytes
  { 0x54, 0, 0, 0x00ffffff },	// and #0xffffff			// Mask the 3 LS bytes
  { 0x15, 0, 3, 0x0018fe34 },	// jeq #0x18fe34 jt 16 jf 19		// Compare with OUI 18:fe:34
  { 0x50, 0, 0, 0x00000025 },	// ldb [x + 37]				// Type
  { 0x15, 0, 1, 0x00000004 },	// jeq #0x4 jt 18 jf 19			// Compare type with type 0x4 (corresponding to ESP_NOW)
  { 0x6, 0, 0, 0x00040000 },	// ret #262144	// return 'True'
  { 0x6, 0, 0, 0x00000000 },	// ret #0	// return 'False'
};

void print_packet(uint8_t *data, int len)
{
    printf("----------------------------new packet-----------------------------------\n");
    int i;
    for (i = 0; i < len; i++)
    {
        if (i % 16 == 0)
            printf("\n");
        printf("0x%02x, ", data[i]);
    }
    printf("\n\n");
}

int create_raw_socket(char *dev, struct sock_fprog *bpf)
{
    struct sockaddr_ll sll;
    struct ifreq ifr;
    int fd, ifi, rb, attach_filter;

    bzero(&sll, sizeof(sll));
    bzero(&ifr, sizeof(ifr));

    fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    assert(fd != -1);

    strncpy((char *)ifr.ifr_name, dev, IFNAMSIZ);
    ifi = ioctl(fd, SIOCGIFINDEX, &ifr);
    assert(ifi != -1);

    sll.sll_protocol = htons(ETH_P_ALL);
    sll.sll_family = PF_PACKET;
    sll.sll_ifindex = ifr.ifr_ifindex;
    sll.sll_pkttype = PACKET_OTHERHOST;

    rb = bind(fd, (struct sockaddr *)&sll, sizeof(sll));
    assert(rb != -1);

    attach_filter = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, sizeof(*bpf));
    assert(attach_filter != -1);

    return fd;
}

int main(int argc, char **argv)
{
    assert(argc == 2);

    uint8_t buff[MAX_PACKET_LEN] = {0};
    int sock_fd;
    char *dev = argv[1];
    struct sock_fprog bpf = {FILTER_LENGTH, bpfcode};

    sock_fd = create_raw_socket(dev, &bpf); /* Creating the raw socket */

    printf("\n Waiting to receive packets ........ \n");

    while (1)
    {
        int len = recvfrom(sock_fd, buff, MAX_PACKET_LEN, MSG_TRUNC, NULL, 0);

        if (len < 0)
        {
            perror("Socket receive failed or error");
            break;
        }
        else
        {
            printf("len:%d\n", len);
            print_packet(buff, len);
        }
    }
    close(sock_fd);
    return 0;
}


================================================
FILE: wifiRawSender/Makefile
================================================
test:
	mkdir -p bin
	gcc main.c -Wall -o bin/sender

clean:
	rm -r bin


================================================
FILE: wifiRawSender/main.c
================================================
/*
Florenc Caminade
Thomas FLayols

Send ESP-NOW vendor specific action frame example
https://hackaday.io/project/161896
https://github.com/thomasfla/Linux-ESPNOW

Adapted from : 
https://stackoverflow.com/questions/10824827/raw-sockets-communication-over-wifi-receiver-not-able-to-receive-packets

1/Find your wifi interface:
$ iwconfig

2/Setup your interface in monitor mode :
$ sudo ifconfig wlp5s0 down
$ sudo iwconfig wlp5s0 mode monitor
$ sudo ifconfig wlp5s0 up

3/Run this code as root
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if_arp.h>
#include <arpa/inet.h>
#include <assert.h>


static uint8_t gu8a_dest_mac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

int create_raw_socket(char *dev)
{
    struct sockaddr_ll s_dest_addr; //code from sender
    struct ifreq ifr;
    int fd, ifi, rb;

    bzero(&s_dest_addr, sizeof(s_dest_addr));
    bzero(&ifr, sizeof(ifr));

    (void)memset(&s_dest_addr, 0, sizeof(s_dest_addr));

    fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    assert(fd != -1); //abort if error

    strncpy((char *)ifr.ifr_name, dev, IFNAMSIZ);
    ifi = ioctl(fd, SIOCGIFINDEX, &ifr);
    assert(ifi != -1); //abort if error

    s_dest_addr.sll_family = PF_PACKET;
    //we don't use a protocol above ethernet layer, just use anything here
    s_dest_addr.sll_protocol = htons(ETH_P_ALL);
    s_dest_addr.sll_ifindex = ifr.ifr_ifindex;
    s_dest_addr.sll_hatype = ARPHRD_ETHER;
    s_dest_addr.sll_pkttype = PACKET_OTHERHOST; //PACKET_OUTGOING
    s_dest_addr.sll_halen = ETH_ALEN;
    //MAC - begin
    s_dest_addr.sll_addr[0] = gu8a_dest_mac[0];
    s_dest_addr.sll_addr[1] = gu8a_dest_mac[1];
    s_dest_addr.sll_addr[2] = gu8a_dest_mac[2];
    s_dest_addr.sll_addr[3] = gu8a_dest_mac[3];
    s_dest_addr.sll_addr[4] = gu8a_dest_mac[4];
    s_dest_addr.sll_addr[5] = gu8a_dest_mac[5];
    //MAC - end
    s_dest_addr.sll_addr[6] = 0x00; //not used
    s_dest_addr.sll_addr[7] = 0x00; //not used

    rb = bind(fd, (struct sockaddr *)&s_dest_addr, sizeof(s_dest_addr));
    assert(rb != -1); //abort if error

    return fd;
}

int main(int argc, char **argv)
{
    char *dev = argv[1];

    int sock_fd = -1;
    int32_t s32_res = -1;

    sock_fd = create_raw_socket(dev); /* Creating the raw socket */

    if (-1 == sock_fd)
    {
        perror("Could not create the socket");
        goto LABEL_CLEAN_EXIT;
    }

    printf("Socket created\n");

    fflush(stdout);

    sleep(1);

    printf("******Sending data using raw socket over  %s \n", dev);

    while (1)
    {
        uint8_t data[331] = {
            0x00, 0x00, 0x26, 0x00, 0x2f, 0x40, 0x00, 0xa0, 0x20, 0x08, 0x00, 0xa0, 0x20, 0x08, 0x00, 0x00,
            0xdf, 0x32, 0xfe, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0c, 0x6c, 0x09, 0xc0, 0x00, 0xd3, 0x00,
            0x00, 0x00, 0xd3, 0x00, 0xc7, 0x01, 0xd0, 0x00, 0x3a, 0x01, 0x84, 0xf3, 0xeb, 0x73, 0x55, 0x0d,
            0xf8, 0x1a, 0x67, 0xb7, 0xeb, 0x0b, 0x84, 0xf3, 0xeb, 0x73, 0x55, 0x0d, 0x70, 0x51, 0x7f, 0x18,
            0xfe, 0x34, 0xa2, 0x03, 0x92, 0xb0, 0xdd, 0xff, 0x18, 0xfe, 0x34, 0x04, 0x01, 0x29, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
            0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x1c, 0xd5, 0x35, 0xd3}; //FROM TLINK TO ESP

        s32_res = sendto(sock_fd,data,331,0,NULL,0);

        if (-1 == s32_res)
        {
            perror("Socket send failed");
            goto LABEL_CLEAN_EXIT;
        }
        int i = 0;
        for (i = 0; i < 331; i++)
            printf("%x ", data[i]);

        printf("\n\n");

        usleep(100);
    }

LABEL_CLEAN_EXIT:
    if (sock_fd > 0)
    {
        close(sock_fd);
    }

    printf("***** Raw Socket test- end\n");

    return EXIT_SUCCESS;
}
Download .txt
gitextract_42a6adbu/

├── .gitignore
├── ESP32-Test/
│   ├── ESP32-Test.ino
│   ├── PYTHON_serial/
│   │   └── serial_logger.py
│   ├── p_histogram.ino
│   ├── t_callbacks.ino
│   └── z_setup_loop.ino
├── ESP8266-Test/
│   ├── ESP8266-Test.ino
│   └── serial_logger.py
├── ESP8266_Echo/
│   └── ESP8266_Echo.ino
├── ESPNOW_lib/
│   ├── Makefile
│   ├── README.MD
│   └── src/
│       ├── ESPNOW_manager.cpp
│       ├── ESPNOW_types.cpp
│       ├── Includes/
│       │   ├── ESPNOW_manager.h
│       │   └── ESPNOW_types.h
│       └── main.cpp
├── LICENSE
├── Lab/
│   └── EspNowPacket/
│       ├── EspNowPacket.c
│       └── Makefile
├── README.md
├── wifiRawEcho/
│   ├── Includes/
│   │   └── ESPNOW_packet.h
│   ├── Makefile
│   └── src/
│       ├── ESPNOW_packet.c
│       └── main.c
├── wifiRawReceiver/
│   ├── Makefile
│   └── main.c
└── wifiRawSender/
    ├── Makefile
    └── main.c
Download .txt
SYMBOL INDEX (38 symbols across 11 files)

FILE: ESP32-Test/PYTHON_serial/serial_logger.py
  function read (line 28) | def read(display=True):
  function read_int (line 36) | def read_int(i):
  function decode_histo (line 39) | def decode_histo():

FILE: ESPNOW_lib/src/ESPNOW_manager.cpp
  type sock_filter (line 55) | struct sock_filter
  type sock_filter (line 112) | struct sock_filter
  type sockaddr_ll (line 117) | struct sockaddr_ll
  type ifreq (line 118) | struct ifreq
  type sockaddr (line 142) | struct sockaddr
  type thread_args (line 196) | struct thread_args
  type thread_args (line 196) | struct thread_args

FILE: ESPNOW_lib/src/Includes/ESPNOW_manager.h
  type thread_args (line 16) | struct thread_args {
  function class (line 21) | class ESPNOW_manager {

FILE: ESPNOW_lib/src/Includes/ESPNOW_types.h
  type IEEE80211_actionframe (line 82) | struct IEEE80211_actionframe {

FILE: ESPNOW_lib/src/main.cpp
  function callback (line 27) | void callback(uint8_t src_mac[6], uint8_t *data, int len) {
  function main (line 34) | int main(int argc, char **argv) {

FILE: Lab/EspNowPacket/EspNowPacket.c
  function create_raw_socket (line 44) | int create_raw_socket(char *dev)
  function main (line 86) | int main(int argc, char **argv)
  type ieee80211_radiotap_header (line 142) | struct ieee80211_radiotap_header
  type ieee80211_wlan (line 157) | struct ieee80211_wlan
  type espPacket (line 177) | typedef struct
  function packetSetUp (line 185) | int packetSetUp(uint8_t* packet, uint8_t* mac_dest, uint8_t* mac_src, ui...

FILE: wifiRawEcho/Includes/ESPNOW_packet.h
  type IEEE80211_radiotap (line 7) | struct IEEE80211_radiotap {
  type IEEE80211_vendorspecific (line 18) | struct IEEE80211_vendorspecific {
  type IEEE80211_actionframe (line 28) | struct IEEE80211_actionframe {
  type IEEE80211_wlan (line 35) | struct IEEE80211_wlan {
  type ESPNOW_packet (line 47) | typedef struct {

FILE: wifiRawEcho/src/ESPNOW_packet.c
  function init_ESPNOW_packet (line 8) | void init_ESPNOW_packet(ESPNOW_packet *packet) {
  function packet_to_bytes (line 50) | int packet_to_bytes(uint8_t *bytes, int max_length, ESPNOW_packet packet) {
  function print_raw_packet (line 60) | void print_raw_packet(uint8_t *data, int len)

FILE: wifiRawEcho/src/main.c
  type sock_filter (line 36) | struct sock_filter
  function create_raw_socket (line 133) | int create_raw_socket(char *dev, struct sock_fprog *bpf)
  function main (line 180) | int main(int argc, char **argv)

FILE: wifiRawReceiver/main.c
  type sock_filter (line 52) | struct sock_filter
  function print_packet (line 75) | void print_packet(uint8_t *data, int len)
  function create_raw_socket (line 88) | int create_raw_socket(char *dev, struct sock_fprog *bpf)
  function main (line 118) | int main(int argc, char **argv)

FILE: wifiRawSender/main.c
  function create_raw_socket (line 36) | int create_raw_socket(char *dev)
  function main (line 78) | int main(int argc, char **argv)
Condensed preview — 28 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (67K chars).
[
  {
    "path": ".gitignore",
    "chars": 515,
    "preview": "# Prerequisites\n*.d\n\n# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic"
  },
  {
    "path": "ESP32-Test/ESP32-Test.ino",
    "chars": 628,
    "preview": "#include <esp_now.h>\n#include <WiFi.h>\n#include <esp_wifi_internal.h>\n\n#include <Ticker.h>  //Ticker Library\n\n#define CH"
  },
  {
    "path": "ESP32-Test/PYTHON_serial/serial_logger.py",
    "chars": 3390,
    "preview": "import serial\nimport sys\nimport matplotlib.pyplot as plt\nfrom matplotlib.ticker import MaxNLocator\n\nbase = \"0123456789+/"
  },
  {
    "path": "ESP32-Test/p_histogram.ino",
    "chars": 2014,
    "preview": "#define HISTO_INF 0\n#define HISTO_SUP 10000\n#define HISTO_N_STEP 100\n\n#define recv_list_len N_BATCH/6\n#define packet_rec"
  },
  {
    "path": "ESP32-Test/t_callbacks.ino",
    "chars": 870,
    "preview": "void sendData() {\n  if(n_sent < N_BATCH) {\n    long mytime = micros();\n    int packet_nb = n_sent - error_send;\n    memc"
  },
  {
    "path": "ESP32-Test/z_setup_loop.ino",
    "chars": 1740,
    "preview": "#define TRY_ESP_ACTION(action, name) if(action == ESP_OK) {Serial.println(\"\\t+ \"+String(name));} else {Serial.println(\"-"
  },
  {
    "path": "ESP8266-Test/ESP8266-Test.ino",
    "chars": 4112,
    "preview": "/*\n   19/02/2019 Mac adress modified : Dell laptop\n\n  Master/Server:\n    Sends a 100Byte ESPNOW data block, and awaits a"
  },
  {
    "path": "ESP8266-Test/serial_logger.py",
    "chars": 350,
    "preview": "import serial\nimport time\nimport csv\nimport sys\n\nassert len(sys.argv)==3\n\n\nser = serial.Serial(sys.argv[1], 115200)\nser."
  },
  {
    "path": "ESP8266_Echo/ESP8266_Echo.ino",
    "chars": 1910,
    "preview": "/*\n   19/02/2019 Mac adress modified : Dell laptop\n\n  Master/Server:\n    Sends a 100Byte ESPNOW data block, and awaits a"
  },
  {
    "path": "ESPNOW_lib/Makefile",
    "chars": 321,
    "preview": "\nCC = g++\nCFLAGS  = -g -Wall -std=c++11\nINCLUDES = -I src/Includes/\n\ndefault: all\n\n%.o: src/%.cpp\n\tmkdir -p bin\n\t$(CC) $"
  },
  {
    "path": "ESPNOW_lib/README.MD",
    "chars": 288,
    "preview": "# Before using this code\nDo not forget to turn on monitor mode and choose the right channel on your wireless interface c"
  },
  {
    "path": "ESPNOW_lib/src/ESPNOW_manager.cpp",
    "chars": 7206,
    "preview": "\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <sys/types.h>\n#include <stdint.h>\n#include <pthread"
  },
  {
    "path": "ESPNOW_lib/src/ESPNOW_types.cpp",
    "chars": 1889,
    "preview": "#include \"ESPNOW_types.h\"\n\n#include <stdint.h>\n#include <string.h>\n#include <sys/types.h>\n#include <assert.h>\n\nvoid ESPN"
  },
  {
    "path": "ESPNOW_lib/src/Includes/ESPNOW_manager.h",
    "chars": 1933,
    "preview": "#ifndef ESPNOW_manager_H\n#define ESPNOW_manager_H\n\n#include <stdint.h>\n#include <linux/filter.h>\n#include <string.h>\n#in"
  },
  {
    "path": "ESPNOW_lib/src/Includes/ESPNOW_types.h",
    "chars": 3276,
    "preview": "#ifndef ESPNOW_TYPES_H\n#define ESPNOW_TYPES_H\n\n#include <string.h>\n#include <stdint.h>\n\n#define DATARATE_1Mbps 0x02\n#def"
  },
  {
    "path": "ESPNOW_lib/src/main.cpp",
    "chars": 1045,
    "preview": "/*\nEtienne Arlaud\n*/\n\n#include <stdint.h>\n#include <stdio.h>\n\n#include <assert.h>\n#include <unistd.h>\n#include <sys/time"
  },
  {
    "path": "LICENSE",
    "chars": 1314,
    "preview": "BSD 2-Clause License\n\nCopyright (c) 2019, thomasfla\nAll rights reserved.\n\nRedistribution and use in source and binary fo"
  },
  {
    "path": "Lab/EspNowPacket/EspNowPacket.c",
    "chars": 7051,
    "preview": "/*\nFlorenc Caminade\nThomas FLayols\n\nSend ESP-NOW vendor specific action frame example\nhttps://hackaday.io/project/161896"
  },
  {
    "path": "Lab/EspNowPacket/Makefile",
    "chars": 78,
    "preview": "test:\n\tmkdir -p bin\n\tgcc EspNowPacket.c -Wall  -o bin/main\n\nclean:\n\trm -r bin\n"
  },
  {
    "path": "README.md",
    "chars": 210,
    "preview": "# Linux-ESPNOW\nAn attempt at implementing a direct link between a linux station and an ESP module using ESPNOW protocol "
  },
  {
    "path": "wifiRawEcho/Includes/ESPNOW_packet.h",
    "chars": 1804,
    "preview": "#ifndef ESPNOW_PACKET_H\n#define ESPNOW_PACKET_H\n\n#include <stdint.h>\n#include <stdio.h>\n\nstruct IEEE80211_radiotap {\n\tui"
  },
  {
    "path": "wifiRawEcho/Makefile",
    "chars": 275,
    "preview": "\nCC = gcc\nCFLAGS  = -g -Wall --std=c99\nINCLUDES = -I Includes/\n\ndefault: all\n\n%.o: src/%.c\n\t$(CC) $(CFLAGS) $(INCLUDES) "
  },
  {
    "path": "wifiRawEcho/src/ESPNOW_packet.c",
    "chars": 1822,
    "preview": "#include \"ESPNOW_packet.h\"\n#include <stdio.h>\n#include <string.h>\n#include <assert.h>\n#include <sys/time.h>\n\n\nvoid init_"
  },
  {
    "path": "wifiRawEcho/src/main.c",
    "chars": 7040,
    "preview": "/*\nEtienne Arlaud\n*/\n\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>"
  },
  {
    "path": "wifiRawReceiver/Makefile",
    "chars": 74,
    "preview": "test:\n\tmkdir -p bin\n\tgcc main.c -Wall -o bin/receiver\n\n\nclean:\n\trm -r bin\n"
  },
  {
    "path": "wifiRawReceiver/main.c",
    "chars": 4940,
    "preview": "/*\nFlorenc Caminade\nThomas FLayols\nEtienne Arlaud\n\nReceive raw 802.11 packet and filter ESP-NOW vendor specific action f"
  },
  {
    "path": "wifiRawSender/Makefile",
    "chars": 71,
    "preview": "test:\n\tmkdir -p bin\n\tgcc main.c -Wall -o bin/sender\n\nclean:\n\trm -r bin\n"
  },
  {
    "path": "wifiRawSender/main.c",
    "chars": 5399,
    "preview": "/*\nFlorenc Caminade\nThomas FLayols\n\nSend ESP-NOW vendor specific action frame example\nhttps://hackaday.io/project/161896"
  }
]

About this extraction

This page contains the full source code of the thomasfla/Linux-ESPNOW GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 28 files (60.1 KB), approximately 23.2k tokens, and a symbol index with 38 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!