From 9948e344d5fad0d300d4c4f070dd21f04aaec1f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jurij=20Podgor=C5=A1ek?= Date: Wed, 11 Sep 2024 20:16:41 +0200 Subject: [PATCH] WIP sprejemnik --- linux-receiver/Makefile | 7 + linux-receiver/bin/receiver | Bin 0 -> 17208 bytes linux-receiver/main.c | 253 ++++++++++++++++++++++++++++++++++++ linux-receiver/pozeni.sh | 3 + linux-receiver/prep.sh | 10 ++ linux-receiver/slip.c | 198 ++++++++++++++++++++++++++++ linux-receiver/slip.h | 84 ++++++++++++ 7 files changed, 555 insertions(+) create mode 100644 linux-receiver/Makefile create mode 100755 linux-receiver/bin/receiver create mode 100644 linux-receiver/main.c create mode 100755 linux-receiver/pozeni.sh create mode 100755 linux-receiver/prep.sh create mode 100644 linux-receiver/slip.c create mode 100644 linux-receiver/slip.h diff --git a/linux-receiver/Makefile b/linux-receiver/Makefile new file mode 100644 index 0000000..94da93c --- /dev/null +++ b/linux-receiver/Makefile @@ -0,0 +1,7 @@ +test: + mkdir -p bin + gcc main.c -Wall -o bin/receiver -llo + + +clean: + rm -r bin diff --git a/linux-receiver/bin/receiver b/linux-receiver/bin/receiver new file mode 100755 index 0000000000000000000000000000000000000000..5e24fe22a2819c8d84b2b5a87fdc9bb1dabf6cf6 GIT binary patch literal 17208 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 x`bYJ|{)5ob)P?)a*Izn6xa}@?AwH@k{y$ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Debug? +#define DEBUG + +// Booleans +#include + +// OSC +#include "lo/lo.h" +#include "lo/lo_lowlevel.h" +#include "lo/lo_osc_types.h" + +#define PACKET_LENGTH 400 //Approximate +#define MAX_PACKET_LEN 1000 + +// ESPNOW data payload starts at byte 60 +#define ESP_DATA_OFFSET 57 + +// Sensor message +#include "../src/sensor_msg.h" + +// Maksimalno stevilo +#define ST_SPREJEMNIKOV 10 + +uint8_t odcitekId; +sensor_msg odcitki[ST_SPREJEMNIKOV]; +bool poslji[ST_SPREJEMNIKOV]; + +#include +struct timeval cas; +struct timeval zdaj; +int eps = 0; + +/*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) { + /* + char macNaslov[18]; + snprintf(macNaslov, sizeof(macNaslov), "%02x:%02x:%02x:%02x:%02x:%02x", + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + + printf("%s\n", macNaslov); + */ + //printf("Prejel podatke dolzine %i \n", len); + + // ID senzorja + odcitekId = (uint8_t) data[ESP_DATA_OFFSET]; + + // Vrednosti + memcpy(&odcitki[odcitekId], data + ESP_DATA_OFFSET, sizeof(sensor_msg)); + poslji[odcitekId] = true; + +#ifdef DEBUG + printf("senzor %i\n", odcitekId); + printf("aX: %f \n", odcitki[odcitekId].aX); + printf("aY: %f \n", odcitki[odcitekId].aY); + printf("aZ: %f \n", odcitki[odcitekId].aZ); + printf("qW: %f \n", odcitki[odcitekId].qW); + printf("qX: %f \n", odcitki[odcitekId].qX); + printf("qY: %f \n", odcitki[odcitekId].qY); + printf("qZ: %f \n", odcitki[odcitekId].qZ); + printf("bat: %f \n", odcitki[odcitekId].bat); +#endif + + + + + eps += 1; + gettimeofday(&zdaj, NULL); + + if (zdaj.tv_sec != cas.tv_sec) { + printf("Paketov na sekundo: %i\n", eps); + eps = 0; + gettimeofday(&cas, NULL); + } + return; + + // @TODO locen thread za posiljanje? + char glava[32]; + lo_bundle svezenj; + lo_message m; + char* sporocilo; + size_t dolzina; + + for (int i = 0; i < ST_SPREJEMNIKOV; i++) { + if (poslji[i]) { + // Ustvarim bundle (svezenj) + svezenj = lo_bundle_new(LO_TT_IMMEDIATE); + + // Dodamo sporocila + sprintf(glava, "/ww/%d/acc", i); + m = lo_message_new(); + lo_message_add_float(m, odcitki[i].aX); + lo_message_add_float(m, odcitki[i].aY); + lo_message_add_float(m, odcitki[i].aZ); + + //free(sporocilo); + + lo_bundle_add_message(svezenj, glava, m); + sprintf(glava, "/ww/%d/quat", i); + m = lo_message_new(); + lo_message_add_float(m, odcitki[i].qW); + lo_message_add_float(m, odcitki[i].aX); + lo_message_add_float(m, odcitki[i].aY); + lo_message_add_float(m, odcitki[i].aZ); + + lo_bundle_add_message(svezenj, glava, m); + + sporocilo = lo_bundle_serialise(svezenj, NULL, &dolzina); + lo_bundle_pp(svezenj); + printf("%s\n", sporocilo); + lo_bundle_free(svezenj); + + //printf("%s\n", glava); + //free(sporocilo); + } + } + /* DEBUG - print whole raw packet + for (int i = 0; i < len; i++) { + printf("0x%02x ", data[i]); + } + printf("\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"); + + gettimeofday(&cas, NULL); + + 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; +} diff --git a/linux-receiver/pozeni.sh b/linux-receiver/pozeni.sh new file mode 100755 index 0000000..df49dc1 --- /dev/null +++ b/linux-receiver/pozeni.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +sudo ./bin/receiver wlxd0aeec558360 diff --git a/linux-receiver/prep.sh b/linux-receiver/prep.sh new file mode 100755 index 0000000..b8b775c --- /dev/null +++ b/linux-receiver/prep.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +dev="wlxd0aeec558360" +chan="1" +# sudo bash prep.sh *iface* *channel* +# sudo bash prep.sh wlp1s0 8 +ifconfig $dev down +iwconfig $dev mode monitor +ifconfig $dev up +iwconfig $dev channel $chan diff --git a/linux-receiver/slip.c b/linux-receiver/slip.c new file mode 100644 index 0000000..ea31304 --- /dev/null +++ b/linux-receiver/slip.c @@ -0,0 +1,198 @@ +#include "slip.h" + +/** + * @brief Internal SLIP character values. + **/ +typedef enum { + END = 0xC0, + ESC = 0xDB, + ESC_END = 0xDC, + ESC_ESC = 0xDD +} slip_char_t; + +/** + * @brief Internal SLIP encoder state. + **/ +typedef enum { + STATE_MESSAGE, + STATE_ERROR, + STATE_ESCAPE +} slip_state_t; + +/** + * @brief Initialise a SLIP encoder or decoder. + * + * @param[in] slip : Pointer to SLIP encoder or decoder. + * @param[in] buf : Buffer to hold encoded or decoded message. + * @param[in] len : Length of buffer + **/ +void SLIP_init(slip_t *slip, uint8_t *buf, size_t len, slip_encoding_t encoding) +{ + slip->buf = buf; + slip->len = len; + slip->state = STATE_MESSAGE; + slip->wp = 0; + slip->encoding = encoding; +} + +/** + * @brief Reset SLIP encoder or decoder. + * + * @param[in] slip : Pointer to SLIP encoder or decoder. + **/ +void SLIP_reset(slip_t *slip) +{ + slip->state = STATE_MESSAGE; + slip->wp = 0; +} + +/** + * @brief Gets the length of the encoded or decoded message so far. + * + * @param[in] slip : Pointer to SLIP encoder or decoder. + * + * @return Length of message. + */ +size_t SLIP_get_length(slip_t *slip) +{ + return slip->wp; +} + +/** + * @brief Consume byte for SLIP encoding. + * + * @param[in] slip : Pointer to SLIP encoder. + * @param[in] byte : Byte to be encoded. + * + * @return < 0 : Error + * = 0 : Encoded byte + * > 0 : Success/Finished (Length of encoded data) + **/ +static int SLIP_encode_byte(slip_t *slip, uint8_t byte) +{ + int remaining = slip->len - slip->wp; + int required = (byte == ESC || byte == END) ? 2 : 1; + + if (remaining < required) { + return -1; + } + + if (byte == ESC) + { + slip->buf[slip->wp++] = ESC; + slip->buf[slip->wp++] = ESC_ESC; + } + else if (byte == END) { + slip->buf[slip->wp++] = ESC; + slip->buf[slip->wp++] = ESC_END; + } + else { + slip->buf[slip->wp++] = byte; + } + + return 0; +} + +/** + * @brief SLIP encodes a given frame + * + * @param[in] slip : Pointer to SLIP encoder. + * @param[in] buf : Buffer containing frame. + * @param[in] len : Length of buffer + * + * @return > 0 : Success (Length of encoded data) + * = 0 : Failed + **/ +size_t SLIP_encode(slip_t *slip, const uint8_t *buf, size_t len) +{ + SLIP_reset(slip); + + if(slip->encoding == SLIP_ENCODING_DOUBLE_ENDED && slip->wp == 0) { + /* Start of message */ + /* Double encoded SLIP, where an END delimiter is also added to the beginning of the message */ + slip->buf[slip->wp++] = END; + } + + while(len--) { + if(SLIP_encode_byte(slip, *buf++) < 0) { + /* SLIP encoding failed */ + return 0; + } + } + + if((slip->len - slip->wp) < 1) { + /* No space for END delimiter */ + return 0; + } + + slip->buf[slip->wp++] = END; + return slip->wp; +} + +/** + * @brief Consume byte for SLIP decoding. + * + * @param[in] slip : Pointer to SLIP decoder. + * @param[in] byte : Byte to be decoded. + * + * @return < 0 : Error + * = 0 : Decoded byte + * > 0 : Success/Finished (Length of decoded data) + **/ +int SLIP_decode(slip_t *slip, uint8_t byte) +{ + int retVal = 0; + + if(byte == END) + { + if(slip->wp == 0) { + /* Double ended SLIP encoding. This indicatees the beginning of a SLIP message */ + retVal = 0; + } + else if(slip->wp > 0 && slip->state == STATE_MESSAGE) { + retVal = slip->wp; + } else { + retVal = -1; + } + SLIP_reset(slip); + return retVal; + } + + switch(slip->state) + { + case STATE_MESSAGE: + { + if(slip->wp == slip->len) { + /* ERROR: Ran out of buffer space */ + SLIP_reset(slip); + return -1; + } else if(byte == ESC) { + slip->state = STATE_ESCAPE; + } else { + slip->buf[slip->wp++] = byte; + } + break; + } + case STATE_ESCAPE: + { + if(byte == ESC_END) { + slip->buf[slip->wp++] = END; + slip->state = STATE_MESSAGE; + } else if(byte == ESC_ESC) { + slip->buf[slip->wp++] = ESC; + slip->state = STATE_MESSAGE; + } else { + /* ERROR: Wrong character received */ + SLIP_reset(slip); + return -1; + } + break; + } + case STATE_ERROR: { + SLIP_reset(slip); + return -1; + } + } + + return 0; +} \ No newline at end of file diff --git a/linux-receiver/slip.h b/linux-receiver/slip.h new file mode 100644 index 0000000..3752fb4 --- /dev/null +++ b/linux-receiver/slip.h @@ -0,0 +1,84 @@ +#pragma once + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Type of SLIP encoding to use. + */ +typedef enum { + SLIP_ENCODING_SINGLE_ENDED, /* END delimiter is only added to the end of the msg */ + SLIP_ENCODING_DOUBLE_ENDED /* END delimiter is added to the beginning and the end of the msg */ +} slip_encoding_t; + +/** + * @brief Private SLIP structure. + * @warning: Structure is not to be accessed directly by user. + */ +typedef struct { + uint8_t *buf; + size_t len; + size_t wp; + uint8_t state; + slip_encoding_t encoding; +} slip_t; + +/** + * @brief Initialise a SLIP encoder or decoder. + * + * @param[in] slip : Pointer to SLIP encoder or decoder. + * @param[in] buf : Buffer to hold encoded or decoded message. + * @param[in] len : Length of buffer + **/ +void SLIP_init(slip_t *slip, uint8_t *buf, size_t len, slip_encoding_t encoding); + +/** + * @brief Reset SLIP encoder or decoder. + * + * @param[in] slip : Pointer to SLIP encoder or decoder. + **/ +void SLIP_reset(slip_t *slip); + +/** + * @brief Gets the length of the encoded or decoded message so far. + * + * @param[in] slip : Pointer to SLIP encoder or decoder. + * + * @return Length of message. + */ +size_t SLIP_get_length(slip_t *slip); + +/** + * @brief SLIP encodes a given frame + * + * @param[in] slip : Pointer to SLIP encoder. + * @param[in] buf : Buffer containing frame. + * @param[in] len : Length of buffer + * + * @return > 0 : Success (Length of encoded data) + * = 0 : Failed + **/ +size_t SLIP_encode(slip_t *slip, const uint8_t *buf, size_t len); + +/** + * @brief Consume byte for SLIP decoding. + * + * @param[in] slip : Pointer to SLIP decoder. + * @param[in] byte : Byte to be decoded. + * + * @return < 0 : Error + * = 0 : Decoded byte + * > 0 : Success/Finished (Length of decoded data) + **/ +int SLIP_decode(slip_t *slip, uint8_t byte); + + + +#ifdef __cplusplus +} +#endif +