Skip to content

Commit

Permalink
Merge branch 'crownstone:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Anne van Rossum committed Feb 6, 2023
2 parents 5f20f9b + b3d6e19 commit 9bf0353
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 56 deletions.
4 changes: 2 additions & 2 deletions docs/development_environment/CODE_STYLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ Investigate the `source/.clang-format` (<https://github.com/crownstone/bluenet/b

Support for autoformatting in IDEs is widespread.
E.g.:
- This [Eclipse plugin](https://marketplace.eclipse.org/content/cppstyle) enables formatting files on save or selected pieces of code using `ctrl+shift+f`.
- Commandline tools such as `python3 -m pip install clang-format` are also available.
- For Eclipse, there is a cppstyle plugin that enables formatting files on save or selected pieces of code using `ctrl+shift+f`.
- Command-line tools such as `python3 -m pip install clang-format` are also available.

Always run the formatter before committing.

Expand Down
14 changes: 7 additions & 7 deletions doxygen.config
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ PROJECT_NAME = "Bluenet"
# could be handy for archiving the generated documentation or if some version
# control system is used.

PROJECT_NUMBER = 5.4.0
PROJECT_NUMBER = 5.7.0

# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short.

PROJECT_BRIEF = "Bluenet, the firmware for the Crownstone power outlet"
PROJECT_BRIEF = "Bluenet, firmware for nRF52 smart home devices"

# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55
Expand Down Expand Up @@ -409,25 +409,25 @@ LOOKUP_CACHE_SIZE = 0
# normally produced when WARNINGS is set to YES.
# The default value is: NO.

EXTRACT_ALL = NO
EXTRACT_ALL = YES

# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
# The default value is: NO.

EXTRACT_PRIVATE = NO
EXTRACT_PRIVATE = YES

# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
# The default value is: NO.

EXTRACT_PACKAGE = NO
EXTRACT_PACKAGE = YES

# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
# included in the documentation.
# The default value is: NO.

EXTRACT_STATIC = NO
EXTRACT_STATIC = YES

# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
# locally in source files will be included in the documentation. If set to NO,
Expand All @@ -443,7 +443,7 @@ EXTRACT_LOCAL_CLASSES = YES
# included.
# The default value is: NO.

EXTRACT_LOCAL_METHODS = NO
EXTRACT_LOCAL_METHODS = YES

# If this flag is set to YES, the members of anonymous namespaces will be
# extracted and appear in the documentation as a namespace called
Expand Down
2 changes: 1 addition & 1 deletion source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ add_custom_target(check

add_custom_target(generate_documentation
COMMAND ${CMAKE_COMMAND} -E echo "Run doxygen from ${CMAKE_SOURCE_DIR}"
COMMAND cd ${WORKSPACE_DIR} && doxygen source/doxygen.config
COMMAND cd ${WORKSPACE_DIR} && doxygen doxygen.config
COMMENT "Run documentation generator"
)

Expand Down
116 changes: 89 additions & 27 deletions source/include/localisation/cs_MeshTopology.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,57 @@
#include <localisation/cs_MeshTopologyResearch.h>
#endif

class MeshTopology : EventListener {
/**
* Keeps track of the rssi distance of this crownstone to
* the crownstones in its direct environment.
*
* Several related commands are available over UART.
*/
class MeshTopology: EventListener {
/**
* Set this to true to make every crownstone in the sphere to send a noop message
* on every tick, and make every crownstone respond with a neighbor message with that rssi.
*
* (This gives the highest possible frequency trip wire)
*/
static constexpr bool TripwireResearch = false;

public:
/**
* Initializes the class:
* - Reads State.
* - Allocates buffer.
* - Starts listening for events.
*/
cs_ret_code_t init();

/**
* Commands handled:
* - CMD_MESH_TOPO_GET_RSSI
* - CMD_MESH_TOPO_RESET
* - CMD_MESH_TOPO_GET_MAC
*
* Internal usage:
* - EVT_RECV_MESH_MSG
* - EVT_TICK
*/
void handleEvent(event_t &evt);

/**
* Get the MAC address of a neighbouring crownstone.
*
* @param[in] stoneId The stone ID of the crownstone.
*
* @return ERR_WAIT_FOR_SUCCESS When the MAC address is requested. Wait for EVT_MESH_TOPO_MAC_RESULT.
* However, there will be no event if it times out.
* @return ERR_NOT_FOUND When the stone is not a known neighbour.
*/
cs_ret_code_t getMacAddress(stone_id_t stoneId);

// --------------------------------
// ---------- parameters ----------
// --------------------------------

/**
* Maximum number of neighbours in the list.
*/
Expand Down Expand Up @@ -47,24 +96,6 @@ class MeshTopology : EventListener {
*/
static constexpr uint16_t FAST_INTERVAL_TIMEOUT_SECONDS = 5 * 60;

/**
* Initializes the class:
* - Reads State.
* - Allocates buffer.
* - Starts listening for events.
*/
cs_ret_code_t init();

/**
* Get the MAC address of a neighbouring crownstone.
*
* @param[in] stoneId The stone ID of the crownstone.
*
* @return ERR_WAIT_FOR_SUCCESS When the MAC address is requested. Wait for EVT_MESH_TOPO_MAC_RESULT.
* However, there will be no event if it times out.
* @return ERR_NOT_FOUND When the stone is not a known neighbour.
*/
cs_ret_code_t getMacAddress(stone_id_t stoneId);

private:
static constexpr uint8_t INDEX_NOT_FOUND = 0xFF;
Expand All @@ -79,6 +110,10 @@ class MeshTopology : EventListener {
uint8_t lastSeenSecondsAgo;
};

// ---------------------------------------
// ---------- runtime variables ----------
// ---------------------------------------

/**
* Stone ID of this crownstone, read on init.
*/
Expand Down Expand Up @@ -119,6 +154,10 @@ class MeshTopology : EventListener {
*/
uint8_t _msgCount = 0;

// -------------------------------------
// ---------- private methods ----------
// -------------------------------------

/**
* Resets the stored topology.
*/
Expand All @@ -134,6 +173,11 @@ class MeshTopology : EventListener {
*/
void updateNeighbour(neighbour_node_t& node, stone_id_t id, int8_t rssi, uint8_t channel);

/**
* sets the three rssi values to RSSI_INIT
*/
void clearNeighbourRssi(neighbour_node_t& node);

/**
* Find a neighbour in the list.
*/
Expand All @@ -154,30 +198,48 @@ class MeshTopology : EventListener {
*/
void sendNext();

/**
* Sends a neighbour message for the given node over the mesh.
* No checks are executed.
*
* Returns the message struct for convenience.
*/
cs_mesh_model_msg_neighbour_rssi_t sendNeighbourMessageOverMesh(neighbour_node_t& node);

/**
* Sends the RSSI to a neighbour over UART.
*/
void sendRssiToUart(stone_id_t reveiverId, cs_mesh_model_msg_neighbour_rssi_t& packet);

// Event handlers
// ------------------------------------
// ---------- event handlers ----------
// ------------------------------------

void onNeighbourRssi(stone_id_t id, cs_mesh_model_msg_neighbour_rssi_t& packet);

cs_ret_code_t onStoneMacMsg(MeshMsgEvent& meshMsg);

/**
* Handles mesh messages:
* - CS_MESH_MODEL_TYPE_NEIGHBOUR_RSSI
* - CS_MESH_MODEL_TYPE_STONE_MAC
*
* Also calls `add` if .hops == 0, regarless of the packet type.
*/
void onMeshMsg(MeshMsgEvent& packet, cs_result_t& result);
void onTickSecond();

/**
* Print all neighbours.
* neighbors are removed from the list when their individual countdown expires.
* See TIMEOUT_SECONDS.
*/
void print();
void onTickSecond();

public:
/**
* Internal usage.
* Prints all neighbours.
*/
void handleEvent(event_t& evt);
void print();

#if BUILD_MESH_TOPOLOGY_RESEARCH == 1
private:
MeshTopologyResearch _research;
#endif
};
77 changes: 58 additions & 19 deletions source/src/localisation/cs_MeshTopology.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,11 @@ void MeshTopology::add(stone_id_t id, int8_t rssi, uint8_t channel) {
if (id == 0 || id == _myId) {
return;
}
// auto compressedRssiData = compressRssi(rssi,channel);

uint8_t index = find(id);
if (index == INDEX_NOT_FOUND) {
if (_neighbourCount < MAX_NEIGHBOURS) {
// Init RSSI
_neighbours[_neighbourCount].rssiChannel37 = RSSI_INIT;
_neighbours[_neighbourCount].rssiChannel38 = RSSI_INIT;
_neighbours[_neighbourCount].rssiChannel39 = RSSI_INIT;
clearNeighbourRssi(_neighbours[_neighbourCount]);
updateNeighbour(_neighbours[_neighbourCount], id, rssi, channel);
_neighbourCount++;
}
Expand All @@ -107,7 +103,6 @@ void MeshTopology::add(stone_id_t id, int8_t rssi, uint8_t channel) {
}

void MeshTopology::updateNeighbour(neighbour_node_t& node, stone_id_t id, int8_t rssi, uint8_t channel) {
// TODO: averaging.
LOGMeshTopologyDebug("updateNeighbour id=%u rssi=%i channel=%u", id, rssi, channel);
node.id = id;
switch (channel) {
Expand All @@ -127,6 +122,13 @@ void MeshTopology::updateNeighbour(neighbour_node_t& node, stone_id_t id, int8_t
node.lastSeenSecondsAgo = 0;
}


void MeshTopology::clearNeighbourRssi(neighbour_node_t& node) {
node.rssiChannel37 = RSSI_INIT;
node.rssiChannel38 = RSSI_INIT;
node.rssiChannel39 = RSSI_INIT;
}

uint8_t MeshTopology::find(stone_id_t id) {
for (uint8_t index = 0; index < _neighbourCount; ++index) {
if (_neighbours[index].id == id) {
Expand Down Expand Up @@ -198,22 +200,15 @@ void MeshTopology::sendNext() {
node.id,
node.lastSeenSecondsAgo);

cs_mesh_model_msg_neighbour_rssi_t meshPayload = {
.type = 0,
.neighbourId = node.id,
.rssiChannel37 = node.rssiChannel37,
.rssiChannel38 = node.rssiChannel38,
.rssiChannel39 = node.rssiChannel39,
.lastSeenSecondsAgo = node.lastSeenSecondsAgo,
.counter = _msgCount++};
cs_mesh_model_msg_neighbour_rssi_t meshPayload = sendNeighbourMessageOverMesh(node);

TYPIFY(CMD_SEND_MESH_MSG) meshMsg;
meshMsg.type = CS_MESH_MODEL_TYPE_NEIGHBOUR_RSSI;
meshMsg.reliability = CS_MESH_RELIABILITY_LOWEST;
meshMsg.urgency = CS_MESH_URGENCY_LOW;
meshMsg.type = CS_MESH_MODEL_TYPE_NEIGHBOUR_RSSI;
meshMsg.reliability = CS_MESH_RELIABILITY_LOWEST;
meshMsg.urgency = CS_MESH_URGENCY_LOW;
meshMsg.flags.flags.doNotRelay = false;
meshMsg.payload = reinterpret_cast<uint8_t*>(&meshPayload);
meshMsg.size = sizeof(meshPayload);
meshMsg.payload = reinterpret_cast<uint8_t*>(&meshPayload);
meshMsg.size = sizeof(meshPayload);

event_t event(CS_TYPE::CMD_SEND_MESH_MSG, &meshMsg, sizeof(meshMsg));
event.dispatch();
Expand All @@ -225,6 +220,32 @@ void MeshTopology::sendNext() {
_nextSendIndex++;
}


cs_mesh_model_msg_neighbour_rssi_t MeshTopology::sendNeighbourMessageOverMesh(neighbour_node_t& node) {
cs_mesh_model_msg_neighbour_rssi_t meshPayload = {
.type = 0,
.neighbourId = node.id,
.rssiChannel37 = node.rssiChannel37,
.rssiChannel38 = node.rssiChannel38,
.rssiChannel39 = node.rssiChannel39,
.lastSeenSecondsAgo = node.lastSeenSecondsAgo,
.counter = _msgCount++
};

TYPIFY(CMD_SEND_MESH_MSG) meshMsg;
meshMsg.type = CS_MESH_MODEL_TYPE_NEIGHBOUR_RSSI;
meshMsg.reliability = CS_MESH_RELIABILITY_LOWEST;
meshMsg.urgency = CS_MESH_URGENCY_LOW;
meshMsg.flags.flags.doNotRelay = false;
meshMsg.payload = reinterpret_cast<uint8_t*>(&meshPayload);
meshMsg.size = sizeof(meshPayload);

event_t event(CS_TYPE::CMD_SEND_MESH_MSG, &meshMsg, sizeof(meshMsg));
event.dispatch();

return meshPayload;
}

void MeshTopology::sendRssiToUart(stone_id_t receiverId, cs_mesh_model_msg_neighbour_rssi_t& packet) {
LOGMeshTopologyDebug("sendRssiToUart receiverId=%u senderId=%u", receiverId, packet.neighbourId);
mesh_topology_neighbour_rssi_uart_t uartMsg = {
Expand Down Expand Up @@ -310,6 +331,18 @@ void MeshTopology::onMeshMsg(MeshMsgEvent& packet, cs_result_t& result) {
if (packet.type == CS_MESH_MODEL_TYPE_STONE_MAC) {
result.returnCode = onStoneMacMsg(packet);
}

if constexpr (TripwireResearch) {
LOGMeshTopologyVerbose("forward noop as neighbour mesh msg for tripwire");
if(packet.type == CS_MESH_MODEL_TYPE_CMD_NOOP) {
neighbour_node_t node = {};
clearNeighbourRssi(node);
updateNeighbour(node, packet.srcStoneId, packet.rssi, packet.channel);
sendNeighbourMessageOverMesh(node);
}
}


add(packet.srcStoneId, packet.rssi, packet.channel);
}

Expand Down Expand Up @@ -394,6 +427,12 @@ void MeshTopology::handleEvent(event_t& evt) {
if (*packet % (1000 / TICK_INTERVAL_MS) == 0) {
onTickSecond();
}

if constexpr(TripwireResearch) {
LOGMeshTopologyVerbose("send a noop for tripwire");
sendNoop();
}

break;
}
case CS_TYPE::CMD_MESH_TOPO_GET_MAC: {
Expand Down

0 comments on commit 9bf0353

Please sign in to comment.