Skip to content

Commit

Permalink
[communication] Reimplement AMNB protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
salkinium committed Jul 31, 2020
1 parent 026f82d commit 8820d6b
Show file tree
Hide file tree
Showing 22 changed files with 2,584 additions and 1,822 deletions.
132 changes: 132 additions & 0 deletions examples/nucleo_g071rb/amnb/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Copyright (c) 2019, Niklas Hauser
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include <modm/board.hpp>
#include <modm/communication/amnb.hpp>

using namespace Board;
using namespace std::chrono_literals;
using namespace modm::amnb;
// ----------------------------------------------------------------------------

const Listener listeners[] =
{
{1, +[](uint8_t sender, const uint32_t& data)
{
MODM_LOG_INFO << "Node2 and Node3 received Broadcast 1 from '" << sender;
MODM_LOG_INFO << "': " << data << modm::endl;
}
},
{2, [](uint8_t sender)
{
MODM_LOG_INFO << "Node2 and Node3 received Broadcast 2 from '" << sender << "'" << modm::endl;
}
},
};
const Action actions[] =
{
{1, +[]() -> Response
{
static uint8_t counter{0};
MODM_LOG_INFO << "Node1 and Node3 received Action 1" << modm::endl;
return counter++;
}
},
{2, +[](const uint32_t& data) -> Response
{
static uint8_t counter{0};
MODM_LOG_INFO << "Node1 and Node3 received Action 2 with argument: " << data << modm::endl;
return ErrorResponse(counter++);
}
},
};

// Two nodes on the same device on different UARTs of course!
DeviceWrapper<Usart1> device1;
DeviceWrapper<Usart3> device2;
DeviceWrapper<Usart4> device3;
Node node1(device1, 1, actions);
Node node2(device2, 2, listeners);
Node node3(device3, 3, actions, listeners);

// You need to connect D1 with D15 and with A0
using PinNode1 = GpioC4; // D1
using PinNode2 = GpioB8; // D15
using PinNode3 = GpioA0; // A0

// ----------------------------------------------------------------------------
int
main()
{
Board::initialize();
LedD13::setOutput();

Usart1::connect<PinNode1::Tx>();
Usart1::initialize<SystemClock, 115200>();
// Use Single-Wire Half-Duplex Mode
PinNode1::configure(Gpio::OutputType::OpenDrain);
PinNode1::configure(Gpio::InputType::PullUp);
USART1->CR1 &= ~USART_CR1_UE;
USART1->CR3 = USART_CR3_HDSEL;
USART1->CR1 |= USART_CR1_UE;

Usart3::connect<PinNode2::Tx>();
Usart3::initialize<SystemClock, 115200>();
// Use Single-Wire Half-Duplex Mode
PinNode2::configure(Gpio::OutputType::OpenDrain);
PinNode2::configure(Gpio::InputType::PullUp);
USART3->CR1 &= ~USART_CR1_UE;
USART3->CR3 = USART_CR3_HDSEL;
USART3->CR1 |= USART_CR1_UE;

Usart4::connect<PinNode3::Tx>();
Usart4::initialize<SystemClock, 115200>();
// Use Single-Wire Half-Duplex Mode
PinNode3::configure(Gpio::OutputType::OpenDrain);
PinNode3::configure(Gpio::InputType::PullUp);
USART4->CR1 &= ~USART_CR1_UE;
USART4->CR3 = USART_CR3_HDSEL;
USART4->CR1 |= USART_CR1_UE;


modm::ShortPeriodicTimer tmr{1s};
uint32_t counter{0};

while (true)
{
node1.update();
node2.update();
node3.update();

if (tmr.execute())
{
LedD13::toggle();
node1.broadcast(1, counter++);
node3.broadcast(2);

{
modm::ResumableResult< Result<uint8_t> > res{0};
while((res = node2.request<uint8_t>(1, 1)).getState() == modm::rf::Running)
{ node1.update(); node2.update(); node3.update(); }
MODM_LOG_INFO << "Node1 responded with: " << res.getResult().error();
MODM_LOG_INFO << " " << *res.getResult().result() << modm::endl;
}
{
modm::ResumableResult< Result<uint8_t, uint8_t> > res{0};
while((res = node1.request<uint8_t, uint8_t>(3, 2, counter)).getState() == modm::rf::Running)
{ node1.update(); node2.update(); node3.update(); }
MODM_LOG_INFO << "Node3 responded with: " << res.getResult().error();
MODM_LOG_INFO << " " << *res.getResult().resultError() << modm::endl;
}
}
}

return 0;
}
19 changes: 19 additions & 0 deletions examples/nucleo_g071rb/amnb/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<library>
<extends>modm:nucleo-g071rb</extends>
<options>
<option name="modm:build:build.path">../../../build/nucleo_g071rb/amnb</option>
<option name="modm:platform:uart:1:buffer.tx">1</option>
<option name="modm:platform:uart:1:buffer.rx">32</option>
<option name="modm:platform:uart:3:buffer.tx">1</option>
<option name="modm:platform:uart:3:buffer.rx">32</option>
<option name="modm:communication:amnb:with_heap">False</option>
</options>
<modules>
<module>modm:platform:gpio</module>
<module>modm:communication:amnb</module>
<module>modm:platform:uart:1</module>
<module>modm:platform:uart:3</module>
<module>modm:platform:uart:4</module>
<module>modm:build:scons</module>
</modules>
</library>
89 changes: 1 addition & 88 deletions src/modm/communication/amnb.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2010-2011, Fabian Greif
* Copyright (c) 2011-2015, Niklas Hauser
* Copyright (c) 2020, Niklas Hauser
*
* This file is part of the modm project.
*
Expand All @@ -10,90 +9,4 @@
*/
// ----------------------------------------------------------------------------

