Code Monkey home page Code Monkey logo

radio-firmware's People

Contributors

gustavosinbandera1 avatar jeandudey avatar luisan00 avatar rdymac avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

radio-firmware's Issues

Max. number of routes in routing table.

We need to find an optimal number of entries in the routing table without using too much RAM for the moment.

Ideally we should investigate how much memory the firmware uses and then choose an optimal value.

Refactor McMsg implementation

Description

We currently call this rreqtable, we should change this (and improve) the implementation of this table, in order to fix possible bugs, and also, to catch up with the latest draft.

List of things to do

  • Rename to McMsg Set (probably with a 3 letter acronym to be more ergonomic when coding).
  • Catch up with the standard.
  • Add proper documentation.
  • Verify it doesn't have race conditions.

See also

UART communication between CC1312 and ESP32

Communicating MCUs through the UART port

This feature is necessary to communicate both MCUs

We have a bunch of options available, for example:

Implement Neighbor Set

The neighbor set contains information about neighboring AODVv2 routers, this differs from the NIB on RIOT-OS which is specific to link local nodes and NDP itself.

Having a complete implementation could give more benefits as outlined in the draft, although not explicitly needed.

I'm currently working on the Local Route Set, if anyone is willing to work on this feel free to comment here and take a look.

A possible implementation of the entries would look like this:

/**
 * @brief   Neighbor Set entry
 * 
 * @see <a href="https://tools.ietf.org/html/draft-perkins-manet-aodvv2-03#section-4.3">
 *          draft-perkins-manet-aodvv2-03, Section 4.3. Neighbor Set
 *      </a>
 */
typedef struct {
    /**
     * @brief   An IP address of the neighboring router.
     */
    ipv6_addr_t address;
    /**
     * @brief   Indicates whether the link to the neighbor is bidirectional.
     */
    uint8_t state;
    /**
     * @brief   Indicates the time at which the Neighbor.State should be updated:
     */
    timex_t timeout; 
    /**
     * @brief   The interface on which the link to the neighbor was established.
     */
    gnrc_netif_t *interface;
    aodvv2_seqnum_t ack_seqnum;
    aodvv2_seqnum_t heard_rerr_seqnum;
} aodvv2_neighbor_t;

Further reading

PANID generation.

Currently we don't set a 802.15.4 PANID (Personal Area Network ID). In normal RPL protocols (centralized) the PANID is generated by the root node I think (I'm not sure about this).

Prefix based routing

Currently we treat all addresses equally, with the 128 bits as the complete "prefix", this should be configurable in AODVv2.

This eases the configuration of the router client set as we only have to add a prefix with the proper length.

Add RGB leds and Buttons to Turpial board definition.

Currently the RGB and Buttons for the final Turpial board are to be defined. We need to define:

  • Add function to print board configuration, to easily access the information when debugging.
  • RGB led pins, initialize them.
  • Buttons.

Functionality also for them is needed to be defined though.

Use proper frontEndMode in CMD_PROP_RADIO_DIV_SETUP command

As per the documentation says, these values are available:

 uint16_t frontEndMode:3;               //!< \brief 0x00: Differential mode<br>
                                        //!<        0x01: Single-ended mode RFP<br>
                                        //!<        0x02: Single-ended mode RFN<br>
                                        //!<        0x05 Single-ended mode RFP with external frontend control on RF pins (RFN and RXTX)<br>
                                        //!<        0x06 Single-ended mode RFN with external frontend control on RF pins (RFP and RXTX)<br>
                                        //!<        Others: <i>Reserved</i>

We need to investigate what is the right value to use with the Turpial boards.

Route Request Message - RREQ -

To know routes, it is necessary to send a broadcast message with a route request format, as described in the aodvv2 protocol.
To reach the goal, after get the message and parse it, inside AODVv2 module , we need to create a Route request message format using oonf_rfc5444 api and attach it as a message inside original packet structure from application layer, and send it as a broadcast message

operations flow chart of the aodvv2 protocol

draw a flowchart describing the operation of the AODVV2 protocol

The AODVv2 protocol's operations include:

  1. managing sequence numbers.
  2. monitoring adjacent AODVv2 routers.
    3, Performing route discovery and dealing with requests from other routers.
    4.Processing incoming route information and updating the route table.
    5.Suppressing redundant messages.
    6.Maintaining the route table and reporting broken routes.

Add 'turpial' board definition

