|
1 | 1 | #include "MyMesh.h" |
| 2 | +#include <algorithm> |
2 | 3 |
|
3 | 4 | /* ------------------------------ Config -------------------------------- */ |
4 | 5 |
|
|
46 | 47 | #define REQ_TYPE_KEEP_ALIVE 0x02 |
47 | 48 | #define REQ_TYPE_GET_TELEMETRY_DATA 0x03 |
48 | 49 | #define REQ_TYPE_GET_ACCESS_LIST 0x05 |
| 50 | +#define REQ_TYPE_GET_NEIGHBOURS 0x06 |
49 | 51 |
|
50 | 52 | #define RESP_SERVER_LOGIN_OK 0 // response to ANON_REQ |
51 | 53 |
|
@@ -187,6 +189,98 @@ int MyMesh::handleRequest(ClientInfo *sender, uint32_t sender_timestamp, uint8_t |
187 | 189 | return ofs; |
188 | 190 | } |
189 | 191 | } |
| 192 | + if (payload[0] == REQ_TYPE_GET_NEIGHBOURS) { |
| 193 | + uint8_t request_version = payload[1]; |
| 194 | + if (request_version == 0) { |
| 195 | + |
| 196 | + // reply data offset (after response sender_timestamp/tag) |
| 197 | + int reply_offset = 4; |
| 198 | + |
| 199 | + // get request params |
| 200 | + uint8_t count = payload[2]; // how many neighbours to fetch |
| 201 | + uint8_t offset = payload[3]; // offset from start of neighbours list |
| 202 | + uint8_t order_by = payload[4]; // how to order neighbours. 0=newest_to_oldest, 1=oldest_to_newest, 2=strongest_to_weakest, 3=weakest_to_strongest |
| 203 | + uint8_t pubkey_prefix_length = payload[5]; // how many bytes of neighbour pub key we want |
| 204 | + // we also send a 4 byte random blob in payload[6...9] to help packet uniqueness |
| 205 | + |
| 206 | + MESH_DEBUG_PRINTLN("REQ_TYPE_GET_NEIGHBOURS count=%d, offset=%d, order_by=%d, pubkey_prefix_length=%d", count, offset, order_by, pubkey_prefix_length); |
| 207 | + |
| 208 | + // clamp pub key prefix length to max pub key length |
| 209 | + if(pubkey_prefix_length > PUB_KEY_SIZE){ |
| 210 | + pubkey_prefix_length = PUB_KEY_SIZE; |
| 211 | + MESH_DEBUG_PRINTLN("REQ_TYPE_GET_NEIGHBOURS invalid pubkey_prefix_length=%d clamping to %d", pubkey_prefix_length, PUB_KEY_SIZE); |
| 212 | + } |
| 213 | + |
| 214 | + // create copy of neighbours list, skipping empty entries so we can sort it separately from main list |
| 215 | + int16_t neighbours_count = 0; |
| 216 | + NeighbourInfo sorted_neighbours[MAX_NEIGHBOURS]; |
| 217 | + for (int i = 0; i < MAX_NEIGHBOURS; i++) { |
| 218 | + auto neighbour = &neighbours[i]; |
| 219 | + if (neighbour->heard_timestamp > 0) { |
| 220 | + sorted_neighbours[neighbours_count] = *neighbour; |
| 221 | + neighbours_count++; |
| 222 | + } |
| 223 | + } |
| 224 | + |
| 225 | + // sort neighbours based on order |
| 226 | + if (order_by == 0) { |
| 227 | + // sort by newest to oldest |
| 228 | + MESH_DEBUG_PRINTLN("REQ_TYPE_GET_NEIGHBOURS sorting newest to oldest"); |
| 229 | + std::sort(sorted_neighbours, sorted_neighbours + neighbours_count, [](const NeighbourInfo &a, const NeighbourInfo &b) { |
| 230 | + return a.heard_timestamp > b.heard_timestamp; // desc |
| 231 | + }); |
| 232 | + } else if (order_by == 1) { |
| 233 | + // sort by oldest to newest |
| 234 | + MESH_DEBUG_PRINTLN("REQ_TYPE_GET_NEIGHBOURS sorting oldest to newest"); |
| 235 | + std::sort(sorted_neighbours, sorted_neighbours + neighbours_count, [](const NeighbourInfo &a, const NeighbourInfo &b) { |
| 236 | + return a.heard_timestamp < b.heard_timestamp; // asc |
| 237 | + }); |
| 238 | + } else if (order_by == 2) { |
| 239 | + // sort by strongest to weakest |
| 240 | + MESH_DEBUG_PRINTLN("REQ_TYPE_GET_NEIGHBOURS sorting strongest to weakest"); |
| 241 | + std::sort(sorted_neighbours, sorted_neighbours + neighbours_count, [](const NeighbourInfo &a, const NeighbourInfo &b) { |
| 242 | + return a.snr > b.snr; // desc |
| 243 | + }); |
| 244 | + } else if (order_by == 3) { |
| 245 | + // sort by weakest to strongest |
| 246 | + MESH_DEBUG_PRINTLN("REQ_TYPE_GET_NEIGHBOURS sorting weakest to strongest"); |
| 247 | + std::sort(sorted_neighbours, sorted_neighbours + neighbours_count, [](const NeighbourInfo &a, const NeighbourInfo &b) { |
| 248 | + return a.snr < b.snr; // asc |
| 249 | + }); |
| 250 | + } |
| 251 | + |
| 252 | + // build results buffer |
| 253 | + int results_count = 0; |
| 254 | + int results_offset = 0; |
| 255 | + uint8_t results_buffer[130]; |
| 256 | + for(int index = 0; index < count && index + offset < neighbours_count; index++){ |
| 257 | + |
| 258 | + // stop if we can't fit another entry in results |
| 259 | + int entry_size = pubkey_prefix_length + 4 + 1; |
| 260 | + if(results_offset + entry_size > sizeof(results_buffer)){ |
| 261 | + MESH_DEBUG_PRINTLN("REQ_TYPE_GET_NEIGHBOURS no more entries can fit in results buffer"); |
| 262 | + break; |
| 263 | + } |
| 264 | + |
| 265 | + // add next neighbour to results |
| 266 | + auto neighbour = &sorted_neighbours[index + offset]; |
| 267 | + uint32_t heard_seconds_ago = getRTCClock()->getCurrentTime() - neighbour->heard_timestamp; |
| 268 | + memcpy(&results_buffer[results_offset], neighbour->id.pub_key, pubkey_prefix_length); results_offset += pubkey_prefix_length; |
| 269 | + memcpy(&results_buffer[results_offset], &heard_seconds_ago, 4); results_offset += 4; |
| 270 | + memcpy(&results_buffer[results_offset], &neighbour->snr, 1); results_offset += 1; |
| 271 | + results_count++; |
| 272 | + |
| 273 | + } |
| 274 | + |
| 275 | + // build reply |
| 276 | + MESH_DEBUG_PRINTLN("REQ_TYPE_GET_NEIGHBOURS neighbours_count=%d results_count=%d", neighbours_count, results_count); |
| 277 | + memcpy(&reply_data[reply_offset], &neighbours_count, 2); reply_offset += 2; |
| 278 | + memcpy(&reply_data[reply_offset], &results_count, 2); reply_offset += 2; |
| 279 | + memcpy(&reply_data[reply_offset], &results_buffer, results_offset); reply_offset += results_offset; |
| 280 | + |
| 281 | + return reply_offset; |
| 282 | + } |
| 283 | + } |
190 | 284 | return 0; // unknown command |
191 | 285 | } |
192 | 286 |
|
|
0 commit comments