Skip to content

Commit

Permalink
[amnb] WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
salkinium committed Jun 1, 2020
1 parent 684372f commit 6d896e7
Show file tree
Hide file tree
Showing 23 changed files with 2,311 additions and 1,862 deletions.
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.

173 changes: 173 additions & 0 deletions src/modm/communication/amnb/handler.hpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*
* Copyright (c) 2020, 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/.
*/
// ----------------------------------------------------------------------------

#pragma once

#include "message.hpp"
#include <modm/processing.hpp>

namespace modm::amnb
{

/// @ingroup modm_communication_amnb
enum class Error : uint8_t
{
Ok = 0,

RequestTimeout,
WrongArgumentSize,
NoAction,
};

/// @ingroup modm_communication_amnb
struct Listener
{
inline
Listener(int command, void(*listener)(uint8_t))
: command(command), callback((void*)listener),
redirect([](const Message &msg, void *cb)
{ reinterpret_cast<decltype(listener)>(cb)(msg.address()); })
{}

template<typename T>
Listener(int command, void(*listener)(uint8_t, const T&))
: command(command), callback((void*)listener),
redirect([](const Message &msg, void* cb)
{
if (msg.length() == sizeof(T))
reinterpret_cast<decltype(listener)>(cb)(msg.address(), *msg.get<T>());
})
{}

protected:
const uint8_t command;
void *const callback;
void (*const redirect)(const Message &msg, void *cb);

inline
void call(const Message &msg) const
{
redirect(msg, callback);
}

template< class, size_t > friend class Node;
};

/// @ingroup modm_communication_amnb
struct Response
{
inline
Response()
: msg(0, 0, 0, Type::Response) {}

template<typename T>
Response(T retval)
: msg(0, 0, sizeof(T), Type::Response)
{ *msg.get<T>() = retval; }

Message msg;
};

/// @ingroup modm_communication_amnb
template<typename T>
inline Response
ErrorResponse(T error)
{
Response res(error);
res.msg.setType(Type::UserError);
return res;
}

/// @ingroup modm_communication_amnb
struct Action
{
inline
Action(int command, Response(*action)())
: command(command), callback((void*)action),
redirect([](const Message &msg, void *cb) -> Message
{
if (msg.length() == 0)
return reinterpret_cast<decltype(action)>(cb)().msg;
return Response(Error::WrongArgumentSize).msg;
})
{}

template<typename T>
Action(int command, Response(*action)(const T&))
: command(command), callback((void*)action),
redirect([](const Message &msg, void* cb) -> Message
{
if (msg.length() == sizeof(T))
return reinterpret_cast<decltype(action)>(cb)(*msg.get<T>()).msg;
return Response(Error::WrongArgumentSize).msg;
})
{}

inline
Action(int command, void(*action)())
: command(command), callback((void*)action),
redirect([](const Message &msg, void *cb) -> Message
{
if (msg.length() == 0) {
reinterpret_cast<decltype(action)>(cb)();
return Response().msg;
}
return Response(Error::WrongArgumentSize).msg;
})
{}

template<typename T>
Action(int command, void(*action)(const T&))
: command(command), callback((void*)action),
redirect([](const Message &msg, void* cb) -> Message
{
if (msg.length() == sizeof(T)) {
reinterpret_cast<decltype(action)>(cb)(*msg.get<T>());
return Response().msg;
}
return Response(Error::WrongArgumentSize).msg;
})
{}

protected:
const uint8_t command;
void *const callback;
Message (*const redirect)(const Message &msg, void *cb);

inline
Message call(const Message &msg) const
{
return redirect(msg, callback);
}

template< class, size_t > friend class Node;
};

}

%% if with_io
#include <modm/io/iostream.hpp>

inline modm::IOStream&
operator << (modm::IOStream& s, const modm::amnb::Error error)
{
using namespace modm::amnb;
switch(error)
{
case Error::Ok: s << "Ok"; break;
case Error::NoAction: s << "NoAction"; break;
case Error::RequestTimeout: s << "RequestTimeout"; break;
case Error::WrongArgumentSize: s << "WrongArgumentSize"; break;
}
return s;
}
%% endif

Loading

0 comments on commit 6d896e7

Please sign in to comment.