RIOT allows to write board modules outside of the RIOT repository, certain features need to be enabled in the CC1312 MCU in order to use it correctly (mainly for the UART0/UART1 pin changes).

Setup firmware to use RIOT

In the first revisions of the firmware we used Contiki-NG as our OS. For maintainability decisions we now are going to use RIOT.

Here is a checklist of what needs to be done:

  • Remove the contiki-ng project
  • Set a RIOT submodule pointing to our fork.
  • Add a basic project structure.

Bootloader support

Bootloader Support
This feature is necessary if we want to update the firmware directly from the master MCU (esp32).
Without a bootloader in the radio module we can only flash the firmware through the JTAG interface.

Parsing the packet captured in the network layer from the application layer

After getting the package inside gnrc_aodvv2 module from the application layer, we need the next:

  1. PARSE THE PACKET: When gnrc_aodvv2 module get a packet from app layer, this packet need to has special considerations in order to handle the information in right way
  2. SET AND GET after parse all information inside the packet, gnrc_aodvv2, will change some information according to the case, for instance if there arent any routing information to send a packet , gnrc_aodvv2 module will need to edit target address or destine address to multicast address in order to send a multicast messages to all nodes in the local network .

Structure of the packet when it arrive to gnrx_aodvv2 module from app layer

Type to represent parts (either headers or payload) of a packet, called snips.

The idea behind the packet snips is that they either can represent protocol-specific headers or payload. A packet can be comprised of multiple pktsnip_t elements.

example
Fig1.

                                                    buffer
+---------------------------+                      +------+
| size = 14                 | data +-------------->|      |
| type = NETTYPE_ETHERNET   |------+               +------+
+---------------------------+                      .      .
      | next                                       .      .
      v                                            +------+
+---------------------------+         +----------->|      |
| size = 40                 | data    |            |      |
| type = NETTYPE_IPV6       |---------+            +------+
+---------------------------+                      .      .
      | next                                       .      .
      v                                            +------+
+---------------------------+            +-------->|      |
| size = 8                  | data       |         +------+
| type = NETTYPE_UDP        |------------+         .      .
+---------------------------+                      .      .
      | next                                       +------+
      v                                     +----->|      |
+---------------------------+               |      |      |
| size = 59                 | data          |      .      .
| type = NETTYPE_UNDEF      |---------------+      .      .
+---------------------------+                      .      .

To keep data duplication as low as possible the order of the snips in a packet will be reversed depending on if you send the packet or if you received it. For sending the order is from (in the network stack) lowest protocol snip to the highest, for receiving the order is from highest snip to the lowest. This way, if a layer needs to duplicate the packet a tree is created rather than a duplication of the whole package.

A very extreme example for this (we only expect one or two duplications at maximum per package) can be seen here:
Fig2.

Sending                          Receiving
 =======                          =========

 * Payload                        * L2 header
 ^                                ^
 |                                |
 |\                               |\
 | * L4 header 1                  | * L2.5 header 1
 | * L3 header 1                  | * L3 header 1
 | * netif header 1               | * L4 header 1
 * L4 header 2                    | * Payload 1
 ^                                * L3 header 2
 |                                ^
 |\                               |
 | * L3 header 2                  |\
 | * L2 header 2                  | * L4 header 2
 * L2 header 3                    | * Payload 2
 |\                               * Payload 3
 | * L2 header 3
 * L2 header 4

Parse the packet

After receive the packet from app layer to gnrc_aodvv2 module, it will need to parse the incoming headers to know some useful information. as the Fig2 is showing , when app layer is trying to send a message , how gnrc_aodvv2 module will need to get the headers and payload message in the right order.
codesnip1