/**
* @ingroup modm_communication
* @defgroup amnb Asynchronous Multi-Node Bus (AMNB)
*
* @section amnb_intro Introduction
*
* The AMNB (**A**synchronous **M**ulti-**N**ode **B**us) is a
* multi-master bus system, using p-persitent CSMA to send messages.
*
* One bus can be populated with up to 64 nodes. The nodes can be queried for
* data and they will respond like an SAB Slave, and can query data from other
* nodes like an SAB Master, or they can just broadcast a message.
* Each node can listen to all the responses and broadcasts and store that
* information for its purpose.
*
* Action callbacks to query requests can be defined as well as universal
* callbacks to any transmitted messaged (Listener callbacks).
* As an optional advanced feature, error handling callbacks can also be defined,
* which fire if messages have not been able to be sent, or requests timed out
* or misbehaved in other manners, or other nodes query unavailable information.
*
* @section amnb_protocol Protocol
*
* Features:
* - Maximum payload length is 32 byte.
* - CRC8 (1-Wire)
*
* @subsection structure Structure
*
@verbatim
+------+--------+--------+---------+--------------+-----+
| SYNC | LENGTH | HEADER | COMMAND | ... DATA ... | CRC |
+------+--------+--------+---------+--------------+-----+
@endverbatim
*
* - `SYNC` - Synchronization byte (always 0x54)
* - `LENGTH` - Length of the payload (without header, command and CRC byte)
* - `HEADER` - Address of the slave and two flag bits
* - `COMMAND` - Command code
* - `DATA` - Up to 32 byte of payload
* - `CRC` - CRC-8 checksum (iButton)
*
* @subsubsection header Header
*
@verbatim
7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+
| Flags | ADDRESS |
+---+---+---+---+---+---+---+---+
Flags | Meaning
--------+---------
0 0 | data broadcast by a node
0 1 | data request by a node
1 0 | negative response from the node (NACK)
1 1 | positive response from the node (ACK)
@endverbatim
*
* When transmitting, the *second bit* determines, whether or not to expect an
* answer from the addressed node.
* To just send information without any need for acknowledgment, use a broadcast.
* When a node is responding, the *second bit* has to following meaning:
*
* - `true` - Message is an positive response and may contain a payload
* - `false` - Message signals an error condition and carries only one byte of
* payload. This byte is an error code.
*
* @section amnb_electric Electrical characteristics
*
* Between different boards CAN transceivers are used. Compared to RS485 the
* CAN transceivers have the advantage to work without a separate direction input.
* You can just connected the transceiver directly to the UART of your
* microcontroller.
* These are identical to the SAB CAN electrical characteristics.
* You have to use the CAN transceivers, otherwise it cannot be determined, if
* the bus is busy or available for transmission.
*
* @author Fabian Greif
* @author Niklas Hauser
*/

#ifndef MODM_AMNB_HPP
#define MODM_AMNB_HPP

#include "amnb/node.hpp"

#endif // MODM_AMNB_HPP
107 changes: 0 additions & 107 deletions src/modm/communication/amnb/constants.hpp

This file was deleted.

Loading

0 comments on commit 8820d6b

Please sign in to comment.