kopia lustrzana https://github.com/OpenRTX/OpenRTX
Reorganised M17LinkSetupframe and M17Frame classes, encapsulating structs defining their internal data structure
rodzic
8f63d349a2
commit
c73aa92305
|
@ -35,6 +35,10 @@ using payload_t = std::array< uint8_t, 16 >; // Data type for frame payload fi
|
||||||
using lich_t = std::array< uint8_t, 12 >; // Data type for Golay(24,12) encoded LICH data
|
using lich_t = std::array< uint8_t, 12 >; // Data type for Golay(24,12) encoded LICH data
|
||||||
|
|
||||||
|
|
||||||
|
static constexpr std::array<uint8_t, 2> LSF_SYNC_WORD = {0x55, 0xF7}; // LSF sync word
|
||||||
|
static constexpr std::array<uint8_t, 2> DATA_SYNC_WORD = {0xFF, 0x5D}; // Stream data sync word
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This structure provides bit field definitions for the "TYPE" field
|
* This structure provides bit field definitions for the "TYPE" field
|
||||||
* contained in an M17 Link Setup Frame.
|
* contained in an M17 Link Setup Frame.
|
||||||
|
@ -49,35 +53,11 @@ typedef union
|
||||||
uint16_t encSubType : 2; //< Encryption subtype
|
uint16_t encSubType : 2; //< Encryption subtype
|
||||||
uint16_t CAN : 4; //< Channel Access Number
|
uint16_t CAN : 4; //< Channel Access Number
|
||||||
uint16_t : 4; //< Reserved, padding to 16 bit
|
uint16_t : 4; //< Reserved, padding to 16 bit
|
||||||
};
|
}
|
||||||
|
fields;
|
||||||
|
|
||||||
uint16_t value;
|
uint16_t value;
|
||||||
}
|
}
|
||||||
streamType_t;
|
streamType_t;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data structure corresponding to a full M17 Link Setup Frame.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
call_t dst; //< Destination callsign
|
|
||||||
call_t src; //< Source callsign
|
|
||||||
streamType_t type; //< Stream type information
|
|
||||||
meta_t meta; //< Metadata
|
|
||||||
uint16_t crc; //< CRC
|
|
||||||
}
|
|
||||||
__attribute__((packed)) lsf_t;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data structure corresponding to a full M17 data frame.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint16_t frameNum; //< Frame number
|
|
||||||
payload_t payload; //< Payload data
|
|
||||||
}
|
|
||||||
__attribute__((packed)) dataFrame_t;
|
|
||||||
|
|
||||||
#endif /* M17_DATATYPES_H */
|
#endif /* M17_DATATYPES_H */
|
||||||
|
|
|
@ -89,30 +89,28 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get underlying data structure.
|
* Get underlying data.
|
||||||
*
|
*
|
||||||
* @return a reference to the underlying dataFrame_t data structure.
|
* @return a pointer to const uint8_t allowing direct access to frame data.
|
||||||
*/
|
*/
|
||||||
dataFrame_t& getData()
|
const uint8_t *getData()
|
||||||
{
|
{
|
||||||
return data;
|
return reinterpret_cast < const uint8_t * > (&data);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dump the frame content to a std::array.
|
|
||||||
*
|
|
||||||
* \return std::array containing the content of the frame.
|
|
||||||
*/
|
|
||||||
std::array< uint8_t, sizeof(dataFrame_t) > toArray()
|
|
||||||
{
|
|
||||||
std::array< uint8_t, sizeof(dataFrame_t) > frame;
|
|
||||||
memcpy(frame.data(), &data, frame.size());
|
|
||||||
return frame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
dataFrame_t data; ///< Underlying frame data.
|
/**
|
||||||
|
* Data structure corresponding to a full M17 data frame.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t frameNum; ///< Frame number
|
||||||
|
payload_t payload; ///< Payload data
|
||||||
|
}
|
||||||
|
__attribute__((packed)) dataFrame_t;
|
||||||
|
|
||||||
|
dataFrame_t data; ///< Underlying frame data.
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* M17_FRAME_H */
|
#endif /* M17_FRAME_H */
|
||||||
|
|
|
@ -61,6 +61,13 @@ public:
|
||||||
*/
|
*/
|
||||||
void setSource(const std::string& callsign);
|
void setSource(const std::string& callsign);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get source callsign.
|
||||||
|
*
|
||||||
|
* @return: string containing the source callsign.
|
||||||
|
*/
|
||||||
|
std::string getSource();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set destination callsign.
|
* Set destination callsign.
|
||||||
*
|
*
|
||||||
|
@ -68,6 +75,13 @@ public:
|
||||||
*/
|
*/
|
||||||
void setDestination(const std::string& callsign);
|
void setDestination(const std::string& callsign);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get destination callsign.
|
||||||
|
*
|
||||||
|
* @return: string containing the destination callsign.
|
||||||
|
*/
|
||||||
|
std::string getDestination();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get stream type field.
|
* Get stream type field.
|
||||||
*
|
*
|
||||||
|
@ -97,11 +111,20 @@ public:
|
||||||
void updateCrc();
|
void updateCrc();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get underlying data structure.
|
* Check if frame data is valid that is, if the CRC computed over the LSF
|
||||||
|
* fields matches the one carried by the LSF itself.
|
||||||
*
|
*
|
||||||
* @return a reference to the underlying dataFrame_t data structure.
|
* @return true if CRC of LSF data matches the one stored in the LSF itself,
|
||||||
|
* false otherwise.
|
||||||
*/
|
*/
|
||||||
lsf_t& getData();
|
bool valid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get underlying data.
|
||||||
|
*
|
||||||
|
* @return a pointer to const uint8_t allowing direct access to LSF data.
|
||||||
|
*/
|
||||||
|
const uint8_t *getData();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate one of the six possible LSF chunks for embedding in data frame's
|
* Generate one of the six possible LSF chunks for embedding in data frame's
|
||||||
|
@ -112,13 +135,6 @@ public:
|
||||||
*/
|
*/
|
||||||
lich_t generateLichSegment(const uint8_t segmentNum);
|
lich_t generateLichSegment(const uint8_t segmentNum);
|
||||||
|
|
||||||
/**
|
|
||||||
* Dump the frame content to a std::array.
|
|
||||||
*
|
|
||||||
* \return std::array containing the content of the frame.
|
|
||||||
*/
|
|
||||||
std::array< uint8_t, sizeof(lsf_t) > toArray();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -131,7 +147,20 @@ private:
|
||||||
*/
|
*/
|
||||||
uint16_t crc16(const void *data, const size_t len);
|
uint16_t crc16(const void *data, const size_t len);
|
||||||
|
|
||||||
lsf_t data; ///< Underlying frame data.
|
/**
|
||||||
|
* Data structure corresponding to a full M17 Link Setup Frame.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
call_t dst; ///< Destination callsign
|
||||||
|
call_t src; ///< Source callsign
|
||||||
|
streamType_t type; ///< Stream type information
|
||||||
|
meta_t meta; ///< Metadata
|
||||||
|
uint16_t crc; ///< CRC
|
||||||
|
}
|
||||||
|
__attribute__((packed)) lsf_t;
|
||||||
|
|
||||||
|
lsf_t data; ///< Underlying frame data.
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* M17_LINKSETUPFRAME_H */
|
#endif /* M17_LINKSETUPFRAME_H */
|
||||||
|
|
|
@ -45,11 +45,21 @@ void M17LinkSetupFrame::setSource(const std::string& callsign)
|
||||||
encode_callsign(callsign, data.src);
|
encode_callsign(callsign, data.src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string M17LinkSetupFrame::getSource()
|
||||||
|
{
|
||||||
|
return decode_callsign(data.src);
|
||||||
|
}
|
||||||
|
|
||||||
void M17LinkSetupFrame::setDestination(const std::string& callsign)
|
void M17LinkSetupFrame::setDestination(const std::string& callsign)
|
||||||
{
|
{
|
||||||
encode_callsign(callsign, data.dst);
|
encode_callsign(callsign, data.dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string M17LinkSetupFrame::getDestination()
|
||||||
|
{
|
||||||
|
return decode_callsign(data.dst);
|
||||||
|
}
|
||||||
|
|
||||||
streamType_t M17LinkSetupFrame::getType()
|
streamType_t M17LinkSetupFrame::getType()
|
||||||
{
|
{
|
||||||
// NOTE: M17 fields are big-endian, we need to swap bytes
|
// NOTE: M17 fields are big-endian, we need to swap bytes
|
||||||
|
@ -77,9 +87,17 @@ void M17LinkSetupFrame::updateCrc()
|
||||||
data.crc = __builtin_bswap16(crc);
|
data.crc = __builtin_bswap16(crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
lsf_t& M17LinkSetupFrame::getData()
|
bool M17LinkSetupFrame::valid()
|
||||||
{
|
{
|
||||||
return data;
|
uint16_t crc = crc16(&data, 28);
|
||||||
|
if(data.crc == __builtin_bswap16(crc)) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t * M17LinkSetupFrame::getData()
|
||||||
|
{
|
||||||
|
return reinterpret_cast < const uint8_t * >(&data);
|
||||||
}
|
}
|
||||||
|
|
||||||
lich_t M17LinkSetupFrame::generateLichSegment(const uint8_t segmentNum)
|
lich_t M17LinkSetupFrame::generateLichSegment(const uint8_t segmentNum)
|
||||||
|
@ -119,13 +137,6 @@ lich_t M17LinkSetupFrame::generateLichSegment(const uint8_t segmentNum)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array< uint8_t, sizeof(lsf_t) > M17LinkSetupFrame::toArray()
|
|
||||||
{
|
|
||||||
std::array< uint8_t, sizeof(lsf_t) > frame;
|
|
||||||
memcpy(frame.data(), &data, frame.size());
|
|
||||||
return frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t M17LinkSetupFrame::crc16(const void *data, const size_t len)
|
uint16_t M17LinkSetupFrame::crc16(const void *data, const size_t len)
|
||||||
{
|
{
|
||||||
const uint8_t *ptr = reinterpret_cast< const uint8_t *>(data);
|
const uint8_t *ptr = reinterpret_cast< const uint8_t *>(data);
|
||||||
|
|
|
@ -26,9 +26,6 @@
|
||||||
namespace M17
|
namespace M17
|
||||||
{
|
{
|
||||||
|
|
||||||
static constexpr std::array<uint8_t, 2> LSF_SYNC_WORD = {0x55, 0xF7};
|
|
||||||
static constexpr std::array<uint8_t, 2> DATA_SYNC_WORD = {0xFF, 0x5D};
|
|
||||||
|
|
||||||
M17Transmitter::M17Transmitter(M17Modulator& modulator) : modulator(modulator),
|
M17Transmitter::M17Transmitter(M17Modulator& modulator) : modulator(modulator),
|
||||||
currentLich(0), frameNumber(0)
|
currentLich(0), frameNumber(0)
|
||||||
{
|
{
|
||||||
|
@ -59,9 +56,9 @@ void M17Transmitter::start(const std::string& src, const std::string& dst)
|
||||||
if(!dst.empty()) lsf.setDestination(dst);
|
if(!dst.empty()) lsf.setDestination(dst);
|
||||||
|
|
||||||
streamType_t type;
|
streamType_t type;
|
||||||
type.stream = 1; // Stream
|
type.fields.stream = 1; // Stream
|
||||||
type.dataType = 2; // Voice data
|
type.fields.dataType = 2; // Voice data
|
||||||
type.CAN = 0; // Channel access number
|
type.fields.CAN = 0; // Channel access number
|
||||||
|
|
||||||
lsf.setType(type);
|
lsf.setType(type);
|
||||||
lsf.updateCrc();
|
lsf.updateCrc();
|
||||||
|
@ -75,7 +72,7 @@ void M17Transmitter::start(const std::string& src, const std::string& dst)
|
||||||
// Encode the LSF, then puncture and decorrelate its data
|
// Encode the LSF, then puncture and decorrelate its data
|
||||||
std::array<uint8_t, 61> encoded;
|
std::array<uint8_t, 61> encoded;
|
||||||
encoder.reset();
|
encoder.reset();
|
||||||
encoder.encode(&lsf.getData(), encoded.data(), sizeof(lsf_t));
|
encoder.encode(lsf.getData(), encoded.data(), sizeof(M17LinkSetupFrame));
|
||||||
encoded[60] = encoder.flush();
|
encoded[60] = encoder.flush();
|
||||||
|
|
||||||
std::array<uint8_t, 46> punctured;
|
std::array<uint8_t, 46> punctured;
|
||||||
|
@ -105,7 +102,7 @@ void M17Transmitter::send(const payload_t& payload, const bool isLast)
|
||||||
// Encode frame
|
// Encode frame
|
||||||
std::array<uint8_t, 37> encoded;
|
std::array<uint8_t, 37> encoded;
|
||||||
encoder.reset();
|
encoder.reset();
|
||||||
encoder.encode(&dataFrame.getData(), encoded.data(), sizeof(dataFrame_t));
|
encoder.encode(dataFrame.getData(), encoded.data(), sizeof(M17Frame));
|
||||||
encoded[36] = encoder.flush();
|
encoded[36] = encoder.flush();
|
||||||
|
|
||||||
std::array<uint8_t, 34> punctured;
|
std::array<uint8_t, 34> punctured;
|
||||||
|
|
Ładowanie…
Reference in New Issue