static void gnrc_process_message(gnrc_pktsnip_t *pkt) {
  gnrc_pktsnip_t *udp_snip, *tmp_pkt;
  gnrc_netif_t *netif = NULL;

  DEBUG("AODV---- _send(packet)\n");
  /* write protect first header */
  tmp_pkt = gnrc_pktbuf_start_write(pkt);
  if (tmp_pkt == NULL) {
    DEBUG("AODV: cannot send packet: unable to allocate packet\n");
    gnrc_pktbuf_release(pkt);
    return;
  }
  pkt = tmp_pkt;
  udp_snip = tmp_pkt->next;

  if (pkt->type == GNRC_NETTYPE_NETIF) {
    gnrc_netif_hdr_t *netif_hdr = pkt->data;
    netif = gnrc_netif_hdr_get_netif(pkt->data);
  }
  if (udp_snip->type == GNRC_NETTYPE_IPV6) {
    if (ipv6_addr_is_unspecified(&((ipv6_hdr_t *)udp_snip->data)->dst)) {
      DEBUG("ipv6: destination address is unspecified address (::), " "dropping packet \n");
      gnrc_pktbuf_release_error(pkt, EINVAL);
      return;
    }

    char ipv6_addr[IPV6_ADDR_MAX_STR_LEN];
    ipv6_addr_to_str(ipv6_addr, &((ipv6_hdr_t *)udp_snip->data)->dst, IPV6_ADDR_MAX_STR_LEN);
    DEBUG("AODB TEST -------target address --> %s\n", ipv6_addr);

    // init multicast address: set to to a link-local all nodes multicast address
    //just for testing we are setting up the target address to broadcast address, 
    //to emit a message to all nodes when app layer tried to send a message to some node.
    _v6_addr_mcast = ipv6_addr_all_nodes_link_local;
    ((ipv6_hdr_t *)udp_snip->data)->dst = _v6_addr_mcast;
  }

  // in this place we need to remove the packet from the packet buffer and save
  // it to local storage and inject the rfc5444 packet format tp send a route
  // request as a message
  //tmp_pkt->next->data represent the original message from app layer 
  tmp_pkt = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_UDP);
  if (tmp_pkt != NULL) {
    DEBUG("-------------------------------------DATA: %s",
          (char *)tmp_pkt->next->data);
  }
}
  1. The first available Header is GNRC_NETTYPE_NETIF
    and the way as we can get the packet is something like this:
 if (pkt->type == GNRC_NETTYPE_NETIF) {
    gnrc_netif_hdr_t *netif_hdr = pkt->data;
    gnrc_netif_hdr_print(netif_hdr);
    netif = gnrc_netif_hdr_get_netif(pkt->data);
  }
  1. The second available header is GNRC_NETTYPE_IPV6
    and it can be accessed by
pkt->next->type     //to get the header's type
pkt->next->data    //to get the IPV6 headers information

or just using the next function:

tmp_pkt = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6);
char ipv6_addr[IPV6_ADDR_MAX_STR_LEN];
 ipv6_addr_to_str(ipv6_addr, &((ipv6_hdr_t *)tmp_pkt->next->data)->dst, IPV6_ADDR_MAX_STR_LEN);
  DEBUG("AODB TEST -------target address --> %s\n", ipv6_addr);
  1. the third available header is UDP headers for this case and it can be accessed by
//where tmp_pkt->next->data is representing the original message from app layer
tmp_pkt = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_UDP);
if (tmp_pkt != NULL) {
   DEBUG("-------------------------------------DATA: %s", (char *)tmp_pkt->next->data);
}

Open discussion: Reliability of RREP in some scenarios.

        A                         B                      C        
-----------------         -----------------      -----------------
        |                         |                      |
    +-------+                 +-------+              +-------+    
    |       |                 |       |              |       |    
    +-------+                 +-------+              +-------+    
        |      newpkt[B][A]       |                      |        
        <-------------------------|                      |        
        |                         |                      |        
    +-------+                 +-------+              +-------+    
    |       |                 |       |              |       |    
    +-------+                 +-------+              +-------+    
        |                         |     newpkt[C][A]     |        
        <------------------------------------------------|        
        |                         |                      |        
    +-------+                 +-------+              +-------+    
    |       |                 |       |              |       |    
    +-------+                 +-------+              +-------+    
        |                         |                      |        
-----------------         -----------------      -----------------

In the first scenario a packet from B to A is followed by a packet from C to A.
when packet from C to A, the new RREQ cannot go more than one hope, because node B now know the route to node A and it would need to send RREP in both directions to origin address and to target address, for actual the code is sending RREQ until to reach destination address, this approach overloads the network

Add SeqNoRtr field to RREQ/RREP messages

Description:

RREP and RREQ messages defines an Address TLV named SeqNoRtr which we currently don't implement and is needed to implement Local Route Set correctly:

       +---------------------------+------------------------------+
       | Data                      | Address Block                |
       +---------------------------+------------------------------+
       | OrigPrefix/OrigPrefixLen  | <address> + <prefix-length>  |
       | TargPrefix/TargPrefixLen  | <address> + <prefix-length>  |
       | SeqNoRtr/PrefixLen        | <address> + <prefix-length>  |
       +---------------------------+------------------------------+

