btcven / radio-firmware Goto Github PK
View Code? Open in Web Editor NEWThe firmware for the radio module
Home Page: https://locha.io
License: Apache License 2.0
The firmware for the radio module
Home Page: https://locha.io
License: Apache License 2.0
ToDo
Implement the send/TX functionality on the on going driver.
Currently propietary mode doens't allow to set the PAN ID on the RF Core driver level. We need to workaround this manually.
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.
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
See also
This feature is necessary to communicate both MCUs
SLIP - Serial Line Internet Protocol -
CSLIP - Compressed SLIP -
KISS - keep it simple, stupid -
Modbus RTU
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;
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).
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.
Currently the RGB and Buttons for the final Turpial board are to be defined. We need to define:
Functionality also for them is needed to be defined though.
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.
ToDo
RIOT has support for the CC1312 LaunchPad board, but it doesn't has a radio driver for that MCU.
Currently it's being worked on, here is the progress: btcven/RIOT#5.
Implement receive/RX functonality on the CC1312 radio driver.
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
draw a flowchart describing the operation of the AODVV2 protocol
The AODVv2 protocol's operations include:
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).
The radio subsystem has limited resources. We must find the right balance by assigning some constants used in the routing protocol, MAX_HOPS
, MAX_ROUTES
, etc.
Currently RIOT doesn't has native support for mobility networks, currently there is an ongoing work for getting the AODVv2 routing protocol working.
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:
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.
After getting the package inside gnrc_aodvv2 module from the application layer, we need the next:
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
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);
}
}
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);
}
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);
//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);
}
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
https://locha.io/ at the repository description.
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:
Proposed tags: #mesh #network #radio #mcu #locha-mesh
We need to have a basic structure of aodv module , and all Makefile dependencies, to be able to load it
ifneq (,$(filter aodvv2,$(USEMODULE)))
DIRS += net/gnrc/aodvv2
endif
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
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 ##########################
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
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 after compiling and flashing the last changes.
git clone..
and change dir.git checkout dev
make
, make flash
, make term
, etcThe 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
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
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.
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).
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
We need to ACK received packets, and also implement a re-send logic for packets not ACKed.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.