// Copyright 2020 Mobilinkd LLC. #pragma once #include #include #include // Don't have std::span in C++17. #include namespace mobilinkd { struct LinkSetupFrame { using call_t = std::array; // NUL-terminated C-string. using encoded_call_t = std::array; using frame_t = std::array; using nonce_t = std::string_view; // std::span would be better here. enum TxType { PACKET, STREAM }; enum DataType { DT_RESERVED, DATA, VOICE, MIXED }; enum EncType { NONE, AES, LFSR, ET_RESERVED }; call_t mycall_ = {0}; call_t tocall_ = {0}; TxType tx_type_ = TxType::STREAM; DataType data_type_ = DataType::VOICE; EncType encryption_type_ = EncType::NONE; template static encoded_call_t encode_callsign(std::array callsign) { // Encode the characters to base-40 digits. uint64_t encoded = 0; std::reverse(callsign.begin(), callsign.end()); for (auto c : callsign) { if (c == 0) continue; encoded *= 40; if (c >= 'A' and c <= 'Z') { encoded += c - 'A' + 1; } else if (c >= '0' and c <= '9') { encoded += c - '0' + 27; } else if (c == '-') { encoded += 37; } else if (c == '/') { encoded += 38; } else if (c == '.') { encoded += 39; } } const auto p = reinterpret_cast(&encoded); encoded_call_t result; std::copy(p, p + 6, result.rbegin()); return result; } static call_t decode_callsign(encoded_call_t callsign) { static const char callsign_map[] = "xABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/."; uint64_t encoded = 0; // This only works on little endian architectures. auto p = reinterpret_cast(&encoded); std::copy(callsign.rbegin(), callsign.rend(), p); // decode each base-40 digit and map them to the appriate character. call_t result; result.fill(0); size_t index = 0; while (encoded) { result[index++] = callsign_map[encoded % 40]; encoded /= 40; } return result; } LinkSetupFrame() {} LinkSetupFrame& myCall(const char*) { return *this; } }; } // mobilinkd