See also:

Create structure for AODVv2 module

We need to have a basic structure of aodv module , and all Makefile dependencies, to be able to load it

AODVv2 module creation

  1. Create a folder called aodvv2 inside sys/net/gnrc/
  2. Create a folder called aodvv2 inside sys/include/net/gnrc/
  3. register module inside /RIOT/sys/Makefile with the next command
ifneq (,$(filter aodvv2,$(USEMODULE)))
DIRS += net/gnrc/aodvv2
endif
  1. Create the next files in the right path:
    To have the main entry point for aodv routing protocol
    a. sys/net/gnrc/aodvv2/aodv.c
    b. sys/net/gnrc/aodvv2/aodv.h

    To have a public interface to be used in application layer to init the AODV module
    c. sys/include/net/gnrc/aodvv2/aodvv2.h
    Some useful constant definitions to be used with AODV routing protocol.
    d. sys/include/net/gnrc/aodvv2/types.h

  2. In order to be able to simulate the code we need to change the next file
    RIOT/boards/cc2538dk/dist/board.resc and paste this next code:

path add $CWD
emulation CreateWirelessMedium "wireless"

# The radio is using a range-based medium (with the `Range` set to `11`)
# If not set, the default SimpleMediumFunction will be used (where range is not relevant)
wireless SetRangeWirelessFunction 30

######################### Machine 0 - begin #########################
$name="anode"
$bin[email protected]
i $ORIGIN/radio-firmware.resc
wireless SetPosition radio 0 0 0
showAnalyzer sysbus.uart0
mach clear
start
########################## Machine 0 - end ##########################

######################### Machine 1 - begin #########################
$name="cathode"
$bin[email protected]
i $ORIGIN/radio-firmware.resc
wireless SetPosition radio 10 0 0
showAnalyzer sysbus.uart0
mach clear
start
########################## Machine 1 - end ##########################

######################### Machine 2 - begin #########################
$name="vcc"
$bin[email protected]
i $ORIGIN/radio-firmware.resc
wireless SetPosition radio 20 0 0
showAnalyzer sysbus.uart0
mach clear
start
########################## Machine 2 - end ##########################
  1. Create a new file called radio-firmware.resc inside boards/cc2538dk/dist/ and paste the next code
mach create
using sysbus
machine LoadPlatformDescription @platforms/cpus/cc2538.repl
connector Connect sysbus.radio wireless

machine PyDevFromFile @scripts/pydev/rolling-bit.py 0x400D2004 0x4 True "sysctrl"

$id = `next_value 1`

macro reset
"""
    #set node address. 0x00 0x12 0x4B is TI OUI
    sysbus WriteByte 0x00280028 $id
    sysbus WriteByte 0x0028002C 0x00
    sysbus WriteByte 0x00280030 0xAB
    sysbus WriteByte 0x00280034 0x89
    sysbus WriteByte 0x00280038 0x00
    sysbus WriteByte 0x0028003C 0x4B
    sysbus WriteByte 0x00280040 0x12
    sysbus WriteByte 0x00280044 0x00

    sysbus LoadBinary @http://antmicro.com/projects/renode/cc2538_rom_dump.bin-s_524288-0c196cdc21b5397f82e0ff42b206d1cc4b6d7522 0x0
    sysbus LoadELF $image_file

    #cpu VectorTableOffset `sysbus GetSymbolAddress "vectors"`
"""

runMacro $reset
start

Open discussion: IPv6 address asignment and adding it to Router Client Set

We need a way to assign IPv6 addresses to the computers/mcus/etc that connect over SLIP to the cc1312 (or the MCU that's serving the purpose of an AODVv2 router), also, we need a way to add that address to the Router Client Set so the computer/mcu/etc can be reachable from other AODVv2 routers.

The AODVv2 draft doesn't specify how clients are added nor configured, this is on our own and we need to get a little bit creative into it.

See also

Unable to start communication between nodes.

Unable to start communication between nodes after compiling and flashing the last changes.

How to reproduce:

  • git clone.. and change dir.
  • git checkout dev
  • run make, make flash, make term, etc

The communication appear to be right if we use commands like ping but is unable to run ssh connections or http

Additional context
This was detected while i was trying to connect the monero GUI and the monero daemon.
The connection was done using the commit 720c682fad71c99c6b8b134d889a071ebd8d4041 #116

Changing IEEE 802.15.4 address at flash time

We need to implement a way to change the IEEE 802.15.4 address that resides in the CCFG area of the MCU. This should be done automatically when flashing, this is mostly relevant to Turpial boards

capture packets in the network layer, to be processed inside AODVv2 module

This feature is required to process the packages within the GNRC_AODVV2 module.

when the application layer tries to send a message, it is necessary to capture the packet in the network layer, in order to process and find routes

Describe the solution you'd like

Each layer of the network stack runs in its own thread and each lower layer thread has a higher priority than any upper layer thread. In this regard, the thread of the MAC layer implementation has the highest priority and threads on the application layer have the lowest priority. The communication between threads is handled by the kernel's @ref core_msg functionality and by the @ref net_gnrc_netapi. Most of the times IPC will take place between threads of neighboring layers for packets that traverse the network stack up or down.

Due to the design of @ref net_gnrc "GNRC" and the nature of inter-process communication, it is crucial for a new module that introduces a new thread to follow a certain programming construct if it desires to interact with other threads without blocking the system: Utilizing an event loop.
Hence, a thread for @ref net_gnrc "GNRC" will usually consist of four basic steps.

  1. Initialize a message queue (note that its size must be a power of twosee @ref msg_init_queue())
  2. register for a @ref net_gnrc_nettype
  3. wait for a message
  4. react appropriately to a message and return to 3.

to capture packets that go to the ipv6 module we must subscribe to network messages through the IPC (intercommunication process), which allows to capture messages from some thread (app layer for this case).

  1. To be able to listen incoming packets in UDP module we need to create a thread to handle _event_loop
if (_pid == KERNEL_PID_UNDEF) {
    /* start thread */
    _pid = thread_create(_stack, sizeof(_stack), GNRC_UDP_PRIO,
                         THREAD_CREATE_STACKTEST, _event_loop, NULL, "IPV6");
  }

2.subscribe to specific messages

 void *_event_loop(void *arg)
 {
  static msg_t _msg_q[Q_SZ];
  (void)arg;
   msg_init_queue(_msg_q, Q_SZ);
   gnrc_netreg_entry me_reg = GNRC_NETREG_ENTRY_INIT_PID(
   GNRC_NETREG_DEMUX_CTX_ALL,
   sched_active_pid);
  gnrc_netreg_register(GNRC_NETTYPE_UDP, &me_reg);
  while (1) {
         msg_receive(&msg);
         switch (msg.type) {
             case TYPE1:
                 callback1();
                  break;
             case TYPE2:
                  callback2();
                  break;

              ...
          }
      }
      return NULL;
  }

To have the AODVv2 module waiting for incoming and outgoing UDP packets, we need to use something like this:

static void *_event_loop(void *args)
{

    msg_t msg, reply, msg_q[CONFIG_GNRC_UDP_MSG_QUEUE_SIZE];
    gnrc_netreg_entry_t me_reg = GNRC_NETREG_ENTRY_INIT_PID(GNRC_NETREG_DEMUX_CTX_ALL,
                                                            sched_active_pid);

    (void)args;
    msg_init_queue(msg_q, CONFIG_GNRC_UDP_MSG_QUEUE_SIZE);

    /* start event loop */
    while (1) {
    msg_receive(&msg);
    switch (msg.type) {
    case GNRC_NETAPI_MSG_TYPE_RCV:
      _receive(msg.content.ptr);
      break;
    case GNRC_NETAPI_MSG_TYPE_SND:
      DEBUG("*****AODV**** CAPTURING MESSAGE FROM APPLICATION");
      gnrc_process_message(msg.content.ptr); //to capture the headers and edit some of them
      break;
    case GNRC_NETAPI_MSG_TYPE_SET:
    case GNRC_NETAPI_MSG_TYPE_GET:
      msg_reply(&msg, &reply);
      break;
    default:
      DEBUG("udp: received unidentified message\n");
      break;
    }
  }

    return NULL;
}

To be able to test the GNRC_AODVV2_MODULE, was needed to remove the auto init functionality for UDP protocol, in order to handle the packet directly in gnrc_aodvv2 module

edit the file **sys/auto_init/auto_init.c

#ifdef MODULE_GNRC_UDP
    //DEBUG("Auto init UDP module.\n");
    //gnrc_udp_init();
#endif

it could be great to be able to capture incoming packets to ipv6 module, but in my begin was not possible to get the packet inside gnrc_aodvv2 module first than the ipv6 module itself

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.