Formatted code (#1007)

* Updated style

* Updated files

* fixed new line

* Updated spacing

* File fix WIP

* Updated to clang 13

* updated comment style

* Removed old comment code
This commit is contained in:
jLynx
2023-05-19 08:16:05 +12:00
committed by GitHub
parent 7aca7ce74d
commit 033c4e9a5b
599 changed files with 70746 additions and 66896 deletions

View File

@@ -29,79 +29,79 @@
namespace acars {
size_t Packet::length() const {
return packet_.size();
return packet_.size();
}
bool Packet::is_valid() const {
return true; //length_valid() && crc_ok();
return true; // length_valid() && crc_ok();
}
Timestamp Packet::received_at() const {
return packet_.timestamp();
return packet_.timestamp();
}
uint8_t Packet::block_id() const {
return field_.read(96, 8);
return field_.read(96, 8);
}
std::string Packet::registration_number() const {
std::string result;
result.reserve(7);
const size_t character_length = 8;
for(size_t i=16; i<(16+7*character_length); i+=character_length) {
result += (field_.read(i, character_length) & 0x7F);
}
std::string result;
result.reserve(7);
return result;
const size_t character_length = 8;
for (size_t i = 16; i < (16 + 7 * character_length); i += character_length) {
result += (field_.read(i, character_length) & 0x7F);
}
return result;
}
uint32_t Packet::read(const size_t start_bit, const size_t length) const {
return field_.read(start_bit, length);
return field_.read(start_bit, length);
}
/*std::string Packet::text(
const size_t start_bit,
const size_t character_count
const size_t start_bit,
const size_t character_count
) const {
std::string result;
result.reserve(character_count);
const size_t character_length = 6;
const size_t end_bit = start_bit + character_count * character_length;
for(size_t i=start_bit; i<end_bit; i+=character_length) {
result += char_to_ascii(field_.read(i, character_length));
}
std::string result;
result.reserve(character_count);
return result;
const size_t character_length = 6;
const size_t end_bit = start_bit + character_count * character_length;
for(size_t i=start_bit; i<end_bit; i+=character_length) {
result += char_to_ascii(field_.read(i, character_length));
}
return result;
}*/
bool Packet::crc_ok() const {
CRCReader field_crc { packet_ };
CRC<16> acars_fcs { 0x1021, 0x0000, 0x0000 };
for(size_t i=0; i<data_length(); i+=8) {
acars_fcs.process_byte(field_crc.read(i, 8));
}
CRCReader field_crc{packet_};
CRC<16> acars_fcs{0x1021, 0x0000, 0x0000};
return (acars_fcs.checksum() == (unsigned)field_crc.read(data_length(), fcs_length));
for (size_t i = 0; i < data_length(); i += 8) {
acars_fcs.process_byte(field_crc.read(i, 8));
}
return (acars_fcs.checksum() == (unsigned)field_crc.read(data_length(), fcs_length));
}
size_t Packet::data_and_fcs_length() const {
return length() - 8;
return length() - 8;
}
size_t Packet::data_length() const {
return data_and_fcs_length() - fcs_length;
return data_and_fcs_length() - fcs_length;
}
bool Packet::length_valid() const {
const size_t extra_bits = data_and_fcs_length() & 7;
if( extra_bits != 0 ) {
return false;
}
const size_t extra_bits = data_and_fcs_length() & 7;
if (extra_bits != 0) {
return false;
}
return true;
return true;
}
} /* namespace ais */
} // namespace acars

View File

@@ -33,43 +33,42 @@
namespace acars {
class Packet {
public:
constexpr Packet(
const baseband::Packet& packet
) : packet_ { packet },
field_ { packet_ }
{
}
public:
constexpr Packet(
const baseband::Packet& packet)
: packet_{packet},
field_{packet_} {
}
size_t length() const;
bool is_valid() const;
size_t length() const;
Timestamp received_at() const;
bool is_valid() const;
uint8_t block_id() const;
std::string registration_number() const;
Timestamp received_at() const;
uint32_t read(const size_t start_bit, const size_t length) const;
//std::string text(const size_t start_bit, const size_t character_count) const;
uint8_t block_id() const;
std::string registration_number() const;
bool crc_ok() const;
uint32_t read(const size_t start_bit, const size_t length) const;
// std::string text(const size_t start_bit, const size_t character_count) const;
private:
using Reader = FieldReader<baseband::Packet, BitRemapByteReverse>;
using CRCReader = FieldReader<baseband::Packet, BitRemapNone>;
const baseband::Packet packet_;
const Reader field_;
bool crc_ok() const;
const size_t fcs_length = 16;
private:
using Reader = FieldReader<baseband::Packet, BitRemapByteReverse>;
using CRCReader = FieldReader<baseband::Packet, BitRemapNone>;
size_t data_and_fcs_length() const;
size_t data_length() const;
const baseband::Packet packet_;
const Reader field_;
bool length_valid() const;
const size_t fcs_length = 16;
size_t data_and_fcs_length() const;
size_t data_length() const;
bool length_valid() const;
};
} /* namespace acars */
#endif/*__ACARS_PACKET_H__*/
#endif /*__ACARS_PACKET_H__*/

View File

@@ -30,106 +30,98 @@ namespace adc {
constexpr size_t clock_rate_max = 4500000U;
struct CR {
uint32_t sel;
uint32_t clkdiv;
uint32_t resolution;
uint32_t edge;
uint32_t sel;
uint32_t clkdiv;
uint32_t resolution;
uint32_t edge;
constexpr operator uint32_t() const {
return
((sel & 0xff) << 0)
| ((clkdiv & 0xff) << 8)
| ((0 & 1) << 16)
| (((10 - resolution) & 7) << 17)
| ((1 & 1) << 21)
| ((0 & 7) << 24)
| ((edge & 1) << 27)
;
}
constexpr operator uint32_t() const {
return ((sel & 0xff) << 0) | ((clkdiv & 0xff) << 8) | ((0 & 1) << 16) | (((10 - resolution) & 7) << 17) | ((1 & 1) << 21) | ((0 & 7) << 24) | ((edge & 1) << 27);
}
};
struct Config {
uint32_t cr;
uint32_t cr;
};
template<uint32_t BaseAddress>
template <uint32_t BaseAddress>
class ADC {
public:
static void power_up(const Config config) {
adcp().CR = config.cr;
}
public:
static void power_up(const Config config) {
adcp().CR = config.cr;
}
static void clock_enable() {
if( &adcp() == LPC_ADC0 ) {
LPC_CCU1->CLK_APB3_ADC0_CFG.AUTO = 1;
LPC_CCU1->CLK_APB3_ADC0_CFG.RUN = 1;
}
if( &adcp() == LPC_ADC1 ) {
LPC_CCU1->CLK_APB3_ADC1_CFG.AUTO = 1;
LPC_CCU1->CLK_APB3_ADC1_CFG.RUN = 1;
}
}
static void clock_enable() {
if (&adcp() == LPC_ADC0) {
LPC_CCU1->CLK_APB3_ADC0_CFG.AUTO = 1;
LPC_CCU1->CLK_APB3_ADC0_CFG.RUN = 1;
}
if (&adcp() == LPC_ADC1) {
LPC_CCU1->CLK_APB3_ADC1_CFG.AUTO = 1;
LPC_CCU1->CLK_APB3_ADC1_CFG.RUN = 1;
}
}
static void clock_disable() {
if( &adcp() == LPC_ADC0 ) {
LPC_CCU1->CLK_APB3_ADC0_CFG.RUN = 0;
}
if( &adcp() == LPC_ADC1 ) {
LPC_CCU1->CLK_APB3_ADC1_CFG.RUN = 0;
}
}
static void clock_disable() {
if (&adcp() == LPC_ADC0) {
LPC_CCU1->CLK_APB3_ADC0_CFG.RUN = 0;
}
if (&adcp() == LPC_ADC1) {
LPC_CCU1->CLK_APB3_ADC1_CFG.RUN = 0;
}
}
static void disable() {
adcp().INTEN = 0;
adcp().CR = 0;
static void disable() {
adcp().INTEN = 0;
adcp().CR = 0;
clock_disable();
}
clock_disable();
}
static void interrupts_disable() {
adcp().INTEN = 0;
}
static void interrupts_disable() {
adcp().INTEN = 0;
}
static void interrupts_enable(const uint32_t mask) {
adcp().INTEN = mask;
}
static void interrupts_enable(const uint32_t mask) {
adcp().INTEN = mask;
}
static void start_burst() {
adcp().CR |= (1U << 16);
}
static void start_burst() {
adcp().CR |= (1U << 16);
}
static void start_once() {
adcp().CR |= (1U << 24);
}
static void start_once() {
adcp().CR |= (1U << 24);
}
static void start_once(size_t n) {
uint32_t cr = adcp().CR;
cr &= ~(0xffU);
cr |= (1 << 24) | (1 << n);
adcp().CR = cr;
}
static void start_once(size_t n) {
uint32_t cr = adcp().CR;
cr &= ~(0xffU);
cr |= (1 << 24) | (1 << n);
adcp().CR = cr;
}
static void stop_burst() {
adcp().CR &= ~(1U << 16);
}
static void stop_burst() {
adcp().CR &= ~(1U << 16);
}
static uint32_t convert(size_t n) {
start_once(n);
while(true) {
const uint32_t data = adcp().DR[n];
if( (data >> 31) & 1 ) {
return (data >> 6) & 0x3ff;
}
}
}
static uint32_t convert(size_t n) {
start_once(n);
while (true) {
const uint32_t data = adcp().DR[n];
if ((data >> 31) & 1) {
return (data >> 6) & 0x3ff;
}
}
}
private:
static LPC_ADCx_Type& adcp() {
return *reinterpret_cast<LPC_ADCx_Type*>(BaseAddress);
}
private:
static LPC_ADCx_Type& adcp() {
return *reinterpret_cast<LPC_ADCx_Type*>(BaseAddress);
}
};
} /* namespace adc */
} /* namespace lpc43xx */
#endif/*__ADC_H__*/
#endif /*__ADC_H__*/

View File

@@ -29,83 +29,83 @@
namespace adsb {
void make_frame_adsb(ADSBFrame& frame, const uint32_t ICAO_address) {
frame.clear();
frame.push_byte((DF_ADSB << 3) | 5); // DF=17 and CA
frame.push_byte(ICAO_address >> 16);
frame.push_byte(ICAO_address >> 8);
frame.push_byte(ICAO_address & 0xFF);
frame.clear();
frame.push_byte((DF_ADSB << 3) | 5); // DF=17 and CA
frame.push_byte(ICAO_address >> 16);
frame.push_byte(ICAO_address >> 8);
frame.push_byte(ICAO_address & 0xFF);
}
// Civil aircraft ADS-B message type starts with Dowlink Format (DF=17) and frame is 112 bits long.
// Civil aircraft ADS-B message type starts with Dowlink Format (DF=17) and frame is 112 bits long.
// All known DF's >=16 are long (112 bits). All known DF's <=15 are short (56 bits).(In this case 112 bits)
// Msg structure consists of five main parts :|DF=17 (5 bits)|CA (3 bits)|ICAO (24 bits)|ME (56 bits)|CRC (24 bits)
// Msg structure consists of five main parts :|DF=17 (5 bits)|CA (3 bits)|ICAO (24 bits)|ME (56 bits)|CRC (24 bits)
// Aircraft identification and category message structure, the ME (56 bits) = TC,5 bits | CA,3 bits | C1,6 bits | C2,6 bits | C3,6 | C4,6 | C5,6 | C6,6 | C7,6 | C8,6
// TC : (1..4) : Aircraft identification Type Code . // TC : 9 to 18: Airbone postion // TC : 19 Airbone velocity .
// TC : (1..4) : Aircraft identification Type Code . // TC : 9 to 18: Airbone postion // TC : 19 Airbone velocity .
// In this encode_frame_identification function we are using DF = 17 (112 bits long) and TC=4)
void encode_frame_id(ADSBFrame& frame, const uint32_t ICAO_address, const std::string& callsign) {
std::string callsign_formatted(8, '_');
uint64_t callsign_coded = 0;
uint32_t c, s;
char ch;
make_frame_adsb(frame, ICAO_address); // Header DF=17 Downlink Format = ADS-B message (frame 112 bits)
frame.push_byte(TC_IDENT << 3); // 5 top bits ME = TC = we use fix 4 , # Type aircraft Identification Category = TC_IDENT = 4,
// Translate and encode callsign
for (c = 0; c < 8; c++) {
ch = callsign[c];
for (s = 0; s < 64; s++)
if (ch == icao_id_lut[s]) break;
if (s == 64) {
ch = ' '; // Invalid character
s = 32;
}
callsign_coded <<= 6;
callsign_coded |= s;
//callsign[c] = ch;
}
// Insert callsign in frame
for (c = 0; c < 6; c++)
frame.push_byte((callsign_coded >> ((5 - c) * 8)) & 0xFF);
frame.make_CRC();
std::string callsign_formatted(8, '_');
uint64_t callsign_coded = 0;
uint32_t c, s;
char ch;
make_frame_adsb(frame, ICAO_address); // Header DF=17 Downlink Format = ADS-B message (frame 112 bits)
frame.push_byte(TC_IDENT << 3); // 5 top bits ME = TC = we use fix 4 , # Type aircraft Identification Category = TC_IDENT = 4,
// Translate and encode callsign
for (c = 0; c < 8; c++) {
ch = callsign[c];
for (s = 0; s < 64; s++)
if (ch == icao_id_lut[s]) break;
if (s == 64) {
ch = ' '; // Invalid character
s = 32;
}
callsign_coded <<= 6;
callsign_coded |= s;
// callsign[c] = ch;
}
// Insert callsign in frame
for (c = 0; c < 6; c++)
frame.push_byte((callsign_coded >> ((5 - c) * 8)) & 0xFF);
frame.make_CRC();
}
std::string decode_frame_id(ADSBFrame& frame) {
std::string callsign = "";
uint8_t * raw_data = frame.get_raw_data();
uint64_t callsign_coded = 0;
uint32_t c;
// Frame bytes to long
for (c = 5; c < 11; c++) {
callsign_coded <<= 8;
callsign_coded |= raw_data[c];
}
// Long to 6-bit characters
for (c = 0; c < 8; c++) {
callsign.append(1, icao_id_lut[(callsign_coded >> 42) & 0x3F]);
callsign_coded <<= 6;
}
return callsign;
std::string callsign = "";
uint8_t* raw_data = frame.get_raw_data();
uint64_t callsign_coded = 0;
uint32_t c;
// Frame bytes to long
for (c = 5; c < 11; c++) {
callsign_coded <<= 8;
callsign_coded |= raw_data[c];
}
// Long to 6-bit characters
for (c = 0; c < 8; c++) {
callsign.append(1, icao_id_lut[(callsign_coded >> 42) & 0x3F]);
callsign_coded <<= 6;
}
return callsign;
}
/*void generate_frame_emergency(ADSBFrame& frame, const uint32_t ICAO_address, const uint8_t code) {
make_frame_mode_s(frame, ICAO_address);
frame.push_byte((28 << 3) + 1); // TC = 28 (Emergency), subtype = 1 (Emergency)
frame.push_byte(code << 5);
frame.make_CRC();
make_frame_mode_s(frame, ICAO_address);
frame.push_byte((28 << 3) + 1); // TC = 28 (Emergency), subtype = 1 (Emergency)
frame.push_byte(code << 5);
frame.make_CRC();
}*/
// Mode S services. (Mode Select Beacon System). There are two types of Mode S interrogations: The short (56 bits) . and the long (112 bits )
@@ -113,111 +113,116 @@ std::string decode_frame_id(ADSBFrame& frame) {
// Identity squawk replies can be DF=5 (Surveillance Identity reply)(56 bits) / DF 21 (Comm-B with Identity reply) (112 bits)
// DF 21: Comm-B with identity reply structure = |DF=21(5 bits)|FS (3 bits)|DR (5 bits)|UM (6 bits) |Identity squawk code (13 bits) |MB (56 bits) |CRC (24 bits) (total 112 bits)
// Comm-B messages count for a large portion of the Mode S selective interrogation responses.(means, only transmitted information upon selective request)
// Comm-B messages protocol supports many different types of msg's (up to 255).The three more popular ones are the following ones:
// Comm-B messages protocol supports many different types of msg's (up to 255).The three more popular ones are the following ones:
// (a) Mode S ELementary Surveillance (ELS) / (b) Mode S EnHanced Surveillance (EHS) / (c) Meteorological information
// Comm-B Data Selector (BDS) is an 8-bit code that determines which information to be included in the MB fields
void encode_frame_squawk(ADSBFrame& frame, const uint16_t squawk) {
uint16_t squawk_coded;
uint8_t UM_field=0b111101, FS=0b010, DR=0b00001 ;
uint16_t squawk_coded;
uint8_t UM_field = 0b111101, FS = 0b010, DR = 0b00001;
// To be sent those fields, (56 bits). We should store byte by byte into the frame , and It will be transmitted byte to byte same FIFO order.
// DF 5 bits 5 DF=21 (5 top bits) Downlink Format
// FS 3 bits 0b000, FS (3 bottom bits) (Flight status ) = 000 : no alert, no SPI, aircraft is airborne
// DR 5 bits 0b00001 DR (Downlink request) (5 top bits) = 00000 : no downlink request (In surveillance replies, only values 0, 1, 4, and 5 are used.)
// UM 6 bits 0b000010 UM (Utility message)= 000000, Utility message (UM): 6 bits, contains transponder communication status information.(IIS + IDS)
// Identity_code 13 bits squawk id_code in special interleaved format.
// MB 56 bits
// CRC partity 24 bits parity checksum , cyclic redundancy chek.
frame.clear();
frame.push_byte( ( DF_EHS_SQUAWK << 3 ) | FS ); // DF=21 (5bits) + FS (3bits, 010 : alert, NO SPI, aircraft is airborne)
frame.push_byte(( DR <<3 ) | ( UM_field>>3) ); // DR (5bits, 00001 : downlink request + 3 top bits of UM , let's use 0b111000
// 12 11 10 9 8 7 6 5 4 3 2 1 0 (Original notes) bit weight position----------------------
// 32 31 30 29 28 27 26 25 24 23 22 21 20 (it was wrong , now corrected) bit order inside frame msg
// D4 B4 D2 B2 D1 B1 __ A4 C4 A2 C2 A1 C1 standard spec order of the 13 bits, to be sent , each octal digit = 3 bits , (example A=7 binary A4 A2 A0 = 111
// ABCD = code (octal, 0000~7777)
// FEDCBA9876543210
// xAAAxBBBxCCCxDDD 4 x 3 bits (each octal digit)
// x421x421x421x421 binary weight of each binary position, example AAA = 7 = 111 -------------------------
// To be sent those fields, (56 bits). We should store byte by byte into the frame , and It will be transmitted byte to byte same FIFO order.
// DF 5 bits 5 DF=21 (5 top bits) Downlink Format
// FS 3 bits 0b000, FS (3 bottom bits) (Flight status ) = 000 : no alert, no SPI, aircraft is airborne
// DR 5 bits 0b00001 DR (Downlink request) (5 top bits) = 00000 : no downlink request (In surveillance replies, only values 0, 1, 4, and 5 are used.)
// UM 6 bits 0b000010 UM (Utility message)= 000000, Utility message (UM): 6 bits, contains transponder communication status information.(IIS + IDS)
// Identity_code 13 bits squawk id_code in special interleaved format.
// MB 56 bits
// CRC partity 24 bits parity checksum , cyclic redundancy chek.
// Additional , expanded notes -------------------------------
// Identity squawk code ABCD = code (octal, 0000~7777) , input concatenated squawk : 4 octal digits ,A4 A2 A1-B4 B2 B1-C4 C2 C1-D4 D2 D1.
// 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 bit position of the frame msg, (Squawk id is bit 20-32, from C1..D4).
// UM4 UM2 UM1 C1 A1 C2 A2 C4 A4 X B1 D1 B2 D2 B4 D4 3 lower bit UM4,UM2,UM1 of the UM (6bits), and we should re-order the 13 bits ABCD changing 12 bit poistion based on std.
// 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Two bytes , bit position to be send.
squawk_coded = ( (( UM_field & (0b111)) <<13) | ((squawk << 9) & 0x1000) ) | // C1 It also leaves in the top 3 lower bottom bitd part of UM field.
((squawk << 2) & 0x0800) | // A1
((squawk << 6) & 0x0400) | // C2
((squawk >> 1) & 0x0200) | // A2
((squawk << 3) & 0x0100) | // C4
((squawk >> 4) & 0x0080) | // A4
((squawk >> 1) & 0x0020) | // B1
((squawk << 4) & 0x0010) | // D1
((squawk >> 4) & 0x0008) | // B2
((squawk << 1) & 0x0004) | // D2
((squawk >> 7) & 0x0002) | // B4
((squawk >> 2) & 0x0001); // D4
frame.clear();
frame.push_byte((DF_EHS_SQUAWK << 3) | FS); // DF=21 (5bits) + FS (3bits, 010 : alert, NO SPI, aircraft is airborne)
frame.push_byte((DR << 3) | (UM_field >> 3)); // DR (5bits, 00001 : downlink request + 3 top bits of UM , let's use 0b111000
frame.push_byte(squawk_coded>>8); // UM4 UM2 UM1 C1 A1 C2 A2 C4 that is the correct order, confirmed with dump1090
frame.push_byte(squawk_coded); // A4 X(1) B1 D1 B2 D2 B4 D4 that is the correct order, confirmed with dupm1090
// 12 11 10 9 8 7 6 5 4 3 2 1 0 (Original notes) bit weight position----------------------
// 32 31 30 29 28 27 26 25 24 23 22 21 20 (it was wrong , now corrected) bit order inside frame msg
// D4 B4 D2 B2 D1 B1 __ A4 C4 A2 C2 A1 C1 standard spec order of the 13 bits, to be sent , each octal digit = 3 bits , (example A=7 binary A4 A2 A0 = 111
// ABCD = code (octal, 0000~7777)
// DF 21 messages , has 56 bits more after 13 bits of squawk, we should add MB (56 bits)
// In this example, we are adding fixed MB = Track and turn report (BDS 5,0) decoding MB example = "F9363D3BBF9CE9" (56 bits)
// # -9.7, roll angle (deg)
// # 140.273, track angle (deg)
// # -0.406, track angle rate (deg/s)
// # 476, ground speed (kt)
// # 466, TAS (kt)
frame.push_byte(0xF9);frame.push_byte(0x36);frame.push_byte(0x3D);frame.push_byte(0x3B); // If we deltele those two lines, to send this fixed MB (56 bits),
frame.push_byte(0xBF);frame.push_byte(0x9C);frame.push_byte(0xE9); // current fw is padding with 56 x 0's to complete 112 bits msg.
// FEDCBA9876543210
// xAAAxBBBxCCCxDDD 4 x 3 bits (each octal digit)
// x421x421x421x421 binary weight of each binary position, example AAA = 7 = 111 -------------------------
frame.make_CRC();
}
// Additional , expanded notes -------------------------------
// Identity squawk code ABCD = code (octal, 0000~7777) , input concatenated squawk : 4 octal digits ,A4 A2 A1-B4 B2 B1-C4 C2 C1-D4 D2 D1.
// 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 bit position of the frame msg, (Squawk id is bit 20-32, from C1..D4).
// UM4 UM2 UM1 C1 A1 C2 A2 C4 A4 X B1 D1 B2 D2 B4 D4 3 lower bit UM4,UM2,UM1 of the UM (6bits), and we should re-order the 13 bits ABCD changing 12 bit poistion based on std.
// 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Two bytes , bit position to be send.
squawk_coded = (((UM_field & (0b111)) << 13) | ((squawk << 9) & 0x1000)) | // C1 It also leaves in the top 3 lower bottom bitd part of UM field.
((squawk << 2) & 0x0800) | // A1
((squawk << 6) & 0x0400) | // C2
((squawk >> 1) & 0x0200) | // A2
((squawk << 3) & 0x0100) | // C4
((squawk >> 4) & 0x0080) | // A4
((squawk >> 1) & 0x0020) | // B1
((squawk << 4) & 0x0010) | // D1
((squawk >> 4) & 0x0008) | // B2
((squawk << 1) & 0x0004) | // D2
((squawk >> 7) & 0x0002) | // B4
((squawk >> 2) & 0x0001); // D4
frame.push_byte(squawk_coded >> 8); // UM4 UM2 UM1 C1 A1 C2 A2 C4 that is the correct order, confirmed with dump1090
frame.push_byte(squawk_coded); // A4 X(1) B1 D1 B2 D2 B4 D4 that is the correct order, confirmed with dupm1090
// DF 21 messages , has 56 bits more after 13 bits of squawk, we should add MB (56 bits)
// In this example, we are adding fixed MB = Track and turn report (BDS 5,0) decoding MB example = "F9363D3BBF9CE9" (56 bits)
// # -9.7, roll angle (deg)
// # 140.273, track angle (deg)
// # -0.406, track angle rate (deg/s)
// # 476, ground speed (kt)
// # 466, TAS (kt)
frame.push_byte(0xF9);
frame.push_byte(0x36);
frame.push_byte(0x3D);
frame.push_byte(0x3B); // If we deltele those two lines, to send this fixed MB (56 bits),
frame.push_byte(0xBF);
frame.push_byte(0x9C);
frame.push_byte(0xE9); // current fw is padding with 56 x 0's to complete 112 bits msg.
frame.make_CRC();
}
float cpr_mod(float a, float b) {
return a - (b * floor(a / b));
return a - (b * floor(a / b));
}
int cpr_NL_precise(float lat) {
return (int) floor(2 * PI / acos(1 - ((1 - cos(PI / (2 * NZ))) / pow(cos(PI * lat / 180), 2))));
return (int)floor(2 * PI / acos(1 - ((1 - cos(PI / (2 * NZ))) / pow(cos(PI * lat / 180), 2))));
}
int cpr_NL_approx(float lat) {
if (lat < 0)
lat = -lat; // Symmetry
for (size_t c = 0; c < 58; c++) {
if (lat < adsb_lat_lut[c])
return 59 - c;
}
return 1;
if (lat < 0)
lat = -lat; // Symmetry
for (size_t c = 0; c < 58; c++) {
if (lat < adsb_lat_lut[c])
return 59 - c;
}
return 1;
}
int cpr_NL(float lat) {
// TODO prove that the approximate function is good
// enough for the precision we need. Uncomment if
// that is true. No performance penalty was noticed
// from testing, but if you find it might be an issue,
// switch to cpr_NL_approx() instead:
// TODO prove that the approximate function is good
// enough for the precision we need. Uncomment if
// that is true. No performance penalty was noticed
// from testing, but if you find it might be an issue,
// switch to cpr_NL_approx() instead:
//return cpr_NL_approx(lat);
// return cpr_NL_approx(lat);
return cpr_NL_precise(lat);
return cpr_NL_precise(lat);
}
int cpr_N(float lat, int is_odd) {
int nl = cpr_NL(lat) - is_odd;
if (nl < 1)
nl = 1;
nl = 1;
return nl;
}
@@ -225,220 +230,215 @@ float cpr_Dlon(float lat, int is_odd) {
return 360.0 / cpr_N(lat, is_odd);
}
// An ADS-B frame Civil aircraft message type starts with Dowlink Format (DF=17) and frame is 112 bits long.
// An ADS-B frame Civil aircraft message type starts with Dowlink Format (DF=17) and frame is 112 bits long.
// All known DF's >=16 are long (112 bits). All known DF's <=15 are short (56 bits). (In this case 112 bits)
// Msg structure consists of five main parts :|DF=17 (5 bits)|CA (3 bits)|ICAO (24 bits)|ME (56 bits)|CRC (24 bits)
// Msg structure consists of five main parts :|DF=17 (5 bits)|CA (3 bits)|ICAO (24 bits)|ME (56 bits)|CRC (24 bits)
// Airborne position msg struct, the ME (56 bits) = |TC,5 bits| SS, 2 bits | SAF, 1 | ALT, 12 | T, 1 | F, 1 | LAT-CPR, 17 | LON-CPR, 17
// TC : (1..4) : Aircraft identification Type Code. // TC : 9 to 18: Airbone postion and altitude // TC : 19 Airbone velocity .
// Airborne position message is used to broadcast the position and altitude of the aircraft. It has the Type Code 918 and 2022. (here , we use TC=11)
void encode_frame_pos(ADSBFrame& frame, const uint32_t ICAO_address, const int32_t altitude,
const float latitude, const float longitude, const uint32_t time_parity) {
uint32_t altitude_coded;
uint32_t lat, lon;
float delta_lat, yz, rlat, delta_lon, xz;
make_frame_adsb(frame, ICAO_address); // Header DF=17 (long frame 112 bits)
frame.push_byte(TC_AIRBORNE_POS << 3); // Bits 2~1: Surveillance Status, bit 0: NICsb
altitude_coded = (altitude + 1000) / 25; // 25ft precision, insert Q-bit (1)
altitude_coded = ((altitude_coded & 0x7F0) << 1) | 0x10 | (altitude_coded & 0x0F);
frame.push_byte(altitude_coded >> 4); // Top-most altitude bits
// CPR encoding
// Info from: http://antena.fe.uni-lj.si/literatura/Razno/Avionika/modes/CPRencoding.pdf
delta_lat = 360.0 / ((4.0 * NZ) - time_parity); // NZ = 15
yz = floor(CPR_MAX_VALUE * (cpr_mod(latitude, delta_lat) / delta_lat) + 0.5);
rlat = delta_lat * ((yz / CPR_MAX_VALUE) + floor(latitude / delta_lat));
if ((cpr_NL(rlat) - time_parity) > 0)
delta_lon = 360.0 / cpr_N(rlat, time_parity);
else
delta_lon = 360.0;
xz = floor(CPR_MAX_VALUE * (cpr_mod(longitude, delta_lon) / delta_lon) + 0.5);
lat = cpr_mod(yz, CPR_MAX_VALUE);
lon = cpr_mod(xz, CPR_MAX_VALUE);
frame.push_byte((altitude_coded << 4) | ((uint32_t)time_parity << 2) | (lat >> 15)); // T = 0
frame.push_byte(lat >> 7);
frame.push_byte((lat << 1) | (lon >> 16));
frame.push_byte(lon >> 8);
frame.push_byte(lon);
frame.make_CRC();
void encode_frame_pos(ADSBFrame& frame, const uint32_t ICAO_address, const int32_t altitude, const float latitude, const float longitude, const uint32_t time_parity) {
uint32_t altitude_coded;
uint32_t lat, lon;
float delta_lat, yz, rlat, delta_lon, xz;
make_frame_adsb(frame, ICAO_address); // Header DF=17 (long frame 112 bits)
frame.push_byte(TC_AIRBORNE_POS << 3); // Bits 2~1: Surveillance Status, bit 0: NICsb
altitude_coded = (altitude + 1000) / 25; // 25ft precision, insert Q-bit (1)
altitude_coded = ((altitude_coded & 0x7F0) << 1) | 0x10 | (altitude_coded & 0x0F);
frame.push_byte(altitude_coded >> 4); // Top-most altitude bits
// CPR encoding
// Info from: http://antena.fe.uni-lj.si/literatura/Razno/Avionika/modes/CPRencoding.pdf
delta_lat = 360.0 / ((4.0 * NZ) - time_parity); // NZ = 15
yz = floor(CPR_MAX_VALUE * (cpr_mod(latitude, delta_lat) / delta_lat) + 0.5);
rlat = delta_lat * ((yz / CPR_MAX_VALUE) + floor(latitude / delta_lat));
if ((cpr_NL(rlat) - time_parity) > 0)
delta_lon = 360.0 / cpr_N(rlat, time_parity);
else
delta_lon = 360.0;
xz = floor(CPR_MAX_VALUE * (cpr_mod(longitude, delta_lon) / delta_lon) + 0.5);
lat = cpr_mod(yz, CPR_MAX_VALUE);
lon = cpr_mod(xz, CPR_MAX_VALUE);
frame.push_byte((altitude_coded << 4) | ((uint32_t)time_parity << 2) | (lat >> 15)); // T = 0
frame.push_byte(lat >> 7);
frame.push_byte((lat << 1) | (lon >> 16));
frame.push_byte(lon >> 8);
frame.push_byte(lon);
frame.make_CRC();
}
// Decoding method from dump1090
adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd) {
uint8_t * raw_data;
uint32_t latcprE, latcprO, loncprE, loncprO;
float latE, latO, m, Dlon, cpr_lon_odd, cpr_lon_even, cpr_lat_odd, cpr_lat_even;
int ni;
adsb_pos position { false, 0, 0, 0 };
uint32_t time_even = frame_even.get_rx_timestamp();
uint32_t time_odd = frame_odd.get_rx_timestamp();
uint8_t * frame_data_even = frame_even.get_raw_data();
uint8_t * frame_data_odd = frame_odd.get_raw_data();
// Return most recent altitude
if (time_even > time_odd)
raw_data = frame_data_even;
else
raw_data = frame_data_odd;
uint8_t* raw_data;
uint32_t latcprE, latcprO, loncprE, loncprO;
float latE, latO, m, Dlon, cpr_lon_odd, cpr_lon_even, cpr_lat_odd, cpr_lat_even;
int ni;
adsb_pos position{false, 0, 0, 0};
// Q-bit must be present
if (raw_data[5] & 1)
position.altitude = ((((raw_data[5] & 0xFE) << 3) | ((raw_data[6] & 0xF0) >> 4)) * 25) - 1000;
uint32_t time_even = frame_even.get_rx_timestamp();
uint32_t time_odd = frame_odd.get_rx_timestamp();
uint8_t* frame_data_even = frame_even.get_raw_data();
uint8_t* frame_data_odd = frame_odd.get_raw_data();
// Position
latcprE = ((frame_data_even[6] & 3) << 15) | (frame_data_even[7] << 7) | (frame_data_even[8] >> 1);
loncprE = ((frame_data_even[8] & 1) << 16) | (frame_data_even[9] << 8) | frame_data_even[10];
latcprO = ((frame_data_odd[6] & 3) << 15) | (frame_data_odd[7] << 7) | (frame_data_odd[8] >> 1);
loncprO = ((frame_data_odd[8] & 1) << 16) | (frame_data_odd[9] << 8) | frame_data_odd[10];
// Return most recent altitude
if (time_even > time_odd)
raw_data = frame_data_even;
else
raw_data = frame_data_odd;
// Calculate the coefficients
cpr_lon_even = loncprE / CPR_MAX_VALUE;
cpr_lon_odd = loncprO / CPR_MAX_VALUE;
// Q-bit must be present
if (raw_data[5] & 1)
position.altitude = ((((raw_data[5] & 0xFE) << 3) | ((raw_data[6] & 0xF0) >> 4)) * 25) - 1000;
cpr_lat_odd = latcprO / CPR_MAX_VALUE;
cpr_lat_even = latcprE / CPR_MAX_VALUE;
// Position
latcprE = ((frame_data_even[6] & 3) << 15) | (frame_data_even[7] << 7) | (frame_data_even[8] >> 1);
loncprE = ((frame_data_even[8] & 1) << 16) | (frame_data_even[9] << 8) | frame_data_even[10];
// Compute latitude index
float j = floor(((59.0 * cpr_lat_even) - (60.0 * cpr_lat_odd)) + 0.5);
latE = (360.0 / 60.0) * (cpr_mod(j, 60) + cpr_lat_even);
latO = (360.0 / 59.0) * (cpr_mod(j, 59) + cpr_lat_odd);
latcprO = ((frame_data_odd[6] & 3) << 15) | (frame_data_odd[7] << 7) | (frame_data_odd[8] >> 1);
loncprO = ((frame_data_odd[8] & 1) << 16) | (frame_data_odd[9] << 8) | frame_data_odd[10];
if (latE >= 270) latE -= 360;
if (latO >= 270) latO -= 360;
// Calculate the coefficients
cpr_lon_even = loncprE / CPR_MAX_VALUE;
cpr_lon_odd = loncprO / CPR_MAX_VALUE;
// Both frames must be in the same latitude zone
if (cpr_NL(latE) != cpr_NL(latO))
return position;
cpr_lat_odd = latcprO / CPR_MAX_VALUE;
cpr_lat_even = latcprE / CPR_MAX_VALUE;
// Compute longitude
if (time_even > time_odd) {
// Use even frame2
ni = cpr_N(latE, 0);
Dlon = 360.0 / ni;
m = floor((cpr_lon_even * (cpr_NL(latE) - 1)) - (cpr_lon_odd * cpr_NL(latE)) + 0.5);
position.longitude = Dlon * (cpr_mod(m, ni) + cpr_lon_even);
position.latitude = latE;
} else {
// Use odd frame
ni = cpr_N(latO, 1);
Dlon = 360.0 / ni;
m = floor((cpr_lon_even * (cpr_NL(latO) - 1)) - (cpr_lon_odd * cpr_NL(latO)) + 0.5);
position.longitude = Dlon * (cpr_mod(m, ni) + cpr_lon_odd);
position.latitude = latO;
}
if (position.longitude >= 180) position.longitude -= 360;
position.valid = true;
// Compute latitude index
float j = floor(((59.0 * cpr_lat_even) - (60.0 * cpr_lat_odd)) + 0.5);
latE = (360.0 / 60.0) * (cpr_mod(j, 60) + cpr_lat_even);
latO = (360.0 / 59.0) * (cpr_mod(j, 59) + cpr_lat_odd);
return position;
if (latE >= 270) latE -= 360;
if (latO >= 270) latO -= 360;
// Both frames must be in the same latitude zone
if (cpr_NL(latE) != cpr_NL(latO))
return position;
// Compute longitude
if (time_even > time_odd) {
// Use even frame2
ni = cpr_N(latE, 0);
Dlon = 360.0 / ni;
m = floor((cpr_lon_even * (cpr_NL(latE) - 1)) - (cpr_lon_odd * cpr_NL(latE)) + 0.5);
position.longitude = Dlon * (cpr_mod(m, ni) + cpr_lon_even);
position.latitude = latE;
} else {
// Use odd frame
ni = cpr_N(latO, 1);
Dlon = 360.0 / ni;
m = floor((cpr_lon_even * (cpr_NL(latO) - 1)) - (cpr_lon_odd * cpr_NL(latO)) + 0.5);
position.longitude = Dlon * (cpr_mod(m, ni) + cpr_lon_odd);
position.latitude = latO;
}
if (position.longitude >= 180) position.longitude -= 360;
position.valid = true;
return position;
}
// An ADS-B frame is 112 bits long. Civil aircraft ADS-B message starts with the Downlink Format ,DF=17.
// Msg structure consists of five main parts :|DF=17 (5 bits)|CA (3 bits)|ICAO (24 bits)|ME (56 bits)|CRC (24 bits)
// Msg structure consists of five main parts :|DF=17 (5 bits)|CA (3 bits)|ICAO (24 bits)|ME (56 bits)|CRC (24 bits)
// Airborne velocities are all transmitted with Type Code 19 ( TC=19 ) inside ME (56 bits)
// [units] : speed is in knots, vertical rate climb / descend is in ft/min
void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint32_t speed,
const float angle, const int32_t v_rate) {
int32_t velo_ew, velo_ns;
uint32_t velo_ew_abs, velo_ns_abs, v_rate_coded_abs;
// To get NS and EW speeds from speed and bearing, a polar to cartesian conversion is enough
velo_ew = static_cast<int32_t>(sin_f32(DEG_TO_RAD(angle) ) * speed); // East direction, is the projection from West -> East is directly sin(angle=Compas Bearing) , (90º is the max +1, EAST) max velo_EW
velo_ns = static_cast<int32_t>(sin_f32( (pi/2 - DEG_TO_RAD(angle) ) ) * speed); // North direction,is the projection of North = cos(angle=Compas Bearing), cos(angle)= sen(90-angle) (0º is the max +1 NORTH) max velo_NS
v_rate_coded_abs = (abs(v_rate) / 64) + 1; //encoding vertical rate source. (Decoding, VR ft/min = (Decimal v_rate_value - 1)* 64)
velo_ew_abs = abs(velo_ew) + 1; // encoding Velo speed EW , when sign Direction is 0 (+): West->East, (-) 1: East->West
velo_ns_abs = abs(velo_ns) + 1; // encoding Velo speed NS , when sign Direction is 0 (+): South->North , (-) 1: North->South
make_frame_adsb(frame, ICAO_address); // Header DF=17 (long frame 112 bits)
// Airborne velocities are all transmitted with Type Code 19 ( TC=19, using 5 bits ,TC=19 [Binary: 10011]), the following 3 bits are Subt-type Code ,SC= 1,2,3,4
// SC Subtypes code 1 and 2 are used to report ground speeds of aircraft. (SC 3,4 to used to report true airspeed. SC 2,4 are for supersonic aircraft (not used in commercial airline).
frame.push_byte((TC_AIRBORNE_VELO << 3) | 1); // 1st byte , top 5 bits Type Code TC=19, and lower 3 bits (38-40 bits), SC=001 Subtype Code SC: 1 (subsonic) ,
// Message A, (ME bits from 14-35) , 22 bits = Sign ew(1 bit) + V_ew (10 bits) + Sign_ns (1 bit) + V_ns (10 bits)
// Vertical rate source bit VrSrc (ME bit 36) indicates source of the altitude measurements. GNSS altitude(0) / , barometric altitude(1).
// Vertical rate source direction,(ME bit 37) movement can be read from Svr bit , with 0 and 1 referring to climb and descent, respectively (ft/min)
void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint32_t speed, const float angle, const int32_t v_rate) {
int32_t velo_ew, velo_ns;
uint32_t velo_ew_abs, velo_ns_abs, v_rate_coded_abs;
// To get NS and EW speeds from speed and bearing, a polar to cartesian conversion is enough
velo_ew = static_cast<int32_t>(sin_f32(DEG_TO_RAD(angle)) * speed); // East direction, is the projection from West -> East is directly sin(angle=Compas Bearing) , (90º is the max +1, EAST) max velo_EW
velo_ns = static_cast<int32_t>(sin_f32((pi / 2 - DEG_TO_RAD(angle))) * speed); // North direction,is the projection of North = cos(angle=Compas Bearing), cos(angle)= sen(90-angle) (0º is the max +1 NORTH) max velo_NS
v_rate_coded_abs = (abs(v_rate) / 64) + 1; // encoding vertical rate source. (Decoding, VR ft/min = (Decimal v_rate_value - 1)* 64)
velo_ew_abs = abs(velo_ew) + 1; // encoding Velo speed EW , when sign Direction is 0 (+): West->East, (-) 1: East->West
velo_ns_abs = abs(velo_ns) + 1; // encoding Velo speed NS , when sign Direction is 0 (+): South->North , (-) 1: North->South
make_frame_adsb(frame, ICAO_address); // Header DF=17 (long frame 112 bits)
// Airborne velocities are all transmitted with Type Code 19 ( TC=19, using 5 bits ,TC=19 [Binary: 10011]), the following 3 bits are Subt-type Code ,SC= 1,2,3,4
// SC Subtypes code 1 and 2 are used to report ground speeds of aircraft. (SC 3,4 to used to report true airspeed. SC 2,4 are for supersonic aircraft (not used in commercial airline).
frame.push_byte((TC_AIRBORNE_VELO << 3) | 1); // 1st byte , top 5 bits Type Code TC=19, and lower 3 bits (38-40 bits), SC=001 Subtype Code SC: 1 (subsonic) ,
// Message A, (ME bits from 14-35) , 22 bits = Sign ew(1 bit) + V_ew (10 bits) + Sign_ns (1 bit) + V_ns (10 bits)
// Vertical rate source bit VrSrc (ME bit 36) indicates source of the altitude measurements. GNSS altitude(0) / , barometric altitude(1).
// Vertical rate source direction,(ME bit 37) movement can be read from Svr bit , with 0 and 1 referring to climb and descent, respectively (ft/min)
// The encoded vertical rate value VR can be computed using message (ME bits 38 to 46). If the 9-bit block contains all zeros, the vertical rate information is not available.
// + Sign VrSrc (vert rate src) (1 bit)+ VrSrc (9 bits).
frame.push_byte(((velo_ew < 0 ? 1 : 0) << 2) | (velo_ew_abs >> 8));
frame.push_byte(velo_ew_abs);
frame.push_byte(((velo_ns < 0 ? 1 : 0) << 7) | (velo_ns_abs >> 3));
frame.push_byte((velo_ns_abs << 5) | ((v_rate < 0 ? 1 : 0) << 3) | (v_rate_coded_abs >> 6)); // VrSrc = 0
frame.push_byte(v_rate_coded_abs << 2);
frame.push_byte(0);
frame.make_CRC();
// + Sign VrSrc (vert rate src) (1 bit)+ VrSrc (9 bits).
frame.push_byte(((velo_ew < 0 ? 1 : 0) << 2) | (velo_ew_abs >> 8));
frame.push_byte(velo_ew_abs);
frame.push_byte(((velo_ns < 0 ? 1 : 0) << 7) | (velo_ns_abs >> 3));
frame.push_byte((velo_ns_abs << 5) | ((v_rate < 0 ? 1 : 0) << 3) | (v_rate_coded_abs >> 6)); // VrSrc = 0
frame.push_byte(v_rate_coded_abs << 2);
frame.push_byte(0);
frame.make_CRC();
}
// Decoding method from dump1090
adsb_vel decode_frame_velo(ADSBFrame& frame){
adsb_vel velo {false, 0, 0, 0};
adsb_vel decode_frame_velo(ADSBFrame& frame) {
adsb_vel velo{false, 0, 0, 0};
uint8_t * frame_data = frame.get_raw_data();
uint8_t velo_type = frame.get_msg_sub();
uint8_t* frame_data = frame.get_raw_data();
uint8_t velo_type = frame.get_msg_sub();
if(velo_type >= 1 && velo_type <= 4){ //vertical rate is always present
if (velo_type >= 1 && velo_type <= 4) { // vertical rate is always present
velo.v_rate = (((frame_data[8] & 0x07 ) << 6) | ((frame_data[9] >> 2) - 1)) * 64;
velo.v_rate = (((frame_data[8] & 0x07) << 6) | ((frame_data[9] >> 2) - 1)) * 64;
if((frame_data[8] & 0x8) >> 3) velo.v_rate *= -1; //check v_rate sign
}
if ((frame_data[8] & 0x8) >> 3) velo.v_rate *= -1; // check v_rate sign
}
if(velo_type == 1 || velo_type == 2){ //Ground Speed
int32_t raw_ew = ((frame_data[5] & 0x03) << 8) | frame_data[6];
int32_t velo_ew = raw_ew - 1; //velocities are all offset by one (this is part of the spec)
if (velo_type == 1 || velo_type == 2) { // Ground Speed
int32_t raw_ew = ((frame_data[5] & 0x03) << 8) | frame_data[6];
int32_t velo_ew = raw_ew - 1; // velocities are all offset by one (this is part of the spec)
int32_t raw_ns = ((frame_data[7] & 0x7f) << 3) | (frame_data[8] >> 5);
int32_t velo_ns = raw_ns - 1;
int32_t raw_ns = ((frame_data[7] & 0x7f) << 3) | (frame_data[8] >> 5);
int32_t velo_ns = raw_ns - 1;
if (velo_type == 2){ // supersonic indicator so multiply by 4
velo_ew = velo_ew << 2;
velo_ns = velo_ns << 2;
}
if (velo_type == 2) { // supersonic indicator so multiply by 4
velo_ew = velo_ew << 2;
velo_ns = velo_ns << 2;
}
if(frame_data[5]&0x04) velo_ew *= -1; //check ew direction sign
if(frame_data[7]&0x80) velo_ns *= -1; //check ns direction sign
if (frame_data[5] & 0x04) velo_ew *= -1; // check ew direction sign
if (frame_data[7] & 0x80) velo_ns *= -1; // check ns direction sign
velo.speed = fast_int_magnitude(velo_ns,velo_ew);
if(velo.speed){
//calculate heading in degrees from ew/ns velocities
int16_t heading_temp = (int16_t)(int_atan2(velo_ew,velo_ns)); // Nearest degree
// We don't want negative values but a 0-360 scale.
if (heading_temp < 0) heading_temp += 360.0;
velo.heading = (uint16_t)heading_temp;
}
}else if(velo_type == 3 || velo_type == 4){ //Airspeed
velo.valid = frame_data[5] & (1<<2);
velo.heading = ((((frame_data[5] & 0x03)<<8) | frame_data[6]) * 45) << 7;
}
velo.speed = fast_int_magnitude(velo_ns, velo_ew);
return velo;
if (velo.speed) {
// calculate heading in degrees from ew/ns velocities
int16_t heading_temp = (int16_t)(int_atan2(velo_ew, velo_ns)); // Nearest degree
// We don't want negative values but a 0-360 scale.
if (heading_temp < 0) heading_temp += 360.0;
velo.heading = (uint16_t)heading_temp;
}
} else if (velo_type == 3 || velo_type == 4) { // Airspeed
velo.valid = frame_data[5] & (1 << 2);
velo.heading = ((((frame_data[5] & 0x03) << 8) | frame_data[6]) * 45) << 7;
}
return velo;
}
} /* namespace adsb */

View File

@@ -32,57 +32,56 @@
namespace adsb {
enum downlink_format {
DF_ADSB = 17,
DF_EHS_SQUAWK = 21, // DF 21: Comm-B with identity reply . Mode S enhanced surveillance of squawk + (MB_field = Track and turn report (BDS 5,0)).
// Confirmed that it is Detected correctly by dump1090. and sdrangel.
DF_ADSB = 17,
DF_EHS_SQUAWK = 21, // DF 21: Comm-B with identity reply . Mode S enhanced surveillance of squawk + (MB_field = Track and turn report (BDS 5,0)).
// Confirmed that it is Detected correctly by dump1090. and sdrangel.
};
enum type_code {
TC_IDENT = 4,
TC_AIRBORNE_POS = 11,
TC_AIRBORNE_VELO = 19
TC_IDENT = 4,
TC_AIRBORNE_POS = 11,
TC_AIRBORNE_VELO = 19
};
enum data_selector {
BDS_ID = 0x20,
BDS_ID_MARKS = 0x21,
BDS_INTENT = 0x40,
BDS_HEADING = 0x60
BDS_ID = 0x20,
BDS_ID_MARKS = 0x21,
BDS_INTENT = 0x40,
BDS_HEADING = 0x60
};
struct adsb_pos {
bool valid;
float latitude;
float longitude;
int32_t altitude;
bool valid;
float latitude;
float longitude;
int32_t altitude;
};
struct adsb_vel {
bool valid;
int32_t speed; //knot
uint16_t heading; //degree
int32_t v_rate; //ft/min
bool valid;
int32_t speed; // knot
uint16_t heading; // degree
int32_t v_rate; // ft/min
};
const float CPR_MAX_VALUE = 131072.0;
const float adsb_lat_lut[58] = {
10.47047130, 14.82817437, 18.18626357, 21.02939493,
23.54504487, 25.82924707, 27.93898710, 29.91135686,
31.77209708, 33.53993436, 35.22899598, 36.85025108,
38.41241892, 39.92256684, 41.38651832, 42.80914012,
44.19454951, 45.54626723, 46.86733252, 48.16039128,
49.42776439, 50.67150166, 51.89342469, 53.09516153,
54.27817472, 55.44378444, 56.59318756, 57.72747354,
58.84763776, 59.95459277, 61.04917774, 62.13216659,
63.20427479, 64.26616523, 65.31845310, 66.36171008,
67.39646774, 68.42322022, 69.44242631, 70.45451075,
71.45986473, 72.45884545, 73.45177442, 74.43893416,
75.42056257, 76.39684391, 77.36789461, 78.33374083,
79.29428225, 80.24923213, 81.19801349, 82.13956981,
83.07199445, 83.99173563, 84.89166191, 85.75541621,
86.53536998, 87.00000000
};
10.47047130, 14.82817437, 18.18626357, 21.02939493,
23.54504487, 25.82924707, 27.93898710, 29.91135686,
31.77209708, 33.53993436, 35.22899598, 36.85025108,
38.41241892, 39.92256684, 41.38651832, 42.80914012,
44.19454951, 45.54626723, 46.86733252, 48.16039128,
49.42776439, 50.67150166, 51.89342469, 53.09516153,
54.27817472, 55.44378444, 56.59318756, 57.72747354,
58.84763776, 59.95459277, 61.04917774, 62.13216659,
63.20427479, 64.26616523, 65.31845310, 66.36171008,
67.39646774, 68.42322022, 69.44242631, 70.45451075,
71.45986473, 72.45884545, 73.45177442, 74.43893416,
75.42056257, 76.39684391, 77.36789461, 78.33374083,
79.29428225, 80.24923213, 81.19801349, 82.13956981,
83.07199445, 83.99173563, 84.89166191, 85.75541621,
86.53536998, 87.00000000};
const float PI = 3.14159265358979323846;
@@ -93,20 +92,18 @@ void make_frame_adsb(ADSBFrame& frame, const uint32_t ICAO_address);
void encode_frame_id(ADSBFrame& frame, const uint32_t ICAO_address, const std::string& callsign);
std::string decode_frame_id(ADSBFrame& frame);
void encode_frame_pos(ADSBFrame& frame, const uint32_t ICAO_address, const int32_t altitude,
const float latitude, const float longitude, const uint32_t time_parity);
void encode_frame_pos(ADSBFrame& frame, const uint32_t ICAO_address, const int32_t altitude, const float latitude, const float longitude, const uint32_t time_parity);
adsb_pos decode_frame_pos(ADSBFrame& frame_even, ADSBFrame& frame_odd);
void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint32_t speed,
const float angle, const int32_t v_rate);
void encode_frame_velo(ADSBFrame& frame, const uint32_t ICAO_address, const uint32_t speed, const float angle, const int32_t v_rate);
adsb_vel decode_frame_velo(ADSBFrame& frame);
//void encode_frame_emergency(ADSBFrame& frame, const uint32_t ICAO_address, const uint8_t code);
// void encode_frame_emergency(ADSBFrame& frame, const uint32_t ICAO_address, const uint8_t code);
void encode_frame_squawk(ADSBFrame& frame, const uint16_t squawk);
} /* namespace adsb */
#endif/*__ADSB_H__*/
#endif /*__ADSB_H__*/

View File

@@ -19,7 +19,7 @@
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __ADSB_FRAME_H__
#define __ADSB_FRAME_H__
@@ -28,104 +28,104 @@
namespace adsb {
alignas(4) const uint8_t adsb_preamble[16] = { 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 };
alignas(4) const uint8_t adsb_preamble[16] = {1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0};
alignas(4) const char icao_id_lut[65] = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ##### ###############0123456789######";
class ADSBFrame {
public:
uint8_t get_DF() {
return (raw_data[0] >> 3);
}
public:
uint8_t get_DF() {
return (raw_data[0] >> 3);
}
uint8_t get_msg_type() {
return (raw_data[4] >> 3);
}
uint8_t get_msg_type() {
return (raw_data[4] >> 3);
}
uint8_t get_msg_sub() {
return (raw_data[4] & 7);
}
uint8_t get_msg_sub() {
return (raw_data[4] & 7);
}
uint32_t get_ICAO_address() {
return (raw_data[1] << 16) + (raw_data[2] << 8) + raw_data[3];
}
void set_rx_timestamp(uint32_t timestamp) {
rx_timestamp = timestamp;
}
uint32_t get_rx_timestamp() {
return rx_timestamp;
}
uint32_t get_ICAO_address() {
return (raw_data[1] << 16) + (raw_data[2] << 8) + raw_data[3];
}
void clear() {
index = 0;
memset(raw_data, 0, 14);
}
void set_rx_timestamp(uint32_t timestamp) {
rx_timestamp = timestamp;
}
uint32_t get_rx_timestamp() {
return rx_timestamp;
}
void push_byte(uint8_t byte) {
if (index >= 14)
return;
raw_data[index++] = byte;
}
void clear() {
index = 0;
memset(raw_data, 0, 14);
}
uint8_t * get_raw_data() const {
return (uint8_t* )raw_data;
}
void make_CRC() {
uint32_t computed_CRC = compute_CRC();
// Insert CRC in frame
raw_data[11] = (computed_CRC >> 16) & 0xFF;
raw_data[12] = (computed_CRC >> 8) & 0xFF;
raw_data[13] = computed_CRC & 0xFF;
}
void push_byte(uint8_t byte) {
if (index >= 14)
return;
bool check_CRC() {
uint32_t computed_CRC = compute_CRC();
if ((raw_data[11] != ((computed_CRC >> 16) & 0xFF)) ||
(raw_data[12] != ((computed_CRC >> 8) & 0xFF)) ||
(raw_data[13] != (computed_CRC & 0xFF))) return false;
return true;
}
bool empty() {
return (index == 0);
}
private:
static const uint8_t adsb_preamble[16];
static const char icao_id_lut[65];
alignas(4) uint8_t index { 0 };
alignas(4) uint8_t raw_data[14] { }; // 112 bits at most
uint32_t rx_timestamp { };
raw_data[index++] = byte;
}
uint32_t compute_CRC() {
uint8_t adsb_crc[14] = { 0 }; // Temp buffer
uint8_t b, c, s, bitn;
const uint32_t crc_poly = 0x1205FFF;
// Copy frame data
memcpy(adsb_crc, raw_data, 11);
// Compute CRC
for (c = 0; c < 11; c++) {
for (b = 0; b < 8; b++) {
if ((adsb_crc[c] << b) & 0x80) {
for (s = 0; s < 25; s++) {
bitn = (c * 8) + b + s;
if ((crc_poly >> s) & 1) adsb_crc[bitn >> 3] ^= (0x80 >> (bitn & 7));
}
}
}
}
return (adsb_crc[11] << 16) + (adsb_crc[12] << 8) + adsb_crc[13];
}
uint8_t* get_raw_data() const {
return (uint8_t*)raw_data;
}
void make_CRC() {
uint32_t computed_CRC = compute_CRC();
// Insert CRC in frame
raw_data[11] = (computed_CRC >> 16) & 0xFF;
raw_data[12] = (computed_CRC >> 8) & 0xFF;
raw_data[13] = computed_CRC & 0xFF;
}
bool check_CRC() {
uint32_t computed_CRC = compute_CRC();
if ((raw_data[11] != ((computed_CRC >> 16) & 0xFF)) ||
(raw_data[12] != ((computed_CRC >> 8) & 0xFF)) ||
(raw_data[13] != (computed_CRC & 0xFF))) return false;
return true;
}
bool empty() {
return (index == 0);
}
private:
static const uint8_t adsb_preamble[16];
static const char icao_id_lut[65];
alignas(4) uint8_t index{0};
alignas(4) uint8_t raw_data[14]{}; // 112 bits at most
uint32_t rx_timestamp{};
uint32_t compute_CRC() {
uint8_t adsb_crc[14] = {0}; // Temp buffer
uint8_t b, c, s, bitn;
const uint32_t crc_poly = 0x1205FFF;
// Copy frame data
memcpy(adsb_crc, raw_data, 11);
// Compute CRC
for (c = 0; c < 11; c++) {
for (b = 0; b < 8; b++) {
if ((adsb_crc[c] << b) & 0x80) {
for (s = 0; s < 25; s++) {
bitn = (c * 8) + b + s;
if ((crc_poly >> s) & 1) adsb_crc[bitn >> 3] ^= (0x80 >> (bitn & 7));
}
}
}
}
return (adsb_crc[11] << 16) + (adsb_crc[12] << 8) + adsb_crc[13];
}
};
} /* namespace adsb */
#endif/*__ADSB_FRAME_H__*/
#endif /*__ADSB_FRAME_H__*/

View File

@@ -36,12 +36,14 @@ namespace ais {
// sample=38.4k, deviation=2400, symbol=9600
// Length: 4 taps, 1 symbol, 1/4 cycle of sinusoid
// Gain: 1.0 (sinusoid / len(taps))
constexpr std::array<std::complex<float>, 4> square_taps_38k4_1t_p { {
{ 0.25000000f, 0.00000000f }, { 0.23096988f, 0.09567086f },
{ 0.17677670f, 0.17677670f }, { 0.09567086f, 0.23096988f },
} };
constexpr std::array<std::complex<float>, 4> square_taps_38k4_1t_p{{
{0.25000000f, 0.00000000f},
{0.23096988f, 0.09567086f},
{0.17677670f, 0.17677670f},
{0.09567086f, 0.23096988f},
}};
} /* namespace ais */
} /* namespace baseband */
#endif/*__AIS_BASEBAND_H__*/
#endif /*__AIS_BASEBAND_H__*/

View File

@@ -28,193 +28,190 @@
namespace ais {
struct PacketLengthRange {
constexpr PacketLengthRange(
) : min_bytes { 0 },
max_bytes { 0 }
{
}
constexpr PacketLengthRange()
: min_bytes{0},
max_bytes{0} {
}
constexpr PacketLengthRange(
const uint16_t min_bits,
const uint16_t max_bits
) : min_bytes { static_cast<uint8_t>(min_bits / 8U) },
max_bytes { static_cast<uint8_t>(max_bits / 8U) }
{
// static_assert((min_bits & 7) == 0, "minimum bits not a multiple of 8");
// static_assert((max_bits & 7) == 0, "minimum bits not a multiple of 8");
}
constexpr PacketLengthRange(
const uint16_t min_bits,
const uint16_t max_bits)
: min_bytes{static_cast<uint8_t>(min_bits / 8U)},
max_bytes{static_cast<uint8_t>(max_bits / 8U)} {
// static_assert((min_bits & 7) == 0, "minimum bits not a multiple of 8");
// static_assert((max_bits & 7) == 0, "minimum bits not a multiple of 8");
}
constexpr bool contains(const size_t bit_count) const {
return !is_above(bit_count) && !is_below(bit_count);
}
constexpr bool contains(const size_t bit_count) const {
return !is_above(bit_count) && !is_below(bit_count);
}
constexpr bool is_above(const size_t bit_count) const {
return (min() > bit_count);
}
constexpr bool is_above(const size_t bit_count) const {
return (min() > bit_count);
}
constexpr bool is_below(const size_t bit_count) const {
return (max() < bit_count);
}
constexpr bool is_below(const size_t bit_count) const {
return (max() < bit_count);
}
constexpr size_t min() const {
return min_bytes * 8;
}
constexpr size_t max() const {
return max_bytes * 8;
}
constexpr size_t min() const {
return min_bytes * 8;
}
private:
const uint8_t min_bytes;
const uint8_t max_bytes;
constexpr size_t max() const {
return max_bytes * 8;
}
private:
const uint8_t min_bytes;
const uint8_t max_bytes;
};
static constexpr std::array<PacketLengthRange, 64> packet_length_range { {
{ 0, 0 }, // 0
{ 168, 168 }, // 1
{ 168, 168 }, // 2
{ 168, 168 }, // 3
{ 168, 168 }, // 4
{ 424, 424 }, // 5
{ 0, 0 }, // 6
{ 0, 0 }, // 7
{ 0, 1008 }, // 8
{ 0, 0 }, // 9
{ 0, 0 }, // 10
{ 0, 0 }, // 11
{ 0, 0 }, // 12
{ 0, 0 }, // 13
{ 0, 0 }, // 14
{ 0, 0 }, // 15
{ 0, 0 }, // 16
{ 0, 0 }, // 17
{ 168, 168 }, // 18
{ 0, 0 }, // 19
{ 72, 160 }, // 20
{ 272, 360 }, // 21
{ 168, 168 }, // 22
{ 160, 160 }, // 23
{ 160, 168 }, // 24
{ 0, 168 }, // 25
{ 0, 0 }, // 26
{ 0, 0 }, // 27
{ 0, 0 }, // 28
{ 0, 0 }, // 29
{ 0, 0 }, // 30
{ 0, 0 }, // 31
} };
static constexpr std::array<PacketLengthRange, 64> packet_length_range{{
{0, 0}, // 0
{168, 168}, // 1
{168, 168}, // 2
{168, 168}, // 3
{168, 168}, // 4
{424, 424}, // 5
{0, 0}, // 6
{0, 0}, // 7
{0, 1008}, // 8
{0, 0}, // 9
{0, 0}, // 10
{0, 0}, // 11
{0, 0}, // 12
{0, 0}, // 13
{0, 0}, // 14
{0, 0}, // 15
{0, 0}, // 16
{0, 0}, // 17
{168, 168}, // 18
{0, 0}, // 19
{72, 160}, // 20
{272, 360}, // 21
{168, 168}, // 22
{160, 160}, // 23
{160, 168}, // 24
{0, 168}, // 25
{0, 0}, // 26
{0, 0}, // 27
{0, 0}, // 28
{0, 0}, // 29
{0, 0}, // 30
{0, 0}, // 31
}};
struct PacketLengthValidator {
constexpr bool operator()(const uint_fast8_t message_id, const size_t length) const {
return packet_length_range[message_id].contains(length);
}
constexpr bool operator()(const uint_fast8_t message_id, const size_t length) const {
return packet_length_range[message_id].contains(length);
}
};
struct PacketTooLong {
constexpr bool operator()(const uint_fast8_t message_id, const size_t length) const {
return packet_length_range[message_id].is_below(length);
}
constexpr bool operator()(const uint_fast8_t message_id, const size_t length) const {
return packet_length_range[message_id].is_below(length);
}
};
static constexpr char char_to_ascii(const uint8_t c) {
return (c ^ 32) + 32;
return (c ^ 32) + 32;
}
size_t Packet::length() const {
return packet_.size();
return packet_.size();
}
bool Packet::is_valid() const {
return length_valid() && crc_ok();
return length_valid() && crc_ok();
}
Timestamp Packet::received_at() const {
return packet_.timestamp();
return packet_.timestamp();
}
uint32_t Packet::message_id() const {
return field_.read(0, 6);
return field_.read(0, 6);
}
MMSI Packet::user_id() const {
return field_.read(8, 30);
return field_.read(8, 30);
}
MMSI Packet::source_id() const {
return field_.read(8, 30);
return field_.read(8, 30);
}
uint32_t Packet::read(const size_t start_bit, const size_t length) const {
return field_.read(start_bit, length);
return field_.read(start_bit, length);
}
std::string Packet::text(
const size_t start_bit,
const size_t character_count
) const {
std::string result;
result.reserve(character_count);
const size_t character_length = 6;
const size_t end_bit = start_bit + character_count * character_length;
for(size_t i=start_bit; i<end_bit; i+=character_length) {
result += char_to_ascii(field_.read(i, character_length));
}
const size_t start_bit,
const size_t character_count) const {
std::string result;
result.reserve(character_count);
return result;
const size_t character_length = 6;
const size_t end_bit = start_bit + character_count * character_length;
for (size_t i = start_bit; i < end_bit; i += character_length) {
result += char_to_ascii(field_.read(i, character_length));
}
return result;
}
DateTime Packet::datetime(const size_t start_bit) const {
return {
static_cast<uint16_t>(field_.read(start_bit + 0, 14)),
static_cast<uint8_t >(field_.read(start_bit + 14, 4)),
static_cast<uint8_t >(field_.read(start_bit + 18, 5)),
static_cast<uint8_t >(field_.read(start_bit + 23, 5)),
static_cast<uint8_t >(field_.read(start_bit + 28, 6)),
static_cast<uint8_t >(field_.read(start_bit + 34, 6)),
};
return {
static_cast<uint16_t>(field_.read(start_bit + 0, 14)),
static_cast<uint8_t>(field_.read(start_bit + 14, 4)),
static_cast<uint8_t>(field_.read(start_bit + 18, 5)),
static_cast<uint8_t>(field_.read(start_bit + 23, 5)),
static_cast<uint8_t>(field_.read(start_bit + 28, 6)),
static_cast<uint8_t>(field_.read(start_bit + 34, 6)),
};
}
Latitude Packet::latitude(const size_t start_bit) const {
return field_.read(start_bit, 27);
return field_.read(start_bit, 27);
}
Longitude Packet::longitude(const size_t start_bit) const {
return field_.read(start_bit, 28);
return field_.read(start_bit, 28);
}
bool Packet::crc_ok() const {
CRCReader field_crc { packet_ };
CRC<16> ais_fcs { 0x1021, 0xffff, 0xffff };
for(size_t i=0; i<data_length(); i+=8) {
ais_fcs.process_byte(field_crc.read(i, 8));
}
CRCReader field_crc{packet_};
CRC<16> ais_fcs{0x1021, 0xffff, 0xffff};
return (ais_fcs.checksum() == (unsigned)field_crc.read(data_length(), fcs_length));
for (size_t i = 0; i < data_length(); i += 8) {
ais_fcs.process_byte(field_crc.read(i, 8));
}
return (ais_fcs.checksum() == (unsigned)field_crc.read(data_length(), fcs_length));
}
size_t Packet::data_and_fcs_length() const {
// Subtract end flag (8 bits) - one unstuffing bit (occurs during end flag).
return length() - 7;
// Subtract end flag (8 bits) - one unstuffing bit (occurs during end flag).
return length() - 7;
}
size_t Packet::data_length() const {
return data_and_fcs_length() - fcs_length;
return data_and_fcs_length() - fcs_length;
}
bool Packet::length_valid() const {
const size_t extra_bits = data_and_fcs_length() & 7;
if( extra_bits != 0 ) {
return false;
}
const size_t extra_bits = data_and_fcs_length() & 7;
if (extra_bits != 0) {
return false;
}
const PacketLengthValidator packet_length_valid;
if( !packet_length_valid(message_id(), data_length()) ) {
return false;
}
const PacketLengthValidator packet_length_valid;
if (!packet_length_valid(message_id(), data_length())) {
return false;
}
return true;
return true;
}
} /* namespace ais */

View File

@@ -32,60 +32,56 @@
namespace ais {
struct DateTime {
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
};
template<size_t FieldSize, int32_t DegMax, uint32_t NAValue>
template <size_t FieldSize, int32_t DegMax, uint32_t NAValue>
struct LatLonBase {
constexpr LatLonBase(
) : LatLonBase { raw_not_available }
{
}
constexpr LatLonBase(
const int32_t raw
) : raw_ { raw }
{
}
constexpr LatLonBase()
: LatLonBase{raw_not_available} {
}
constexpr LatLonBase(
const LatLonBase& other
) : raw_ { other.raw_ }
{
}
LatLonBase& operator=( const LatLonBase &)=default;
constexpr LatLonBase(
const int32_t raw)
: raw_{raw} {
}
int32_t normalized() const {
return static_cast<int32_t>(raw() << sign_extend_shift) / (1 << sign_extend_shift);
}
constexpr LatLonBase(
const LatLonBase& other)
: raw_{other.raw_} {
}
int32_t raw() const {
return raw_;
}
LatLonBase& operator=(const LatLonBase&) = default;
bool is_not_available() const {
return raw() == raw_not_available;
}
int32_t normalized() const {
return static_cast<int32_t>(raw() << sign_extend_shift) / (1 << sign_extend_shift);
}
bool is_valid() const {
return (normalized() >= raw_valid_min) && (normalized() <= raw_valid_max);
}
int32_t raw() const {
return raw_;
}
private:
int32_t raw_;
bool is_not_available() const {
return raw() == raw_not_available;
}
static constexpr size_t sign_extend_shift = 32 - FieldSize;
bool is_valid() const {
return (normalized() >= raw_valid_min) && (normalized() <= raw_valid_max);
}
static constexpr int32_t raw_not_available = NAValue;
static constexpr int32_t raw_valid_min = -DegMax * 60 * 10000;
static constexpr int32_t raw_valid_max = DegMax * 60 * 10000;
private:
int32_t raw_;
static constexpr size_t sign_extend_shift = 32 - FieldSize;
static constexpr int32_t raw_not_available = NAValue;
static constexpr int32_t raw_valid_min = -DegMax * 60 * 10000;
static constexpr int32_t raw_valid_max = DegMax * 60 * 10000;
};
using Latitude = LatLonBase<27, 90, 0x3412140>;
@@ -99,50 +95,49 @@ using TrueHeading = uint16_t;
using MMSI = uint32_t;
class Packet {
public:
constexpr Packet(
const baseband::Packet& packet
) : packet_ { packet },
field_ { packet_ }
{
}
public:
constexpr Packet(
const baseband::Packet& packet)
: packet_{packet},
field_{packet_} {
}
size_t length() const;
bool is_valid() const;
size_t length() const;
Timestamp received_at() const;
bool is_valid() const;
uint32_t message_id() const;
MMSI user_id() const;
MMSI source_id() const;
Timestamp received_at() const;
uint32_t read(const size_t start_bit, const size_t length) const;
uint32_t message_id() const;
MMSI user_id() const;
MMSI source_id() const;
std::string text(const size_t start_bit, const size_t character_count) const;
uint32_t read(const size_t start_bit, const size_t length) const;
DateTime datetime(const size_t start_bit) const;
std::string text(const size_t start_bit, const size_t character_count) const;
Latitude latitude(const size_t start_bit) const;
Longitude longitude(const size_t start_bit) const;
DateTime datetime(const size_t start_bit) const;
bool crc_ok() const;
Latitude latitude(const size_t start_bit) const;
Longitude longitude(const size_t start_bit) const;
private:
using Reader = FieldReader<baseband::Packet, BitRemapByteReverse>;
using CRCReader = FieldReader<baseband::Packet, BitRemapNone>;
const baseband::Packet packet_;
const Reader field_;
bool crc_ok() const;
const size_t fcs_length = 16;
private:
using Reader = FieldReader<baseband::Packet, BitRemapByteReverse>;
using CRCReader = FieldReader<baseband::Packet, BitRemapNone>;
size_t data_and_fcs_length() const;
size_t data_length() const;
const baseband::Packet packet_;
const Reader field_;
bool length_valid() const;
const size_t fcs_length = 16;
size_t data_and_fcs_length() const;
size_t data_length() const;
bool length_valid() const;
};
} /* namespace ais */
#endif/*__AIS_PACKET_H__*/
#endif /*__AIS_PACKET_H__*/

View File

@@ -30,550 +30,543 @@ namespace asahi_kasei {
namespace ak4951 {
void AK4951::configure_digital_interface_i2s() {
// Configure for external slave mode.
map.r.mode_control_1.DIF = 0b11; // I2S compatible
map.r.mode_control_1.BCKO = 0; // BICK = 32fs
update(Register::ModeControl1);
// Configure for external slave mode.
map.r.mode_control_1.DIF = 0b11; // I2S compatible
map.r.mode_control_1.BCKO = 0; // BICK = 32fs
update(Register::ModeControl1);
map.r.mode_control_2.CM = 0b00; // MCKI = 256fs
map.r.mode_control_2.FS = 0b1011; // fs = 48kHz
update(Register::ModeControl2);
map.r.mode_control_2.CM = 0b00; // MCKI = 256fs
map.r.mode_control_2.FS = 0b1011; // fs = 48kHz
update(Register::ModeControl2);
}
void AK4951::configure_digital_interface_external_slave() {
map.r.power_management_2.MS = 0; // Slave mode
map.r.power_management_2.PMPLL = 0; // EXT mode
update(Register::PowerManagement2);
map.r.power_management_2.MS = 0; // Slave mode
map.r.power_management_2.PMPLL = 0; // EXT mode
update(Register::PowerManagement2);
}
void AK4951::configure_digital_interface_external_master() {
map.r.power_management_2.MS = 1; // Master mode
map.r.power_management_2.PMPLL = 0; // EXT mode
update(Register::PowerManagement2);
map.r.power_management_2.MS = 1; // Master mode
map.r.power_management_2.PMPLL = 0; // EXT mode
update(Register::PowerManagement2);
}
void AK4951::init() {
reset();
reset();
// Write dummy address to "release" the reset.
write(0x00, 0x00);
// Write dummy address to "release" the reset.
write(0x00, 0x00);
configure_digital_interface_i2s();
configure_digital_interface_external_slave();
configure_digital_interface_i2s();
configure_digital_interface_external_slave();
map.r.power_management_1.PMVCM = 1;
update(Register::PowerManagement1);
map.r.power_management_1.PMVCM = 1;
update(Register::PowerManagement1);
// Headphone output is hi-Z when not active, reduces crosstalk from speaker output.
map.r.beep_control.HPZ = 1;
update(Register::BeepControl);
// Headphone output is hi-Z when not active, reduces crosstalk from speaker output.
map.r.beep_control.HPZ = 1;
update(Register::BeepControl);
// Pause for VCOM and REGFIL pins to stabilize.
chThdSleepMilliseconds(2);
// Pause for VCOM and REGFIL pins to stabilize.
chThdSleepMilliseconds(2);
headphone_mute();
headphone_mute();
// SPK-Amp gain setting: SPKG1-0 bits = “00” → “01”
map.r.signal_select_2.SPKG = 0b01;
update(Register::SignalSelect2);
// SPK-Amp gain setting: SPKG1-0 bits = “00” → “01”
map.r.signal_select_2.SPKG = 0b01;
update(Register::SignalSelect2);
map.r.signal_select_3.MONO = 0b00;
update(Register::SignalSelect3);
map.r.signal_select_3.MONO = 0b00;
update(Register::SignalSelect3);
map.r.digital_filter_mode.PFSDO = 0; // ADC bypass digital filter block.
map.r.digital_filter_mode.ADCPF = 1; // ADC output
map.r.digital_filter_mode.PFDAC = 0b00; // SDTI
update(Register::DigitalFilterMode);
map.r.digital_filter_mode.PFSDO = 0; // ADC bypass digital filter block.
map.r.digital_filter_mode.ADCPF = 1; // ADC output
map.r.digital_filter_mode.PFDAC = 0b00; // SDTI
update(Register::DigitalFilterMode);
// Set up FRN, FRATT and ADRST1-0 bits (Addr = 09H)
// map.r.timer_select.FRN = 0;
// map.r.timer_select.FRATT = 0;
// map.r.timer_select.ADRST = 0b00;
// update(Register::TimerSelect);
// Set up FRN, FRATT and ADRST1-0 bits (Addr = 09H)
// map.r.timer_select.FRN = 0;
// map.r.timer_select.FRATT = 0;
// map.r.timer_select.ADRST = 0b00;
// update(Register::TimerSelect);
// Set up ALC mode (Addr = 0AH, 0BH)
// map.r.alc_timer_select. = ;
// update(Register::ALCTimerSelect);
// map.r.alc_mode_control_1. = ;
// update(Register::ALCModeControl1);
// Set up ALC mode (Addr = 0AH, 0BH)
// map.r.alc_timer_select. = ;
// update(Register::ALCTimerSelect);
// map.r.alc_mode_control_1. = ;
// update(Register::ALCModeControl1);
// Set up REF value of ALC (Addr = 0CH)
// map.r.alc_mode_control_2. = ;
// update(Register::ALCModeControl2);
// Set up REF value of ALC (Addr = 0CH)
// map.r.alc_mode_control_2. = ;
// update(Register::ALCModeControl2);
// Set up IVOL value of ALC operation start (Addr = 0DH)
// map.r.l_ch_input_volume_control. = ;
// update(Register::LchInputVolumeControl);
// map.r.r_ch_input_volume_control. = ;
// update(Register::RchInputVolumeControl);
// Set up IVOL value of ALC operation start (Addr = 0DH)
// map.r.l_ch_input_volume_control. = ;
// update(Register::LchInputVolumeControl);
// map.r.r_ch_input_volume_control. = ;
// update(Register::RchInputVolumeControl);
// Set up the output digital volume. (Addr = 13H)
// set_headphone_volume(...);
// Set up the output digital volume. (Addr = 13H)
// set_headphone_volume(...);
// Set up Programmable Filter Path: PFDAC1-0 bits=“01”, PFSDO=ADCPF bits=“0” (Addr = 1DH)
// map.r.digital_filter_mode.PFDAC = 0b01;
// update(Register::DigitalFilterMode);
// Set up Programmable Filter Path: PFDAC1-0 bits=“01”, PFSDO=ADCPF bits=“0” (Addr = 1DH)
// map.r.digital_filter_mode.PFDAC = 0b01;
// update(Register::DigitalFilterMode);
}
bool AK4951::detected() {
return reset();
return reset();
}
bool AK4951::reset() {
io.audio_reset_state(true);
io.audio_reset_state(true);
// PDN# pulse must be >200ns
chThdSleepMicroseconds(10);
// PDN# pulse must be >200ns
chThdSleepMicroseconds(10);
io.audio_reset_state(false);
io.audio_reset_state(false);
return true;
return true;
}
void AK4951::set_digtal_volume_control(const reg_t value) {
map.r.l_ch_digital_volume_control.DV = value;
update(Register::LchDigitalVolumeControl);
map.r.l_ch_digital_volume_control.DV = value;
update(Register::LchDigitalVolumeControl);
}
void AK4951::set_headphone_volume(const volume_t volume) {
const auto normalized = headphone_gain_range().normalize(volume);
auto n = normalized.centibel() / 5;
set_digtal_volume_control(0xcb - n);
const auto normalized = headphone_gain_range().normalize(volume);
auto n = normalized.centibel() / 5;
set_digtal_volume_control(0xcb - n);
}
void AK4951::headphone_mute() {
set_digtal_volume_control(0xff);
set_digtal_volume_control(0xff);
}
void AK4951::set_dac_power(const bool enable) {
map.r.power_management_1.PMDAC = enable;
update(Register::PowerManagement1);
map.r.power_management_1.PMDAC = enable;
update(Register::PowerManagement1);
}
void AK4951::set_headphone_power(const bool enable) {
map.r.power_management_2.PMHPL = map.r.power_management_2.PMHPR = enable;
update(Register::PowerManagement2);
map.r.power_management_2.PMHPL = map.r.power_management_2.PMHPR = enable;
update(Register::PowerManagement2);
}
void AK4951::set_speaker_power(const bool enable) {
map.r.power_management_2.PMSL = enable;
update(Register::PowerManagement2);
map.r.power_management_2.PMSL = enable;
update(Register::PowerManagement2);
}
void AK4951::select_line_out(const LineOutSelect value) {
map.r.power_management_2.LOSEL = (value == LineOutSelect::Line) ? 1 : 0;
update(Register::PowerManagement2);
map.r.power_management_2.LOSEL = (value == LineOutSelect::Line) ? 1 : 0;
update(Register::PowerManagement2);
}
void AK4951::headphone_enable() {
set_dac_power(true);
set_headphone_power(true);
set_dac_power(true);
set_headphone_power(true);
// Wait for headphone amplifier charge pump power-up.
chThdSleepMilliseconds(35);
// Wait for headphone amplifier charge pump power-up.
chThdSleepMilliseconds(35);
}
void AK4951::headphone_disable() {
set_headphone_power(false);
set_dac_power(false);
set_headphone_power(false);
set_dac_power(false);
}
void AK4951::speaker_enable() {
// Set up the path of DAC → SPK-Amp: DACS bit = “0” → “1”
map.r.signal_select_1.DACS = 1;
update(Register::SignalSelect1);
// Set up the path of DAC → SPK-Amp: DACS bit = “0” → “1”
map.r.signal_select_1.DACS = 1;
update(Register::SignalSelect1);
// Enter Speaker-Amp Output Mode: LOSEL bit = “0”
select_line_out(LineOutSelect::Speaker);
// Enter Speaker-Amp Output Mode: LOSEL bit = “0”
select_line_out(LineOutSelect::Speaker);
// Power up DAC, Programmable Filter and Speaker-Amp: PMDAC=PMPFIL=PMSL bits=“0”→“1”
set_dac_power(true);
// map.r.power_management_1.PMPFIL = 1;
// update(Register::PowerManagement1);
set_speaker_power(true);
// Power up DAC, Programmable Filter and Speaker-Amp: PMDAC=PMPFIL=PMSL bits=“0”→“1”
set_dac_power(true);
// map.r.power_management_1.PMPFIL = 1;
// update(Register::PowerManagement1);
set_speaker_power(true);
// Time from PMSL=1 to SLPSN=1.
chThdSleepMilliseconds(1);
// Time from PMSL=1 to SLPSN=1.
chThdSleepMilliseconds(1);
// Exit the power-save mode of Speaker-Amp: SLPSN bit = “0” → “1”
map.r.signal_select_1.SLPSN = 1;
update(Register::SignalSelect1);
// Exit the power-save mode of Speaker-Amp: SLPSN bit = “0” → “1”
map.r.signal_select_1.SLPSN = 1;
update(Register::SignalSelect1);
}
void AK4951::speaker_disable() {
// Enter Speaker-Amp Power Save Mode: SLPSN bit = “1” → “0”
map.r.signal_select_1.SLPSN = 0;
update(Register::SignalSelect1);
// Enter Speaker-Amp Power Save Mode: SLPSN bit = “1” → “0”
map.r.signal_select_1.SLPSN = 0;
update(Register::SignalSelect1);
// Disable the path of DAC → SPK-Amp: DACS bit = “1” → “0”
map.r.signal_select_1.DACS = 0;
update(Register::SignalSelect1);
// Disable the path of DAC → SPK-Amp: DACS bit = “1” → “0”
map.r.signal_select_1.DACS = 0;
update(Register::SignalSelect1);
// Power down DAC, Programmable Filter and speaker: PMDAC=PMPFIL=PMSL bits= “1”→“0”
set_dac_power(false);
// map.r.power_management_1.PMPFIL = 0;
// update(Register::PowerManagement1);
set_speaker_power(false);
// Power down DAC, Programmable Filter and speaker: PMDAC=PMPFIL=PMSL bits= “1”→“0”
set_dac_power(false);
// map.r.power_management_1.PMPFIL = 0;
// update(Register::PowerManagement1);
set_speaker_power(false);
}
void AK4951::microphone_enable(int8_t alc_mode) {
// alc_mode =0 = (OFF =same as original code = NOT using AK4951 Programmable digital filter block),
// alc_mode >1 (with DIGITAL FILTER BLOCK , example : 1:(+12dB) , 2:(+9dB)", 3:(+6dB), ...)
// alc_mode =0 = (OFF =same as original code = NOT using AK4951 Programmable digital filter block),
// alc_mode >1 (with DIGITAL FILTER BLOCK , example : 1:(+12dB) , 2:(+9dB)", 3:(+6dB), ...)
// map.r.digital_mic.DMIC = 0; // originally commented code
// update(Register::DigitalMic); // originally commented code
// map.r.digital_mic.DMIC = 0; // originally commented code
// update(Register::DigitalMic); // originally commented code
uint_fast8_t mgain =0b0111; // Pre-amp mic (Original code, =0b0111 (+21dB's=7x3dBs),(Max is NOT 0b1111!, it is 0b1010=+30dBs=10x3dBs)
uint_fast8_t mgain = 0b0111; // Pre-amp mic (Original code, =0b0111 (+21dB's=7x3dBs),(Max is NOT 0b1111!, it is 0b1010=+30dBs=10x3dBs)
map.r.signal_select_2.INL = 0b01; // Lch input signal = LIN2 , our ext. MONO MIC is connected here LIN2 in Portapack.
map.r.signal_select_2.INR = 0b01; // Rch input signal = RIN2 , Not used ,not connected ,but no problem.
map.r.signal_select_2.MICL = 0; // MPWR = 2.4V (it has two possible settings , 2.4V or 2.0V) , (majority smarthphones around 2V , range 1V-5V)
update(Register::SignalSelect2);
map.r.signal_select_2.INL = 0b01; // Lch input signal = LIN2 , our ext. MONO MIC is connected here LIN2 in Portapack.
map.r.signal_select_2.INR = 0b01; // Rch input signal = RIN2 , Not used ,not connected ,but no problem.
map.r.signal_select_2.MICL = 0; // MPWR = 2.4V (it has two possible settings , 2.4V or 2.0V) , (majority smarthphones around 2V , range 1V-5V)
update(Register::SignalSelect2);
// ------Common code part, = original setting conditions, it is fine for all user-GUI alc_modes: OFF , and ALC modes .*/
map.r.digital_filter_select_1.HPFAD = 1; // HPF1 ON (after ADC);page 40 datasheet, HPFAD bit controls the ON/OFF of the HPF1 (HPF ON is recommended).
map.r.digital_filter_select_1.HPFC = 0b11; // HPF Cut off frequency of high pass filter from 236.8 Hz @fs=48k ("00":3.7Hz, "01":14,8Hz, "10":118,4Hz)
update(Register::DigitalFilterSelect1);
// ------Common code part, = original setting conditions, it is fine for all user-GUI alc_modes: OFF , and ALC modes .*/
map.r.digital_filter_select_1.HPFAD = 1; // HPF1 ON (after ADC);page 40 datasheet, HPFAD bit controls the ON/OFF of the HPF1 (HPF ON is recommended).
map.r.digital_filter_select_1.HPFC = 0b11; // HPF Cut off frequency of high pass filter from 236.8 Hz @fs=48k ("00":3.7Hz, "01":14,8Hz, "10":118,4Hz)
update(Register::DigitalFilterSelect1);
// map.r.r_ch_mic_gain_setting.MGR = 0x80; // Microphone sensitivity correction = 0dB., (not used by now , original code cond.)
// update(Register::RchMicGainSetting); // (those two lines , not activated, same as original)
// map.r.r_ch_mic_gain_setting.MGR = 0x80; // Microphone sensitivity correction = 0dB., (not used by now , original code cond.)
// update(Register::RchMicGainSetting); // (those two lines , not activated, same as original)
// pre-load 4 byes LPF coefficicients (.lpf_coefficient_0,1,2,3), FSA 14..0, FSB 14..0 , (fcut initial 6kHz, fs 48Khz).
// it will be default pre-loading coeff. for al ALC modes, LPF bit is activated down, for all ALC digital modes.
map.r.lpf_coefficient_0.l = 0x5F; // Pre-loading here LPF 6kHz, 1st Order from digital Block , Fc=6000 Hz, fs = 48khz
map.r.lpf_coefficient_1.h = 0x09; // LPF bit is activated down, for all ALC digital modes.
map.r.lpf_coefficient_2.l = 0xBF; // Writting reg to AK4951, with "update", following instructions.
map.r.lpf_coefficient_3.h = 0x32;
// pre-load 4 byes LPF coefficicients (.lpf_coefficient_0,1,2,3), FSA 14..0, FSB 14..0 , (fcut initial 6kHz, fs 48Khz).
// it will be default pre-loading coeff. for al ALC modes, LPF bit is activated down, for all ALC digital modes.
map.r.lpf_coefficient_0.l = 0x5F; // Pre-loading here LPF 6kHz, 1st Order from digital Block , Fc=6000 Hz, fs = 48khz
map.r.lpf_coefficient_1.h = 0x09; // LPF bit is activated down, for all ALC digital modes.
map.r.lpf_coefficient_2.l = 0xBF; // Writting reg to AK4951, with "update", following instructions.
map.r.lpf_coefficient_3.h = 0x32;
update(Register::LPFCoefficient0); // Writing pre-loaded 4 bytes LPF CoefFiecients 14 bits (FSA13..0, FSB13..0
update(Register::LPFCoefficient1); // In this case , LPF 6KHz , when we activate the LPF block.
update(Register::LPFCoefficient2);
update(Register::LPFCoefficient3);
update(Register::LPFCoefficient0); // Writing pre-loaded 4 bytes LPF CoefFiecients 14 bits (FSA13..0, FSB13..0
update(Register::LPFCoefficient1); // In this case , LPF 6KHz , when we activate the LPF block.
update(Register::LPFCoefficient2);
update(Register::LPFCoefficient3);
// Reset , setting OFF all 5 x Digital Equalizer filters
map.r.digital_filter_select_3.EQ1 = 0; // EQ1 Coeffic Setting , (0: Disable-default, audio data passes EQ1 block by 0dB gain). When EQ1="1”, the settings of E1A15-0, E1B15-0 and E1C15-0 bits are enabled
map.r.digital_filter_select_3.EQ2 = 0; // EQ2 Coeffic Setting , (0: Disable-default, audio data passes EQ2 block by 0dB gain). When EQ2="1”, the settings of E2A15-0, E2B15-0 and E2C15-0 bits are enabled
map.r.digital_filter_select_3.EQ3 = 0; // EQ3 Coeffic Setting , (0: Disable-default, audio data passes EQ3 block by 0dB gain). When EQ3="1”, the settings of E3A15-0, E3B15-0 and E3C15-0 bits are enabled
map.r.digital_filter_select_3.EQ4 = 0; // EQ4 Coeffic Setting , (0: Disable-default, audio data passes EQ4 block by 0dB gain). When EQ4="1”, the settings of E4A15-0, E4B15-0 and E4C15-0 bits are enabled
map.r.digital_filter_select_3.EQ5 = 0; // EQ5 Coeffic Setting , (0: Disable-default, audio data passes EQ5 block by 0dB gain). When EQ5="1”, the settings of E5A15-0, E5B15-0 and E5C15-0 bits are enabled
update(Register::DigitalFilterSelect3); // A,B,C EQ1 Coefficients are already pre-loaded in ak4951.hpp
// Reset , setting OFF all 5 x Digital Equalizer filters
map.r.digital_filter_select_3.EQ1 = 0; // EQ1 Coeffic Setting , (0: Disable-default, audio data passes EQ1 block by 0dB gain). When EQ1="1”, the settings of E1A15-0, E1B15-0 and E1C15-0 bits are enabled
map.r.digital_filter_select_3.EQ2 = 0; // EQ2 Coeffic Setting , (0: Disable-default, audio data passes EQ2 block by 0dB gain). When EQ2="1”, the settings of E2A15-0, E2B15-0 and E2C15-0 bits are enabled
map.r.digital_filter_select_3.EQ3 = 0; // EQ3 Coeffic Setting , (0: Disable-default, audio data passes EQ3 block by 0dB gain). When EQ3="1”, the settings of E3A15-0, E3B15-0 and E3C15-0 bits are enabled
map.r.digital_filter_select_3.EQ4 = 0; // EQ4 Coeffic Setting , (0: Disable-default, audio data passes EQ4 block by 0dB gain). When EQ4="1”, the settings of E4A15-0, E4B15-0 and E4C15-0 bits are enabled
map.r.digital_filter_select_3.EQ5 = 0; // EQ5 Coeffic Setting , (0: Disable-default, audio data passes EQ5 block by 0dB gain). When EQ5="1”, the settings of E5A15-0, E5B15-0 and E5C15-0 bits are enabled
update(Register::DigitalFilterSelect3); // A,B,C EQ1 Coefficients are already pre-loaded in ak4951.hpp
if (alc_mode == 0) { // Programmable Digital Filter OFF, same as original condition., no Digital ALC, nor Wind Noise Filter, LPF , EQ
if (alc_mode==0) { // Programmable Digital Filter OFF, same as original condition., no Digital ALC, nor Wind Noise Filter, LPF , EQ
map.r.digital_filter_select_2.LPF = 0; // LPF-Block, Coeffic Setting Enable (OFF-Default), When LPF bit is “0”, audio data passes the LPF block by 0dB gain.
update(Register::DigitalFilterSelect2);
map.r.digital_filter_select_2.LPF = 0; // LPF-Block, Coeffic Setting Enable (OFF-Default), When LPF bit is “0”, audio data passes the LPF block by 0dB gain.
update(Register::DigitalFilterSelect2);
// Pre-loading AUDIO PATH with all DIGITAL BLOCK by pased, see, audio path block diagramm AK4951 datasheet + Table Playback mode -Recording mode.
// Digital filter block PATH is BY PASSED (we can swith off DIG. BLOCK power , PMPFIL=0) .The Path in Recording Mode 2 & Playback Mode 2 (NO DIG FILTER BLOCK AT ALL, not for MIC recording, nor for Playback)
map.r.digital_filter_mode.ADCPF = 1; // ADCPF bit swith ("0" Mic after ADC Output connected (recording mode) to the DIGITAL FILTER BLOCK. ("1" Playback mode)
map.r.digital_filter_mode.PFSDO = 0; // ADC bit switch ("0" : 1st order HPF) connectedto the Output. By bass DIGITAL block .
map.r.digital_filter_mode.PFDAC = 0b00; // (Input selector for DAC (not used in MIC), SDTI= Audio Serial Data Input Pin)
update(Register::DigitalFilterMode); // Writing the Audio Path : NO DIGITAL BLOCK or DIG BLOCK FOR MIC , Audio mode path : Playback mode /-Recording mode.
// Pre-loading AUDIO PATH with all DIGITAL BLOCK by pased, see, audio path block diagramm AK4951 datasheet + Table Playback mode -Recording mode.
// Digital filter block PATH is BY PASSED (we can swith off DIG. BLOCK power , PMPFIL=0) .The Path in Recording Mode 2 & Playback Mode 2 (NO DIG FILTER BLOCK AT ALL, not for MIC recording, nor for Playback)
map.r.digital_filter_mode.ADCPF = 1; // ADCPF bit swith ("0" Mic after ADC Output connected (recording mode) to the DIGITAL FILTER BLOCK. ("1" Playback mode)
map.r.digital_filter_mode.PFSDO = 0; // ADC bit switch ("0" : 1st order HPF) connectedto the Output. By bass DIGITAL block .
map.r.digital_filter_mode.PFDAC = 0b00; // (Input selector for DAC (not used in MIC), SDTI= Audio Serial Data Input Pin)
update(Register::DigitalFilterMode); // Writing the Audio Path : NO DIGITAL BLOCK or DIG BLOCK FOR MIC , Audio mode path : Playback mode /-Recording mode.
map.r.power_management_1.PMADL = 1; // ADC Lch = Lch input signal. Mic Amp Lch and ADC Lch Power Management
map.r.power_management_1.PMADR = 1; // ADC Rch = Rch input signal. Mic Amp Rch and ADC Rch Power Management
map.r.power_management_1.PMPFIL = 0; // Pre-loading , Programmable Dig. filter OFF ,filter unused, routed around.(original value = 0 )
update(Register::PowerManagement1); // Activating the Power management of the used blocks . (Mic ADC always + Dig Block filter , when used )
map.r.power_management_1.PMADL = 1; // ADC Lch = Lch input signal. Mic Amp Lch and ADC Lch Power Management
map.r.power_management_1.PMADR = 1; // ADC Rch = Rch input signal. Mic Amp Rch and ADC Rch Power Management
map.r.power_management_1.PMPFIL = 0; // Pre-loading , Programmable Dig. filter OFF ,filter unused, routed around.(original value = 0 )
update(Register::PowerManagement1); // Activating the Power management of the used blocks . (Mic ADC always + Dig Block filter , when used )
// 1059/fs, 22ms @ 48kHz
chThdSleepMilliseconds(22);
// 1059/fs, 22ms @ 48kHz
chThdSleepMilliseconds(22);
} else { // ( alc_mode !=0)
} else { // ( alc_mode !=0)
switch (alc_mode) { // Pre-loading register values depending on user-GUI selection (they will be sended below, with "update(Register_name::xxx )".
switch(alc_mode) { // Pre-loading register values depending on user-GUI selection (they will be sended below, with "update(Register_name::xxx )".
case 1: // ALC-> on, (+12dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
map.r.alc_mode_control_2.REF = 0xC0; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, C0H=+12dBs)
map.r.l_ch_input_volume_control.IV = 0xC0; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0xC0; // Right Input Dig Vol Setting, same comment as above , The value of IVOL should be <= than REFs
case 1: // ALC-> on, (+12dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
map.r.alc_mode_control_2.REF = 0xC0; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, C0H=+12dBs)
map.r.l_ch_input_volume_control.IV = 0xC0; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0xC0; // Right Input Dig Vol Setting, same comment as above , The value of IVOL should be <= than REFs
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
case 2: // ALC-> on, (+09dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
map.r.alc_mode_control_2.REF = 0xB8; // REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, B8H= +9dBs)
map.r.l_ch_input_volume_control.IV = 0xB8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0xB8; // Right Input Dig Vol Setting, same comment as above , The value of IVOL should be <= than REFs
case 2: // ALC-> on, (+09dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
map.r.alc_mode_control_2.REF = 0xB8; // REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, B8H= +9dBs)
map.r.l_ch_input_volume_control.IV = 0xB8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0xB8; // Right Input Dig Vol Setting, same comment as above , The value of IVOL should be <= than REFs
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
case 3: // ALC-> on, (+06dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
map.r.alc_mode_control_2.REF = 0xB0; // 0xB8 , REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, B0H= +6dBs)
map.r.l_ch_input_volume_control.IV = 0xB0; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0xB0; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
case 3: // ALC-> on, (+06dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
map.r.alc_mode_control_2.REF = 0xB0; // 0xB8 , REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, B0H= +6dBs)
map.r.l_ch_input_volume_control.IV = 0xB0; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0xB0; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
case 4: // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + Pre-amp Mic (+21dB=original)
// + EQ boosting ~<2kHz (f0:1,1k, fb:1,7K, k=1,8) && + LPF 3,5k
map.r.alc_mode_control_2.REF = 0xA8; // 0xA8 , REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A8H= +3dBs)
map.r.l_ch_input_volume_control.IV = 0xA8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0xA8; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
//The EQn (n=1, 2, 3, 4 or 5) coefficient must be set when EQn bit = “0” or PMPFIL bit = “0”.
map.r.digital_filter_select_3.EQ1 = 1; // EQ1 Coeffic Setting , (0: Disable-default, audio data passes EQ1 block by 0dB gain). When EQ1="1”, the settings of E1A15-0, E1B15-0 and E1C15-0 bits are enabled
update(Register::DigitalFilterSelect3); // A,B,C EQ1 Coefficients are already pre-loaded in ak4951.hpp
case 4: // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + Pre-amp Mic (+21dB=original)
// + EQ boosting ~<2kHz (f0:1,1k, fb:1,7K, k=1,8) && + LPF 3,5k
map.r.alc_mode_control_2.REF = 0xA8; // 0xA8 , REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A8H= +3dBs)
map.r.l_ch_input_volume_control.IV = 0xA8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0xA8; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
map.r.lpf_coefficient_0.l = 0x0D; // Pre-loading here LPF 3,5k , 1st Order from digital Block , Fc=3.500 Hz, fs = 48khz
map.r.lpf_coefficient_1.h = 0x06; // LPF bit is activated down, for all ALC digital modes.
map.r.lpf_coefficient_2.l = 0x1A; // Writting reg to AK4951 , down with update....
map.r.lpf_coefficient_3.h = 0x2C;
// LPF bit is activated down, for all ALC digital modes.
break;
// The EQn (n=1, 2, 3, 4 or 5) coefficient must be set when EQn bit = “0” or PMPFIL bit = “0”.
map.r.digital_filter_select_3.EQ1 = 1; // EQ1 Coeffic Setting , (0: Disable-default, audio data passes EQ1 block by 0dB gain). When EQ1="1”, the settings of E1A15-0, E1B15-0 and E1C15-0 bits are enabled
update(Register::DigitalFilterSelect3); // A,B,C EQ1 Coefficients are already pre-loaded in ak4951.hpp
case 5: // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + Pre-amp Mic (+21dB=original)
// + EQ boosting ~<3kHz (f0~1k4,fb~2,4k,k=1,8) && LPF 4kHz
map.r.alc_mode_control_2.REF = 0xA8; // 0xA0 , REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A8H= +3dBs)
map.r.l_ch_input_volume_control.IV = 0xA8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0xA8; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
map.r.digital_filter_select_3.EQ2 = 1; // EQ2 Coeffic Setting , (0: Disable-default, audio data passes EQ2 block by 0dB gain). When EQ2="1”, the settings of E2A15-0, E2B15-0 and E2C15-0 bits are enabled
update(Register::DigitalFilterSelect3);
map.r.lpf_coefficient_0.l = 0x0D; // Pre-loading here LPF 3,5k , 1st Order from digital Block , Fc=3.500 Hz, fs = 48khz
map.r.lpf_coefficient_1.h = 0x06; // LPF bit is activated down, for all ALC digital modes.
map.r.lpf_coefficient_2.l = 0x1A; // Writting reg to AK4951 , down with update....
map.r.lpf_coefficient_3.h = 0x2C;
// LPF bit is activated down, for all ALC digital modes.
break;
map.r.lpf_coefficient_0.l = 0xC3; // Pre-loading here LPF 4k , 1st Order from digital Block , Fc=4000 Hz, fs = 48khz
map.r.lpf_coefficient_1.h = 0x06; // LPF bit is activated down, for all ALC digital modes.
map.r.lpf_coefficient_2.l = 0x86; // Writting reg to AK4951 , down with update....
map.r.lpf_coefficient_3.h = 0x2D;
// LPF bit is activated down, for all ALC digital modes.
break;
case 5: // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + Pre-amp Mic (+21dB=original)
// + EQ boosting ~<3kHz (f0~1k4,fb~2,4k,k=1,8) && LPF 4kHz
map.r.alc_mode_control_2.REF = 0xA8; // 0xA0 , REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A8H= +3dBs)
map.r.l_ch_input_volume_control.IV = 0xA8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0xA8; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
case 6: // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
map.r.alc_mode_control_2.REF = 0xA8; // REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A0H= 0dBs)
map.r.l_ch_input_volume_control.IV = 0xA8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0xA8; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
map.r.digital_filter_select_3.EQ2 = 1; // EQ2 Coeffic Setting , (0: Disable-default, audio data passes EQ2 block by 0dB gain). When EQ2="1”, the settings of E2A15-0, E2B15-0 and E2C15-0 bits are enabled
update(Register::DigitalFilterSelect3);
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
map.r.lpf_coefficient_0.l = 0xC3; // Pre-loading here LPF 4k , 1st Order from digital Block , Fc=4000 Hz, fs = 48khz
map.r.lpf_coefficient_1.h = 0x06; // LPF bit is activated down, for all ALC digital modes.
map.r.lpf_coefficient_2.l = 0x86; // Writting reg to AK4951 , down with update....
map.r.lpf_coefficient_3.h = 0x2D;
// LPF bit is activated down, for all ALC digital modes.
break;
case 7: // ALC-> on, (+00dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
map.r.alc_mode_control_2.REF = 0xA0; // REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A0H= 0dBs)
map.r.l_ch_input_volume_control.IV = 0xA0; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0xA0; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
case 6: // ALC-> on, (+03dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
map.r.alc_mode_control_2.REF = 0xA8; // REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A0H= 0dBs)
map.r.l_ch_input_volume_control.IV = 0xA8; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0xA8; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
case 8: // ALC-> on, (-03dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
map.r.alc_mode_control_2.REF = 0x98; //REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 98H=-03dBs)
map.r.l_ch_input_volume_control.IV = 0x98; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0x98; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
case 7: // ALC-> on, (+00dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
map.r.alc_mode_control_2.REF = 0xA0; // REF7-0 bits,max gain at ALC recoveryoperation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, A0H= 0dBs)
map.r.l_ch_input_volume_control.IV = 0xA0; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0xA0; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
case 9: // ALC-> on, (-06dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
map.r.alc_mode_control_2.REF = 0x90; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 90H=-06dBs)
map.r.l_ch_input_volume_control.IV = 0x90; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0x90; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
case 8: // ALC-> on, (-03dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
map.r.alc_mode_control_2.REF = 0x98; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 98H=-03dBs)
map.r.l_ch_input_volume_control.IV = 0x98; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0x98; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
case 10: // ALC-> on, (-09dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz - Pre-amp MIC -3dB (18dB's)
// Reduce also Pre-amp Mic -3dB's (+18dB's)
mgain = 0b0110; // Pre-amp mic Mic Gain Pre-amp (+18dB), Original=0b0111 (+21dB's =7x3dBs),
map.r.alc_mode_control_2.REF = 0x88; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 88H=-09dBs)
map.r.l_ch_input_volume_control.IV = 0x88; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0x88; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
case 11: // ALC-> on, (-12dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz - Pre-amp MIC -6dB (15dB's)
// Reduce also Pre-amp Mic -6dB's (+15dB's)
mgain = 0b0101; // Pre-amp mic Mic Gain Pre-amp (+15dB), (Original=0b0111 (+21dB's= 7x3dBs),
case 9: // ALC-> on, (-06dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz + Pre-amp Mic (+21dB=original)
map.r.alc_mode_control_2.REF = 0x90; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 90H=-06dBs)
map.r.l_ch_input_volume_control.IV = 0x90; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0x90; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
map.r.alc_mode_control_2.REF = 0x80; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 80H=-12dBs)
map.r.l_ch_input_volume_control.IV = 0x80; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0x80; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
}
case 10: // ALC-> on, (-09dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz - Pre-amp MIC -3dB (18dB's)
// Reduce also Pre-amp Mic -3dB's (+18dB's)
mgain = 0b0110; // Pre-amp mic Mic Gain Pre-amp (+18dB), Original=0b0111 (+21dB's =7x3dBs),
//-------------------------------DIGITAL ALC (Automatic Level Control ) --- --------
map.r.alc_mode_control_1.ALC = 0; // LMTH2-0, WTM1-0, RGAIN2-0, REF7-0, RFST1-0, EQFC1-0, FRATT, FRN and ALCEQN bits (needs to be set up with ALC disable = 0)
update(Register::ALCModeControl1);
map.r.alc_mode_control_2.REF = 0x88; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 88H=-09dBs)
map.r.l_ch_input_volume_control.IV = 0x88; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0x88; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
map.r.timer_select.FRN = 0; // (FRN= 0 Fast Recovery mode , enable )
map.r.timer_select.FRATT = 0; // Fast Recovery Ref. Volume Atten. Amount -0,00106dB's, timing 4/fs (default)
map.r.timer_select.ADRST = 0b00; // initial offset ADC cycles , 22ms @fs=48Khz.
update(Register::TimerSelect);
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
map.r.alc_timer_select.RFST = 0b00; // RFST1-0: ALC Fast Recovery Speed Default: “00” (0.0032dB)
map.r.alc_timer_select.WTM = 0b00; // ALC Recovery Operation Waiting Period 128/fs = 2,7 mseg (min=default)
map.r.alc_timer_select.EQFC = 0b10; // Selecting default, fs 48Khz , ALCEQ: First order zero pole high pass filter fc2=100Hz, fc1=150Hz
map.r.alc_timer_select.IVTM = 0; // IVTM bit set the vol transition time ,236/fs = 4,9msecs (min) (default was 19,7msegs.)
update(Register::ALCTimerSelect);
case 11: // ALC-> on, (-12dB's) Auto Vol max + Wind Noise cancel + LPF 6kHz - Pre-amp MIC -6dB (15dB's)
// Reduce also Pre-amp Mic -6dB's (+15dB's)
mgain = 0b0101; // Pre-amp mic Mic Gain Pre-amp (+15dB), (Original=0b0111 (+21dB's= 7x3dBs),
map.r.alc_mode_control_1.LMTH10 = 0b11; // ALC Limiter Detec Level/ Recovery Counter Reset; lower 2 bits (Ob111=-8,4dbs), (default 0b000=-2,5dBs)
map.r.alc_mode_control_1.RGAIN = 0b000; // ALC Recovery Gain Step, max step , max speed. Default: “000” (0.00424dB)
map.r.alc_mode_control_1.ALC = 1; // ALC Enable . (we are now, NOT in MANUAL volume mode, only becomes manual when (ALC=“0” while ADCPF=“1”. )
map.r.alc_mode_control_1.LMTH2 = 1; // ALC Limiter Detection Level/ Recovery Counter Reset Level,Upper bit,default 0b000
map.r.alc_mode_control_1.ALCEQN = 1; // ALC EQ Off =1 not used by now, 0: ALC EQ On (default)
update(Register::ALCModeControl1);
map.r.alc_mode_control_2.REF = 0x80; // REF7-0 bits,max gain at ALC recovery operation,(FFH +36dBs , D0H +18dBs, A0H 0dBs, 80H=-12dBs)
map.r.l_ch_input_volume_control.IV = 0x80; // Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
map.r.r_ch_input_volume_control.IV = 0x80; // Right Input Dig Vol Setting, same comment as above , Then value of IVOL should be <= than REFs
// map.r.alc_mode_control_2.REF = 0x??; // Pre-loaded in top part. Maximum gain at ALC recovery operation,.(FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
update(Register::ALCModeControl2);
// Already Pre-loaded, "map.r.lpf_coefficient", 6Khz - LPF 1st Order from digital Block,Fc=6000Hz,fs = 48khz
// LPF bit is activated down, for all ALC digital modes.
break;
}
// map.r.l_ch_input_volume_control.IV = 0x??; // Pre-loaded in top part. Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
update(Register::LchInputVolumeControl);
// map.r.r_ch_input_volume_control.IV = 0x??; // Pre-loaded in top part. Right,Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
update(Register::RchInputVolumeControl);
//---------------Switch ON, Digital Automatic Wind Noise Filter reduction -------------------
// Difficult to realise that Dynamic HPF Wind noise filter benefit, maybe because we have another fixed HPF 236.8 Hz .
// Anyway , we propose to activate it , with default setting conditions.
map.r.power_management_1.PMPFIL = 0; // (*1) To programm SENC, STG , we need PMPFIL = 0 . (but this disconnect Digital block power supply.
update(Register::PowerManagement1); // Updated PMPFIL to 0 . (*1)
//-------------------------------DIGITAL ALC (Automatic Level Control ) --- --------
map.r.alc_mode_control_1.ALC = 0; // LMTH2-0, WTM1-0, RGAIN2-0, REF7-0, RFST1-0, EQFC1-0, FRATT, FRN and ALCEQN bits (needs to be set up with ALC disable = 0)
update(Register::ALCModeControl1);
map.r.auto_hpf_control.STG = 0b00; // (00=LOW ATTENUATION Level), lets put 11 (HIGH ATTENUATION Level) (default 00)
map.r.auto_hpf_control.SENC = 0b011; // (000=LOW sensitivity detection)… 111((MAX sensitivity detection) (default 011)
map.r.auto_hpf_control.AHPF = 1; // Autom. Wind noise filter ON (AHPF bit=“1”).It atten. wind noise when detecting ,and adjusts the atten. level dynamically.
update(Register::AutoHPFControl);
map.r.timer_select.FRN = 0; // (FRN= 0 Fast Recovery mode , enable )
map.r.timer_select.FRATT = 0; // Fast Recovery Ref. Volume Atten. Amount -0,00106dB's, timing 4/fs (default)
map.r.timer_select.ADRST = 0b00; // initial offset ADC cycles , 22ms @fs=48Khz.
update(Register::TimerSelect);
// We are in Digital Block ON , (Wind Noise Filter+ALC+LPF+EQ),==> needs at the end , PMPFIL=1 , Program. Dig.filter ON
// map.r.power_management_1.PMPFIL = 1; // that instruction is at the end , we can skp pre-loading Programmable Dig. filter ON (*1)
//---------------------------------------------------------------------
// Writing AUDIO PATH diagramm, Changing Audio mode path : Playback mode1 /-Recording mode2. (Figure 37 AK4951 datasheet, Table 27. Recording Playback Mode)
// When changing those modes, PMPFIL bit must be “0”, it is OK (*1)
map.r.digital_filter_mode.ADCPF = 1; // ADCPF bit swith ("0" Mic after ADC Output connected (recording mode) to the DIGITAL FILTER BLOCK. ("1" Playback mode)
map.r.digital_filter_mode.PFSDO = 1; // ADC (+ 1st order HPF) Output
map.r.digital_filter_mode.PFDAC = 0b00; // (Input selector for DAC (not used in MIC), SDTI= Audio Serial Data Input Pin)
update(Register::DigitalFilterMode); // Writing the Audio Path : NO DIGITAL BLOCK or DIG BLOCK FOR MIC , Audio mode path : Playback mode /-Recording mode.
map.r.alc_timer_select.RFST = 0b00; // RFST1-0: ALC Fast Recovery Speed Default: “00” (0.0032dB)
map.r.alc_timer_select.WTM = 0b00; // ALC Recovery Operation Waiting Period 128/fs = 2,7 mseg (min=default)
map.r.alc_timer_select.EQFC = 0b10; // Selecting default, fs 48Khz , ALCEQ: First order zero pole high pass filter fc2=100Hz, fc1=150Hz
map.r.alc_timer_select.IVTM = 0; // IVTM bit set the vol transition time ,236/fs = 4,9msecs (min) (default was 19,7msegs.)
update(Register::ALCTimerSelect);
// The EQn (n=1, 2, 3, 4 or 5) coefficient must be set when EQn bit = “0” or PMPFIL bit = “0”., but we are already (*1)
// map.r.power_management_1.PMPFIL = 0; // In the previous Wind Noise Filter , we already set up PPFIL = 0
// update(Register::PowerManagement1); // Activating the Power management of the used blocks . (Mic ADC always + Dig Block filter , when used )
map.r.alc_mode_control_1.LMTH10 = 0b11; // ALC Limiter Detec Level/ Recovery Counter Reset; lower 2 bits (Ob111=-8,4dbs), (default 0b000=-2,5dBs)
map.r.alc_mode_control_1.RGAIN = 0b000; // ALC Recovery Gain Step, max step , max speed. Default: “000” (0.00424dB)
map.r.alc_mode_control_1.ALC = 1; // ALC Enable . (we are now, NOT in MANUAL volume mode, only becomes manual when (ALC=“0” while ADCPF=“1”. )
map.r.alc_mode_control_1.LMTH2 = 1; // ALC Limiter Detection Level/ Recovery Counter Reset Level,Upper bit,default 0b000
map.r.alc_mode_control_1.ALCEQN = 1; // ALC EQ Off =1 not used by now, 0: ALC EQ On (default)
update(Register::ALCModeControl1);
// ... Set EQ & LPF coefficients ---------------------------------
// map.r.alc_mode_control_2.REF = 0x??; // Pre-loaded in top part. Maximum gain at ALC recovery operation,.(FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
update(Register::ALCModeControl2);
// writting to the IC ak4951 reg. settings defined in Ak4951.hpp , the 30 bytes , EQ coefficient = 5 (EQ1,2,3,4,5) x 3 (A,B,C coefficients) x 2 bytes (16 bits)
update(Register::E1Coefficient0); // we could pre-load here,ex ,"map.r.e1_coefficient_0.l = 0x50;" , EQ1 Coefficient A : A7...A0, but already done in ak4951.hpp
update(Register::E1Coefficient1); // we could pre-load here,ex ,"map.r.e1_coefficient_1.h = 0xFE;" , EQ1 Coefficient A : A15..A8, " "
update(Register::E1Coefficient2); // we could pre-load here,ex ,"map.r.e1_coefficient_2.l = 0x29;" , EQ1 Coefficient B : B7...B0, " "
update(Register::E1Coefficient3); // we could pre-load here,ex ,"map.r.e1_coefficient_3.h = 0xC5;" , EQ1 Coefficient B : B15..B8, " "
update(Register::E1Coefficient4); // we could pre-load here,ex ,"map.r.e1_coefficient_4.l = 0xA0;" , EQ1 Coefficient C : C7...C0, " "
update(Register::E1Coefficient5); // we could pre-load here,ex ,"map.r.e1_coefficient_5.h = 0x1C;" , EQ1 Coefficient C : C15..C8, " "
update(Register::E2Coefficient0); // writing pre-loaded EQ2 coefficcients
update(Register::E2Coefficient1);
update(Register::E2Coefficient2);
update(Register::E2Coefficient3);
update(Register::E2Coefficient4);
update(Register::E2Coefficient5);
// map.r.l_ch_input_volume_control.IV = 0x??; // Pre-loaded in top part. Left, Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
update(Register::LchInputVolumeControl);
// Already pre-loaded LPF coefficients to 6k, 3,5k or 4k ,(LPF 6Khz all digital alc modes top , except when 3k5 , 4k)
update(Register::LPFCoefficient0); // Writing pre-loaded 4 bytes LPF CoefFiecients 14 bits (FSA13..0, FSB13..0
update(Register::LPFCoefficient1);
update(Register::LPFCoefficient2);
update(Register::LPFCoefficient3);
// map.r.r_ch_input_volume_control.IV = 0x??; // Pre-loaded in top part. Right,Input Digital Volume Setting, (FFH +36dBs , D0H +18dBs, A0H 0dBs, 70H=-18dBs)
update(Register::RchInputVolumeControl);
// Activating LPF block , (and re-configuring the rest of bits of the same register)
map.r.digital_filter_select_2.HPF = 0; // HPF2-Block, Coeffic Setting Enable (OFF-Default), When HPF bit is “0”, audio data passes the HPF2 block by is 0dB gain.
map.r.digital_filter_select_2.LPF = 1; // LPF-Block, Coeffic Setting Enable (OFF-Default), When LPF bit is “0”, audio data passes the LPF block by 0dB gain.
map.r.digital_filter_select_2.FIL3 = 0; // Stereo_Emphasis_Filter-Block,(OFF-Default) Coefficient Setting Enable , OFF , Disable.
map.r.digital_filter_select_2.EQ0 = 0; // Gain Compensation-Block, (OFF-Default) Coeffic Setting Enable, When EQ0 bit = “0” audio data passes the EQ0 block by 0dB gain.
map.r.digital_filter_select_2.GN = 0b00; // Gain Setting of the Gain Compensation Block Default: “00”-Default (0dB)
update(Register::DigitalFilterSelect2);
//---------------Switch ON, Digital Automatic Wind Noise Filter reduction -------------------
// Difficult to realise that Dynamic HPF Wind noise filter benefit, maybe because we have another fixed HPF 236.8 Hz .
// Anyway , we propose to activate it , with default setting conditions.
map.r.power_management_1.PMPFIL = 0; // (*1) To programm SENC, STG , we need PMPFIL = 0 . (but this disconnect Digital block power supply.
update(Register::PowerManagement1); // Updated PMPFIL to 0 . (*1)
// Acitivating digital block , power supply
map.r.power_management_1.PMADL = 1; // ADC Lch = Lch input signal. Mic Amp Lch and ADC Lch Power Management
map.r.power_management_1.PMADR = 1; // ADC Rch = Rch input signal. Mic Amp Rch and ADC Rch Power Management
map.r.power_management_1.PMPFIL = 1; // Pre-loaded in top part. Orig value=0, Programmable Digital filter unused (not power up), routed around.
update(Register::PowerManagement1); // Activating the Power management of the used blocks . (Mic ADC always + Dig Block filter , when used )
map.r.auto_hpf_control.STG = 0b00; // (00=LOW ATTENUATION Level), lets put 11 (HIGH ATTENUATION Level) (default 00)
map.r.auto_hpf_control.SENC = 0b011; // (000=LOW sensitivity detection)… 111((MAX sensitivity detection) (default 011)
map.r.auto_hpf_control.AHPF = 1; // Autom. Wind noise filter ON (AHPF bit=“1”).It atten. wind noise when detecting ,and adjusts the atten. level dynamically.
update(Register::AutoHPFControl);
// 1059/fs, 22ms @ 48kHz
chThdSleepMilliseconds(22);
// We are in Digital Block ON , (Wind Noise Filter+ALC+LPF+EQ),==> needs at the end , PMPFIL=1 , Program. Dig.filter ON
// map.r.power_management_1.PMPFIL = 1; // that instruction is at the end , we can skp pre-loading Programmable Dig. filter ON (*1)
//---------------------------------------------------------------------
}
// Writing AUDIO PATH diagramm, Changing Audio mode path : Playback mode1 /-Recording mode2. (Figure 37 AK4951 datasheet, Table 27. Recording Playback Mode)
// When changing those modes, PMPFIL bit must be “0”, it is OK (*1)
map.r.digital_filter_mode.ADCPF = 1; // ADCPF bit swith ("0" Mic after ADC Output connected (recording mode) to the DIGITAL FILTER BLOCK. ("1" Playback mode)
map.r.digital_filter_mode.PFSDO = 1; // ADC (+ 1st order HPF) Output
map.r.digital_filter_mode.PFDAC = 0b00; // (Input selector for DAC (not used in MIC), SDTI= Audio Serial Data Input Pin)
update(Register::DigitalFilterMode); // Writing the Audio Path : NO DIGITAL BLOCK or DIG BLOCK FOR MIC , Audio mode path : Playback mode /-Recording mode.
// Common part for all alc_mode , --------------------------
// const uint_fast8_t mgain = 0b0111; // Already pre-loaded , in above switch case .
map.r.signal_select_1.MGAIN20 = mgain & 7; // writing 3 lower bits of mgain , (pre-amp mic gain).
map.r.signal_select_1.PMMP = 1; // Activating DC Mic Power supply through 2kohms res., similar majority smartphones headphone+mic jack, "plug-in-power"
map.r.signal_select_1.MPSEL = 1; // MPWR2 pin ,selecting output voltage to MPWR2 pin, that we are using in portapack ext. MIC)
map.r.signal_select_1.MGAIN3 = (mgain >> 3) & 1; // writing 4th upper bit of mgain (pre-amp mic gain).
update(Register::SignalSelect1);
// The EQn (n=1, 2, 3, 4 or 5) coefficient must be set when EQn bit = “0” or PMPFIL bit = “0”., but we are already (*1)
// map.r.power_management_1.PMPFIL = 0; // In the previous Wind Noise Filter , we already set up PPFIL = 0
// update(Register::PowerManagement1); // Activating the Power management of the used blocks . (Mic ADC always + Dig Block filter , when used )
// ... Set EQ & LPF coefficients ---------------------------------
// writting to the IC ak4951 reg. settings defined in Ak4951.hpp , the 30 bytes , EQ coefficient = 5 (EQ1,2,3,4,5) x 3 (A,B,C coefficients) x 2 bytes (16 bits)
update(Register::E1Coefficient0); // we could pre-load here,ex ,"map.r.e1_coefficient_0.l = 0x50;" , EQ1 Coefficient A : A7...A0, but already done in ak4951.hpp
update(Register::E1Coefficient1); // we could pre-load here,ex ,"map.r.e1_coefficient_1.h = 0xFE;" , EQ1 Coefficient A : A15..A8, " "
update(Register::E1Coefficient2); // we could pre-load here,ex ,"map.r.e1_coefficient_2.l = 0x29;" , EQ1 Coefficient B : B7...B0, " "
update(Register::E1Coefficient3); // we could pre-load here,ex ,"map.r.e1_coefficient_3.h = 0xC5;" , EQ1 Coefficient B : B15..B8, " "
update(Register::E1Coefficient4); // we could pre-load here,ex ,"map.r.e1_coefficient_4.l = 0xA0;" , EQ1 Coefficient C : C7...C0, " "
update(Register::E1Coefficient5); // we could pre-load here,ex ,"map.r.e1_coefficient_5.h = 0x1C;" , EQ1 Coefficient C : C15..C8, " "
update(Register::E2Coefficient0); // writing pre-loaded EQ2 coefficcients
update(Register::E2Coefficient1);
update(Register::E2Coefficient2);
update(Register::E2Coefficient3);
update(Register::E2Coefficient4);
update(Register::E2Coefficient5);
// Already pre-loaded LPF coefficients to 6k, 3,5k or 4k ,(LPF 6Khz all digital alc modes top , except when 3k5 , 4k)
update(Register::LPFCoefficient0); // Writing pre-loaded 4 bytes LPF CoefFiecients 14 bits (FSA13..0, FSB13..0
update(Register::LPFCoefficient1);
update(Register::LPFCoefficient2);
update(Register::LPFCoefficient3);
// Activating LPF block , (and re-configuring the rest of bits of the same register)
map.r.digital_filter_select_2.HPF = 0; // HPF2-Block, Coeffic Setting Enable (OFF-Default), When HPF bit is “0”, audio data passes the HPF2 block by is 0dB gain.
map.r.digital_filter_select_2.LPF = 1; // LPF-Block, Coeffic Setting Enable (OFF-Default), When LPF bit is “0”, audio data passes the LPF block by 0dB gain.
map.r.digital_filter_select_2.FIL3 = 0; // Stereo_Emphasis_Filter-Block,(OFF-Default) Coefficient Setting Enable , OFF , Disable.
map.r.digital_filter_select_2.EQ0 = 0; // Gain Compensation-Block, (OFF-Default) Coeffic Setting Enable, When EQ0 bit = “0” audio data passes the EQ0 block by 0dB gain.
map.r.digital_filter_select_2.GN = 0b00; // Gain Setting of the Gain Compensation Block Default: “00”-Default (0dB)
update(Register::DigitalFilterSelect2);
// Acitivating digital block , power supply
map.r.power_management_1.PMADL = 1; // ADC Lch = Lch input signal. Mic Amp Lch and ADC Lch Power Management
map.r.power_management_1.PMADR = 1; // ADC Rch = Rch input signal. Mic Amp Rch and ADC Rch Power Management
map.r.power_management_1.PMPFIL = 1; // Pre-loaded in top part. Orig value=0, Programmable Digital filter unused (not power up), routed around.
update(Register::PowerManagement1); // Activating the Power management of the used blocks . (Mic ADC always + Dig Block filter , when used )
// 1059/fs, 22ms @ 48kHz
chThdSleepMilliseconds(22);
}
// Common part for all alc_mode , --------------------------
// const uint_fast8_t mgain = 0b0111; // Already pre-loaded , in above switch case .
map.r.signal_select_1.MGAIN20 = mgain & 7; // writing 3 lower bits of mgain , (pre-amp mic gain).
map.r.signal_select_1.PMMP = 1; // Activating DC Mic Power supply through 2kohms res., similar majority smartphones headphone+mic jack, "plug-in-power"
map.r.signal_select_1.MPSEL = 1; // MPWR2 pin ,selecting output voltage to MPWR2 pin, that we are using in portapack ext. MIC)
map.r.signal_select_1.MGAIN3 = (mgain >> 3) & 1; // writing 4th upper bit of mgain (pre-amp mic gain).
update(Register::SignalSelect1);
}
void AK4951::microphone_disable() {
map.r.power_management_1.PMADL = 0; // original code , disable Power managem.Mic ADC L
map.r.power_management_1.PMADR = 0; // original code , disable Power managem.Mic ADC R
map.r.power_management_1.PMPFIL = 0; // original code , disable Power managem. all Programmable Dig. block
update(Register::PowerManagement1);
map.r.power_management_1.PMADL = 0; // original code , disable Power managem.Mic ADC L
map.r.power_management_1.PMADR = 0; // original code , disable Power managem.Mic ADC R
map.r.power_management_1.PMPFIL = 0; // original code , disable Power managem. all Programmable Dig. block
update(Register::PowerManagement1);
map.r.alc_mode_control_1.ALC = 0; // original code , Restore , disable ALC block.
update(Register::ALCModeControl1);
map.r.alc_mode_control_1.ALC = 0; // original code , Restore , disable ALC block.
update(Register::ALCModeControl1);
map.r.auto_hpf_control.AHPF = 0; //----------- new code addition , Restore disable Wind noise filter OFF (AHPF bit=“0”).
update(Register::AutoHPFControl);
map.r.auto_hpf_control.AHPF = 0; //----------- new code addition , Restore disable Wind noise filter OFF (AHPF bit=“0”).
update(Register::AutoHPFControl);
//Restore original AUDIO PATH , condition, (Digital filter block PATH is BY PASSED) (we can also swith off DIG. BLOCK power , PMPFIL=0)
// The Path in Recording Mode 2 & Playback Mode 2 , (NO DIG FILTER BLOCK AT ALL, not for MIC recording, nor for Playback)
map.r.digital_filter_mode.ADCPF = 1; // new code addition , ADCPF bit swith ("0" Mic after ADC Output connected (recording mode) to the DIGITAL FILTER BLOCK. ("1" Playback mode)
map.r.digital_filter_mode.PFSDO = 0; // new code addition , ADC bit switch ("0" : 1st order HPF) connectedto the Output. By bass DIGITAL block .
map.r.digital_filter_mode.PFDAC = 0b00; // new code addition , (Input selector for DAC (not used in MIC), SDTI= Audio Serial Data Input Pin)
update(Register::DigitalFilterMode); // Writing the Audio Path : NO DIGITAL BLOCK or DIG BLOCK FOR MIC , Audio mode path : Playback mode /-Recording mode.
// Restore original condition , LPF , OFF . same as when not using DIGITAL Programmable block
map.r.digital_filter_select_2.LPF = 0; // LPF-Block, Coeffic Setting Enable (OFF-Default), When LPF bit is “0”, audio data passes the LPF block by 0dB gain.
update(Register::DigitalFilterSelect2);
// Restore original AUDIO PATH , condition, (Digital filter block PATH is BY PASSED) (we can also swith off DIG. BLOCK power , PMPFIL=0)
// The Path in Recording Mode 2 & Playback Mode 2 , (NO DIG FILTER BLOCK AT ALL, not for MIC recording, nor for Playback)
map.r.digital_filter_mode.ADCPF = 1; // new code addition , ADCPF bit swith ("0" Mic after ADC Output connected (recording mode) to the DIGITAL FILTER BLOCK. ("1" Playback mode)
map.r.digital_filter_mode.PFSDO = 0; // new code addition , ADC bit switch ("0" : 1st order HPF) connectedto the Output. By bass DIGITAL block .
map.r.digital_filter_mode.PFDAC = 0b00; // new code addition , (Input selector for DAC (not used in MIC), SDTI= Audio Serial Data Input Pin)
update(Register::DigitalFilterMode); // Writing the Audio Path : NO DIGITAL BLOCK or DIG BLOCK FOR MIC , Audio mode path : Playback mode /-Recording mode.
map.r.lpf_coefficient_0.l = 0x00; // Pre-loading here LPF 6k , 1st Order from digital Block , Fc=6000 Hz, fs = 48khz
map.r.lpf_coefficient_1.h = 0x00; // LPF bit is activated down, for all ALC digital modes.
map.r.lpf_coefficient_2.l = 0x00; // Writting reg to AK4951 , down with update....
map.r.lpf_coefficient_3.h = 0x00;
// Restore original condition , LPF , OFF . same as when not using DIGITAL Programmable block
map.r.digital_filter_select_2.LPF = 0; // LPF-Block, Coeffic Setting Enable (OFF-Default), When LPF bit is “0”, audio data passes the LPF block by 0dB gain.
update(Register::DigitalFilterSelect2);
update(Register::LPFCoefficient0); // Writing pre-loaded 4 bytes LPF CoefFiecients 14 bits (FSA13..0, FSB13..0
update(Register::LPFCoefficient1);
update(Register::LPFCoefficient2);
update(Register::LPFCoefficient3);
map.r.lpf_coefficient_0.l = 0x00; // Pre-loading here LPF 6k , 1st Order from digital Block , Fc=6000 Hz, fs = 48khz
map.r.lpf_coefficient_1.h = 0x00; // LPF bit is activated down, for all ALC digital modes.
map.r.lpf_coefficient_2.l = 0x00; // Writting reg to AK4951 , down with update....
map.r.lpf_coefficient_3.h = 0x00;
// Switch off all EQ 1,2,3,4,5
map.r.digital_filter_select_3.EQ1 = 0; // EQ1 Coeffic Setting , (0: Disable-default, audio data passes EQ1 block by 0dB gain). When EQ1="1”, the settings of E1A15-0, E1B15-0 and E1C15-0 bits are enabled
map.r.digital_filter_select_3.EQ2 = 0; // EQ2 Coeffic Setting , (0: Disable-default, audio data passes EQ2 block by 0dB gain). When EQ2="1”, the settings of E2A15-0, E2B15-0 and E2C15-0 bits are enabled
map.r.digital_filter_select_3.EQ3 = 0; // EQ3 Coeffic Setting , (0: Disable-default, audio data passes EQ3 block by 0dB gain). When EQ3="1”, the settings of E3A15-0, E3B15-0 and E3C15-0 bits are enabled
map.r.digital_filter_select_3.EQ4 = 0; // EQ4 Coeffic Setting , (0: Disable-default, audio data passes EQ4 block by 0dB gain). When EQ4="1”, the settings of E4A15-0, E4B15-0 and E4C15-0 bits are enabled
map.r.digital_filter_select_3.EQ5 = 0; // EQ5 Coeffic Setting , (0: Disable-default, audio data passes EQ5 block by 0dB gain). When EQ5="1”, the settings of E5A15-0, E5B15-0 and E5C15-0 bits are enabled
update(Register::DigitalFilterSelect3);
update(Register::LPFCoefficient0); // Writing pre-loaded 4 bytes LPF CoefFiecients 14 bits (FSA13..0, FSB13..0
update(Register::LPFCoefficient1);
update(Register::LPFCoefficient2);
update(Register::LPFCoefficient3);
// Switch off all EQ 1,2,3,4,5
map.r.digital_filter_select_3.EQ1 = 0; // EQ1 Coeffic Setting , (0: Disable-default, audio data passes EQ1 block by 0dB gain). When EQ1="1”, the settings of E1A15-0, E1B15-0 and E1C15-0 bits are enabled
map.r.digital_filter_select_3.EQ2 = 0; // EQ2 Coeffic Setting , (0: Disable-default, audio data passes EQ2 block by 0dB gain). When EQ2="1”, the settings of E2A15-0, E2B15-0 and E2C15-0 bits are enabled
map.r.digital_filter_select_3.EQ3 = 0; // EQ3 Coeffic Setting , (0: Disable-default, audio data passes EQ3 block by 0dB gain). When EQ3="1”, the settings of E3A15-0, E3B15-0 and E3C15-0 bits are enabled
map.r.digital_filter_select_3.EQ4 = 0; // EQ4 Coeffic Setting , (0: Disable-default, audio data passes EQ4 block by 0dB gain). When EQ4="1”, the settings of E4A15-0, E4B15-0 and E4C15-0 bits are enabled
map.r.digital_filter_select_3.EQ5 = 0; // EQ5 Coeffic Setting , (0: Disable-default, audio data passes EQ5 block by 0dB gain). When EQ5="1”, the settings of E5A15-0, E5B15-0 and E5C15-0 bits are enabled
update(Register::DigitalFilterSelect3);
}
reg_t AK4951::read(const address_t reg_address) {
const std::array<uint8_t, 1> tx { reg_address };
std::array<uint8_t, 1> rx { 0x00 };
bus.transmit(bus_address, tx.data(), tx.size());
bus.receive(bus_address, rx.data(), rx.size());
return rx[0];
const std::array<uint8_t, 1> tx{reg_address};
std::array<uint8_t, 1> rx{0x00};
bus.transmit(bus_address, tx.data(), tx.size());
bus.receive(bus_address, rx.data(), rx.size());
return rx[0];
}
void AK4951::update(const Register reg) {
write(toUType(reg), map.w[toUType(reg)]);
write(toUType(reg), map.w[toUType(reg)]);
}
void AK4951::write(const address_t reg_address, const reg_t value) {
const std::array<uint8_t, 2> tx { reg_address, value };
bus.transmit(bus_address, tx.data(), tx.size());
const std::array<uint8_t, 2> tx{reg_address, value};
bus.transmit(bus_address, tx.data(), tx.size());
}
} /* namespace ak4951 */

File diff suppressed because it is too large Load Diff

View File

@@ -24,4 +24,4 @@
namespace aprs {
} /* namespace zwave */
} // namespace aprs

View File

@@ -31,465 +31,450 @@
namespace aprs {
const int APRS_MIN_LENGTH = 18; //14 bytes address, control byte and pid. 2 CRC.
const int APRS_MIN_LENGTH = 18; // 14 bytes address, control byte and pid. 2 CRC.
struct aprs_pos{
float latitude;
float longitude;
uint8_t symbol_code;
uint8_t sym_table_id;
struct aprs_pos {
float latitude;
float longitude;
uint8_t symbol_code;
uint8_t sym_table_id;
};
enum ADDRESS_TYPE {
SOURCE,
DESTINATION,
REPEATER
SOURCE,
DESTINATION,
REPEATER
};
class APRSPacket {
public:
void set_timestamp(const Timestamp& value) {
timestamp_ = value;
}
Timestamp timestamp() const {
return timestamp_;
}
void set(const size_t index, const uint8_t data) {
payload[index] = data;
if(index + 1 > payload_size){
payload_size = index + 1;
}
}
uint32_t operator[](const size_t index) const {
return payload[index];
}
uint8_t size() const {
return payload_size;
}
void set_valid_checksum(const bool valid) {
valid_checksum = valid;
}
bool is_valid_checksum() const {
return valid_checksum;
}
uint64_t get_source(){
uint64_t source = 0x0;
for(uint8_t i = SOURCE_START; i < SOURCE_START + ADDRESS_SIZE; i++){
source |= ( ((uint64_t)payload[i]) << ((i - SOURCE_START) * 8));
}
return source;
}
std::string get_source_formatted(){
parse_address(SOURCE_START, SOURCE);
return std::string(address_buffer);
}
std::string get_destination_formatted(){
parse_address(DESTINATION_START, DESTINATION);
return std::string(address_buffer);
}
std::string get_digipeaters_formatted(){
uint8_t position = DIGIPEATER_START;
bool has_more = parse_address(SOURCE_START, REPEATER);
std::string repeaters = "";
while(has_more){
has_more = parse_address(position, REPEATER);
repeaters += std::string(address_buffer);
position += ADDRESS_SIZE;
if(has_more){
repeaters += ">";
}
}
return repeaters;
}
uint8_t get_number_of_digipeaters(){
uint8_t position = DIGIPEATER_START;
bool has_more = parse_address(SOURCE_START, REPEATER);
uint8_t repeaters = 0;
while(has_more){
has_more = parse_address(position, REPEATER);
position += ADDRESS_SIZE;
repeaters++;
}
return repeaters;
}
uint8_t get_information_start_index(){
return DIGIPEATER_START + (get_number_of_digipeaters() * ADDRESS_SIZE) + 2;
}
std::string get_information_text_formatted(){
std::string information_text = "";
for(uint8_t i = get_information_start_index(); i < payload_size - 2; i++){
information_text += payload[i];
}
return information_text;
}
std::string get_stream_text(){
std::string stream = get_source_formatted() + ">" + get_destination_formatted() + ";" + get_digipeaters_formatted() + ";" + get_information_text_formatted();
return stream;
}
char get_data_type_identifier(){
char ident = '\0';
for(uint8_t i = get_information_start_index(); i < payload_size - 2; i++){
ident = payload[i];
break;
}
return ident;
}
bool has_position(){
char ident = get_data_type_identifier();
return
ident == '!' ||
ident == '=' ||
ident == '/' ||
ident == '@' ||
ident == ';' ||
ident == '`' ||
ident == '\''||
ident == 0x1d||
ident == 0x1c;
}
aprs_pos get_position(){
aprs::aprs_pos pos;
char ident = get_data_type_identifier();
std::string info_text = get_information_text_formatted();
std::string lat_str, lng_str;
char first;
//bool supports_compression = true;
bool is_mic_e_format = false;
std::string::size_type start;
switch(ident){
case '/':
case '@':
start = 8;
break;
case '=':
case '!':
start = 1;
break;
case ';':
start = 18;
//supports_compression = false;
break;
case '`':
case '\'':
case 0x1c:
case 0x1d:
is_mic_e_format = true;
break;
default:
return pos;
}
if(is_mic_e_format){
parse_mic_e_format(pos);
}
else {
if(start < info_text.size()){
first = info_text.at(start);
if(std::isdigit(first)){
if(start + 18 < info_text.size()){
lat_str = info_text.substr(start, 8);
pos.sym_table_id = info_text.at(start + 8);
lng_str = info_text.substr(start + 9, 9);
pos.symbol_code = info_text.at(start + 18);
pos.latitude = parse_lat_str(lat_str);
pos.longitude = parse_lng_str(lng_str);
}
}
else {
if(start + 9 < info_text.size()){
pos.sym_table_id = info_text.at(start);
lat_str = info_text.substr(start + 1, 4);
lng_str = info_text.substr(start + 5, 4);
pos.symbol_code = info_text.at(start + 9);
pos.latitude = parse_lat_str_cmp(lat_str);
pos.longitude = parse_lng_str_cmp(lng_str);
}
}
}
}
return pos;
}
void clear() {
payload_size = 0;
}
private:
const uint8_t DIGIPEATER_START = 14;
const uint8_t SOURCE_START = 7;
const uint8_t DESTINATION_START = 0;
const uint8_t ADDRESS_SIZE = 7;
bool valid_checksum = false;
uint8_t payload[256];
char address_buffer[15];
uint8_t payload_size = 0 ;
Timestamp timestamp_ { };
float parse_lat_str_cmp(const std::string& lat_str){
return 90.0 - ( (lat_str.at(0) - 33) * (91*91*91) + (lat_str.at(1) - 33) * (91*91) + (lat_str.at(2) - 33) * 91 + (lat_str.at(3)) ) / 380926.0;
}
float parse_lng_str_cmp(const std::string& lng_str){
return -180.0 + ( (lng_str.at(0) - 33) * (91*91*91) + (lng_str.at(1) - 33) * (91*91) + (lng_str.at(2) - 33) * 91 + (lng_str.at(3)) ) / 190463.0;
}
uint8_t parse_digits(const std::string& str){
if(str.at(0) == ' '){
return 0;
}
uint8_t end = str.find_last_not_of(' ') + 1;
std::string sub = str.substr(0, end);
if(!is_digits(sub)){
return 0;
}
else {
return std::stoi(sub);
}
}
bool is_digits(const std::string& str){
return str.find_last_not_of("0123456789") == std::string::npos;
}
float parse_lat_str(const std::string& lat_str){
float lat = 0.0;
std::string str_lat_deg = lat_str.substr(0, 2);
std::string str_lat_min = lat_str.substr(2, 2);
std::string str_lat_hund = lat_str.substr(5, 2);
std::string dir = lat_str.substr(7, 1);
uint8_t lat_deg = parse_digits(str_lat_deg);
uint8_t lat_min = parse_digits(str_lat_min);
uint8_t lat_hund = parse_digits(str_lat_hund);
lat += lat_deg;
lat += (lat_min + (lat_hund/ 100.0))/60.0;
if(dir.c_str()[0] == 'S'){
lat = -lat;
}
return lat;
}
float parse_lng_str(std::string& lng_str){
float lng = 0.0;
std::string str_lng_deg = lng_str.substr(0, 3);
std::string str_lng_min = lng_str.substr(3, 2);
std::string str_lng_hund = lng_str.substr(6, 2);
std::string dir = lng_str.substr(8, 1);
uint8_t lng_deg = parse_digits(str_lng_deg);
uint8_t lng_min = parse_digits(str_lng_min);
uint8_t lng_hund = parse_digits(str_lng_hund);
lng += lng_deg;
lng += (lng_min + (lng_hund/ 100.0))/60.0;
if(dir.c_str()[0] == 'W'){
lng = -lng;
}
return lng;
}
void parse_mic_e_format(aprs::aprs_pos& pos){
std::string lat_str = "";
std::string lng_str = "";
bool is_north = false;
bool is_west = false;
uint8_t lng_offset = 0;
for(uint8_t i = DESTINATION_START; i < DESTINATION_START + ADDRESS_SIZE - 1; i++){
uint8_t ascii = payload[i] >> 1;
lat_str += get_mic_e_lat_digit(ascii);
if(i - DESTINATION_START == 3){
lat_str += ".";
}
if(i - DESTINATION_START == 3){
is_north = is_mic_e_lat_N(ascii);
}
if(i - DESTINATION_START == 4){
lng_offset = get_mic_e_lng_offset(ascii);
}
if(i - DESTINATION_START == 5){
is_west = is_mic_e_lng_W(ascii);
}
}
if(is_north){
lat_str += "N";
}
else {
lat_str += "S";
}
pos.latitude = parse_lat_str(lat_str);
float lng = 0.0;
uint8_t information_start = get_information_start_index() + 1;
for(uint8_t i = information_start; i < information_start + 3 && i < payload_size - 2; i++){
uint8_t ascii = payload[i];
if(i - information_start == 0){ //deg
ascii -=28;
ascii += lng_offset;
if(ascii >= 180 && ascii <= 189){
ascii -= 80;
}
else if (ascii >= 190 && ascii <= 199){
ascii -= 190;
}
lng += ascii;
}
else if(i - information_start == 1){ //min
ascii -= 28;
if(ascii >= 60){
ascii -= 60;
}
lng += ascii/60.0;
}
else if(i - information_start == 2){ //hundredth minutes
ascii -= 28;
lng += (ascii/100.0)/60.0;
}
}
if(is_west){
lng = -lng;
}
pos.longitude = lng;
}
uint8_t get_mic_e_lat_digit(uint8_t ascii){
if(ascii >= '0' && ascii <= '9'){
return ascii;
}
if(ascii >= 'A' && ascii <= 'J'){
return ascii - 17;
}
if(ascii >= 'P' && ascii <='Y'){
return ascii - 32;
}
if(ascii == 'K' || ascii == 'L' || ascii == 'Z'){
return ' ';
}
return '\0';
}
bool is_mic_e_lat_N(uint8_t ascii){
if(ascii >= 'P' && ascii <='Z'){
return true;
}
return false; //not technical definition, but the other case is invalid
}
bool is_mic_e_lng_W(uint8_t ascii){
if(ascii >= 'P' && ascii <='Z'){
return true;
}
return false; //not technical definition, but the other case is invalid
}
uint8_t get_mic_e_lng_offset(uint8_t ascii){
if(ascii >= 'P' && ascii <='Z'){
return 100;
}
return 0; //not technical definition, but the other case is invalid
}
bool parse_address(uint8_t start, ADDRESS_TYPE address_type){
uint8_t byte = 0;
uint8_t has_more = false;
uint8_t ssid = 0;
uint8_t buffer_index = 0;
for(uint8_t i = start; i < start + ADDRESS_SIZE && i < payload_size - 2; i++){
byte = payload[i];
if(i - start == 6){
has_more = (byte & 0x1) == 0;
ssid = (byte >> 1) & 0x0F;
if(ssid != 0 || address_type == REPEATER){
address_buffer[buffer_index++] = '-';
if(ssid < 10){
address_buffer[buffer_index++] = '0' + ssid;
address_buffer[buffer_index++] = '\0';
}
else {
address_buffer[buffer_index++] = '1';
address_buffer[buffer_index++] = '0' + ssid - 10;
address_buffer[buffer_index++] = '\0';
}
}
else {
address_buffer[buffer_index++] = '\0';
}
}
else {
byte >>= 1;
if(byte != ' '){
address_buffer[buffer_index++] = byte;
}
}
}
return has_more;
}
public:
void set_timestamp(const Timestamp& value) {
timestamp_ = value;
}
Timestamp timestamp() const {
return timestamp_;
}
void set(const size_t index, const uint8_t data) {
payload[index] = data;
if (index + 1 > payload_size) {
payload_size = index + 1;
}
}
uint32_t operator[](const size_t index) const {
return payload[index];
}
uint8_t size() const {
return payload_size;
}
void set_valid_checksum(const bool valid) {
valid_checksum = valid;
}
bool is_valid_checksum() const {
return valid_checksum;
}
uint64_t get_source() {
uint64_t source = 0x0;
for (uint8_t i = SOURCE_START; i < SOURCE_START + ADDRESS_SIZE; i++) {
source |= (((uint64_t)payload[i]) << ((i - SOURCE_START) * 8));
}
return source;
}
std::string get_source_formatted() {
parse_address(SOURCE_START, SOURCE);
return std::string(address_buffer);
}
std::string get_destination_formatted() {
parse_address(DESTINATION_START, DESTINATION);
return std::string(address_buffer);
}
std::string get_digipeaters_formatted() {
uint8_t position = DIGIPEATER_START;
bool has_more = parse_address(SOURCE_START, REPEATER);
std::string repeaters = "";
while (has_more) {
has_more = parse_address(position, REPEATER);
repeaters += std::string(address_buffer);
position += ADDRESS_SIZE;
if (has_more) {
repeaters += ">";
}
}
return repeaters;
}
uint8_t get_number_of_digipeaters() {
uint8_t position = DIGIPEATER_START;
bool has_more = parse_address(SOURCE_START, REPEATER);
uint8_t repeaters = 0;
while (has_more) {
has_more = parse_address(position, REPEATER);
position += ADDRESS_SIZE;
repeaters++;
}
return repeaters;
}
uint8_t get_information_start_index() {
return DIGIPEATER_START + (get_number_of_digipeaters() * ADDRESS_SIZE) + 2;
}
std::string get_information_text_formatted() {
std::string information_text = "";
for (uint8_t i = get_information_start_index(); i < payload_size - 2; i++) {
information_text += payload[i];
}
return information_text;
}
std::string get_stream_text() {
std::string stream = get_source_formatted() + ">" + get_destination_formatted() + ";" + get_digipeaters_formatted() + ";" + get_information_text_formatted();
return stream;
}
char get_data_type_identifier() {
char ident = '\0';
for (uint8_t i = get_information_start_index(); i < payload_size - 2; i++) {
ident = payload[i];
break;
}
return ident;
}
bool has_position() {
char ident = get_data_type_identifier();
return ident == '!' ||
ident == '=' ||
ident == '/' ||
ident == '@' ||
ident == ';' ||
ident == '`' ||
ident == '\'' ||
ident == 0x1d ||
ident == 0x1c;
}
aprs_pos get_position() {
aprs::aprs_pos pos;
char ident = get_data_type_identifier();
std::string info_text = get_information_text_formatted();
std::string lat_str, lng_str;
char first;
// bool supports_compression = true;
bool is_mic_e_format = false;
std::string::size_type start;
switch (ident) {
case '/':
case '@':
start = 8;
break;
case '=':
case '!':
start = 1;
break;
case ';':
start = 18;
// supports_compression = false;
break;
case '`':
case '\'':
case 0x1c:
case 0x1d:
is_mic_e_format = true;
break;
default:
return pos;
}
if (is_mic_e_format) {
parse_mic_e_format(pos);
} else {
if (start < info_text.size()) {
first = info_text.at(start);
if (std::isdigit(first)) {
if (start + 18 < info_text.size()) {
lat_str = info_text.substr(start, 8);
pos.sym_table_id = info_text.at(start + 8);
lng_str = info_text.substr(start + 9, 9);
pos.symbol_code = info_text.at(start + 18);
pos.latitude = parse_lat_str(lat_str);
pos.longitude = parse_lng_str(lng_str);
}
} else {
if (start + 9 < info_text.size()) {
pos.sym_table_id = info_text.at(start);
lat_str = info_text.substr(start + 1, 4);
lng_str = info_text.substr(start + 5, 4);
pos.symbol_code = info_text.at(start + 9);
pos.latitude = parse_lat_str_cmp(lat_str);
pos.longitude = parse_lng_str_cmp(lng_str);
}
}
}
}
return pos;
}
void clear() {
payload_size = 0;
}
private:
const uint8_t DIGIPEATER_START = 14;
const uint8_t SOURCE_START = 7;
const uint8_t DESTINATION_START = 0;
const uint8_t ADDRESS_SIZE = 7;
bool valid_checksum = false;
uint8_t payload[256];
char address_buffer[15];
uint8_t payload_size = 0;
Timestamp timestamp_{};
float parse_lat_str_cmp(const std::string& lat_str) {
return 90.0 - ((lat_str.at(0) - 33) * (91 * 91 * 91) + (lat_str.at(1) - 33) * (91 * 91) + (lat_str.at(2) - 33) * 91 + (lat_str.at(3))) / 380926.0;
}
float parse_lng_str_cmp(const std::string& lng_str) {
return -180.0 + ((lng_str.at(0) - 33) * (91 * 91 * 91) + (lng_str.at(1) - 33) * (91 * 91) + (lng_str.at(2) - 33) * 91 + (lng_str.at(3))) / 190463.0;
}
uint8_t parse_digits(const std::string& str) {
if (str.at(0) == ' ') {
return 0;
}
uint8_t end = str.find_last_not_of(' ') + 1;
std::string sub = str.substr(0, end);
if (!is_digits(sub)) {
return 0;
} else {
return std::stoi(sub);
}
}
bool is_digits(const std::string& str) {
return str.find_last_not_of("0123456789") == std::string::npos;
}
float parse_lat_str(const std::string& lat_str) {
float lat = 0.0;
std::string str_lat_deg = lat_str.substr(0, 2);
std::string str_lat_min = lat_str.substr(2, 2);
std::string str_lat_hund = lat_str.substr(5, 2);
std::string dir = lat_str.substr(7, 1);
uint8_t lat_deg = parse_digits(str_lat_deg);
uint8_t lat_min = parse_digits(str_lat_min);
uint8_t lat_hund = parse_digits(str_lat_hund);
lat += lat_deg;
lat += (lat_min + (lat_hund / 100.0)) / 60.0;
if (dir.c_str()[0] == 'S') {
lat = -lat;
}
return lat;
}
float parse_lng_str(std::string& lng_str) {
float lng = 0.0;
std::string str_lng_deg = lng_str.substr(0, 3);
std::string str_lng_min = lng_str.substr(3, 2);
std::string str_lng_hund = lng_str.substr(6, 2);
std::string dir = lng_str.substr(8, 1);
uint8_t lng_deg = parse_digits(str_lng_deg);
uint8_t lng_min = parse_digits(str_lng_min);
uint8_t lng_hund = parse_digits(str_lng_hund);
lng += lng_deg;
lng += (lng_min + (lng_hund / 100.0)) / 60.0;
if (dir.c_str()[0] == 'W') {
lng = -lng;
}
return lng;
}
void parse_mic_e_format(aprs::aprs_pos& pos) {
std::string lat_str = "";
std::string lng_str = "";
bool is_north = false;
bool is_west = false;
uint8_t lng_offset = 0;
for (uint8_t i = DESTINATION_START; i < DESTINATION_START + ADDRESS_SIZE - 1; i++) {
uint8_t ascii = payload[i] >> 1;
lat_str += get_mic_e_lat_digit(ascii);
if (i - DESTINATION_START == 3) {
lat_str += ".";
}
if (i - DESTINATION_START == 3) {
is_north = is_mic_e_lat_N(ascii);
}
if (i - DESTINATION_START == 4) {
lng_offset = get_mic_e_lng_offset(ascii);
}
if (i - DESTINATION_START == 5) {
is_west = is_mic_e_lng_W(ascii);
}
}
if (is_north) {
lat_str += "N";
} else {
lat_str += "S";
}
pos.latitude = parse_lat_str(lat_str);
float lng = 0.0;
uint8_t information_start = get_information_start_index() + 1;
for (uint8_t i = information_start; i < information_start + 3 && i < payload_size - 2; i++) {
uint8_t ascii = payload[i];
if (i - information_start == 0) { // deg
ascii -= 28;
ascii += lng_offset;
if (ascii >= 180 && ascii <= 189) {
ascii -= 80;
} else if (ascii >= 190 && ascii <= 199) {
ascii -= 190;
}
lng += ascii;
} else if (i - information_start == 1) { // min
ascii -= 28;
if (ascii >= 60) {
ascii -= 60;
}
lng += ascii / 60.0;
} else if (i - information_start == 2) { // hundredth minutes
ascii -= 28;
lng += (ascii / 100.0) / 60.0;
}
}
if (is_west) {
lng = -lng;
}
pos.longitude = lng;
}
uint8_t get_mic_e_lat_digit(uint8_t ascii) {
if (ascii >= '0' && ascii <= '9') {
return ascii;
}
if (ascii >= 'A' && ascii <= 'J') {
return ascii - 17;
}
if (ascii >= 'P' && ascii <= 'Y') {
return ascii - 32;
}
if (ascii == 'K' || ascii == 'L' || ascii == 'Z') {
return ' ';
}
return '\0';
}
bool is_mic_e_lat_N(uint8_t ascii) {
if (ascii >= 'P' && ascii <= 'Z') {
return true;
}
return false; // not technical definition, but the other case is invalid
}
bool is_mic_e_lng_W(uint8_t ascii) {
if (ascii >= 'P' && ascii <= 'Z') {
return true;
}
return false; // not technical definition, but the other case is invalid
}
uint8_t get_mic_e_lng_offset(uint8_t ascii) {
if (ascii >= 'P' && ascii <= 'Z') {
return 100;
}
return 0; // not technical definition, but the other case is invalid
}
bool parse_address(uint8_t start, ADDRESS_TYPE address_type) {
uint8_t byte = 0;
uint8_t has_more = false;
uint8_t ssid = 0;
uint8_t buffer_index = 0;
for (uint8_t i = start; i < start + ADDRESS_SIZE && i < payload_size - 2; i++) {
byte = payload[i];
if (i - start == 6) {
has_more = (byte & 0x1) == 0;
ssid = (byte >> 1) & 0x0F;
if (ssid != 0 || address_type == REPEATER) {
address_buffer[buffer_index++] = '-';
if (ssid < 10) {
address_buffer[buffer_index++] = '0' + ssid;
address_buffer[buffer_index++] = '\0';
} else {
address_buffer[buffer_index++] = '1';
address_buffer[buffer_index++] = '0' + ssid - 10;
address_buffer[buffer_index++] = '\0';
}
} else {
address_buffer[buffer_index++] = '\0';
}
} else {
byte >>= 1;
if (byte != ' ') {
address_buffer[buffer_index++] = byte;
}
}
}
return has_more;
}
};
} /* namespace aprs */
#endif/*__APRS_PACKET_H__*/
#endif /*__APRS_PACKET_H__*/

View File

@@ -26,75 +26,75 @@
namespace portapack {
void BacklightOnOff::on() {
if( !is_on() ) {
io.lcd_backlight(true);
on_ = true;
}
if (!is_on()) {
io.lcd_backlight(true);
on_ = true;
}
}
void BacklightOnOff::off() {
if( is_on() ) {
io.lcd_backlight(false);
on_ = false;
}
if (is_on()) {
io.lcd_backlight(false);
on_ = false;
}
}
void BacklightCAT4004::set_level(const value_t value) {
auto target = value;
void BacklightCAT4004::set_level(const value_t value) {
auto target = value;
// Clip target value to valid range.
if( target < 0 ) {
target = 0;
}
if( target > maximum_level ) {
target = maximum_level;
}
// Clip target value to valid range.
if (target < 0) {
target = 0;
}
if (target > maximum_level) {
target = maximum_level;
}
if( is_on() ) {
pulses(target);
} else {
level_ = target;
}
if (is_on()) {
pulses(target);
} else {
level_ = target;
}
}
void BacklightCAT4004::on() {
if( !is_on() ) {
io.lcd_backlight(true);
halPolledDelay(ticks_setup);
on_ = true;
if (!is_on()) {
io.lcd_backlight(true);
halPolledDelay(ticks_setup);
on_ = true;
// Just enabled driver, initial value is maximum.
const auto target_level = level();
level_ = maximum_level;
// Just enabled driver, initial value is maximum.
const auto target_level = level();
level_ = maximum_level;
pulses(target_level);
}
pulses(target_level);
}
}
void BacklightCAT4004::off() {
if( is_on() ) {
io.lcd_backlight(false);
chThdSleepMilliseconds(ms_pwrdwn);
on_ = false;
}
if (is_on()) {
io.lcd_backlight(false);
chThdSleepMilliseconds(ms_pwrdwn);
on_ = false;
}
}
void BacklightCAT4004::pulses(value_t target) {
while(level() != target) {
pulse();
}
while (level() != target) {
pulse();
}
}
void BacklightCAT4004::pulse() {
io.lcd_backlight(false);
halPolledDelay(ticks_lo);
io.lcd_backlight(true);
halPolledDelay(ticks_hi);
io.lcd_backlight(false);
halPolledDelay(ticks_lo);
io.lcd_backlight(true);
halPolledDelay(ticks_hi);
level_ -= 1;
if( level_ < 0 ) {
level_ = levels() - 1;
}
level_ -= 1;
if (level_ < 0) {
level_ = levels() - 1;
}
}
} /* namespace portapack */

View File

@@ -26,95 +26,95 @@
namespace portapack {
class Backlight {
public:
using value_t = int_fast8_t;
public:
using value_t = int_fast8_t;
virtual ~Backlight() = default;
virtual ~Backlight() = default;
virtual value_t levels() const = 0;
virtual value_t levels() const = 0;
virtual void set_level(const value_t value) = 0;
virtual value_t level() const = 0;
virtual void set_level(const value_t value) = 0;
virtual value_t level() const = 0;
virtual void increase() = 0;
virtual void decrease() = 0;
virtual void increase() = 0;
virtual void decrease() = 0;
virtual void on() = 0;
virtual void off() = 0;
virtual void on() = 0;
virtual void off() = 0;
virtual bool is_on() const = 0;
virtual bool is_on() const = 0;
};
class BacklightBase : public Backlight {
public:
void increase() override {
set_level(level() + 1);
}
public:
void increase() override {
set_level(level() + 1);
}
void decrease() override {
set_level(level() - 1);
}
void decrease() override {
set_level(level() - 1);
}
};
class BacklightOnOff : public BacklightBase {
public:
value_t levels() const override {
return 1;
}
public:
value_t levels() const override {
return 1;
}
void set_level(const value_t) override {
}
void set_level(const value_t) override {
}
value_t level() const override {
return levels() - 1;
}
value_t level() const override {
return levels() - 1;
}
void on() override;
void off() override;
void on() override;
void off() override;
bool is_on() const override {
return on_;
}
bool is_on() const override {
return on_;
}
private:
static constexpr value_t maximum_level = 1;
private:
static constexpr value_t maximum_level = 1;
bool on_ { false };
bool on_{false};
};
class BacklightCAT4004 : public BacklightBase {
public:
value_t levels() const override {
return maximum_level + 1;
}
public:
value_t levels() const override {
return maximum_level + 1;
}
void set_level(const value_t value) override;
void set_level(const value_t value) override;
value_t level() const override {
return level_;
}
value_t level() const override {
return level_;
}
void on() override;
void off() override;
void on() override;
void off() override;
bool is_on() const override {
return on_;
}
bool is_on() const override {
return on_;
}
private:
static constexpr value_t initial_brightness = 25;
static constexpr value_t maximum_level = 31;
private:
static constexpr value_t initial_brightness = 25;
static constexpr value_t maximum_level = 31;
static constexpr uint32_t ticks_setup = 204e6 * 10e-6;
static constexpr uint32_t ms_pwrdwn = 5;
static constexpr uint32_t ticks_lo = 204e6 * 1e-6;
static constexpr uint32_t ticks_hi = 204e6 * 1e-6;
static constexpr uint32_t ticks_setup = 204e6 * 10e-6;
static constexpr uint32_t ms_pwrdwn = 5;
static constexpr uint32_t ticks_lo = 204e6 * 1e-6;
static constexpr uint32_t ticks_hi = 204e6 * 1e-6;
value_t level_ { initial_brightness };
bool on_ { false };
value_t level_{initial_brightness};
bool on_{false};
void pulses(value_t target);
void pulse();
void pulses(value_t target);
void pulse();
};
} /* namespace portapack */

View File

@@ -31,10 +31,10 @@ using sample_t = complex8_t;
using buffer_t = buffer_t<sample_t>;
enum class Direction {
Receive = 0,
Transmit = 1,
Receive = 0,
Transmit = 1,
};
} /* namespace baseband */
#endif/*__BASEBAND_H__*/
#endif /*__BASEBAND_H__*/

View File

@@ -27,12 +27,12 @@ using namespace hackrf::one;
namespace baseband {
void CPLD::init() {
set_invert(false);
gpio_q_invert.output();
set_invert(false);
gpio_q_invert.output();
}
void CPLD::set_invert(const bool invert) {
gpio_q_invert.write(invert);
gpio_q_invert.write(invert);
}
}
} // namespace baseband

View File

@@ -27,14 +27,14 @@
namespace baseband {
class CPLD {
public:
void init();
public:
void init();
void set_invert(const bool invert);
private:
void set_invert(const bool invert);
private:
};
}
} // namespace baseband
#endif/*__BASEBAND_CPLD_H__*/
#endif /*__BASEBAND_CPLD_H__*/

View File

@@ -30,43 +30,43 @@
namespace baseband {
class Packet {
public:
void set_timestamp(const Timestamp& value) {
timestamp_ = value;
}
Timestamp timestamp() const {
return timestamp_;
}
public:
void set_timestamp(const Timestamp& value) {
timestamp_ = value;
}
void add(const bool symbol) {
if( count < capacity() ) {
data[count++] = symbol;
}
}
Timestamp timestamp() const {
return timestamp_;
}
uint_fast8_t operator[](const size_t index) const {
return (index < size()) ? data[index] : 0;
}
void add(const bool symbol) {
if (count < capacity()) {
data[count++] = symbol;
}
}
size_t size() const {
return count;
}
uint_fast8_t operator[](const size_t index) const {
return (index < size()) ? data[index] : 0;
}
size_t capacity() const {
return data.size();
}
size_t size() const {
return count;
}
void clear() {
count = 0;
}
size_t capacity() const {
return data.size();
}
private:
std::bitset<2560> data { };
Timestamp timestamp_ { };
size_t count { 0 };
void clear() {
count = 0;
}
private:
std::bitset<2560> data{};
Timestamp timestamp_{};
size_t count{0};
};
} /* namespace baseband */
#endif/*__BASEBAND_PACKET_H__*/
#endif /*__BASEBAND_PACKET_H__*/

View File

@@ -29,134 +29,134 @@ namespace baseband {
/*
struct PinConfig {
P_OUT_CFG p_out_cfg;
P_OE_CFG p_oe_cfg { P_OE_CFG::GPIO_OE };
P_OUT_CFG p_out_cfg;
P_OE_CFG p_oe_cfg { P_OE_CFG::GPIO_OE };
constexpr SGPIOPinConfig(
P_OUT_CFG p_out_cfg
) :
p_out_cfg(p_out_cfg)
{
}
constexpr SGPIOPinConfig(
P_OUT_CFG p_out_cfg
) :
p_out_cfg(p_out_cfg)
{
}
};
static constexpr bool slice_mode_multislice = false;
static constexpr P_OUT_CFG output_multiplexing_mode =
slice_mode_multislice ? P_OUT_CFG::DOUT_DOUTM8C : P_OUT_CFG::DOUT_DOUTM8A;
slice_mode_multislice ? P_OUT_CFG::DOUT_DOUTM8C : P_OUT_CFG::DOUT_DOUTM8A;
static constexpr std::array<PinConfig, 16> pin_config { {
[PIN_D0] = { output_multiplexing_mode, SLICE_A },
[PIN_D1] = { output_multiplexing_mode, SLICE_I },
[PIN_D2] = { output_multiplexing_mode, },
[PIN_D3] = { output_multiplexing_mode, },
[PIN_D4] = { output_multiplexing_mode, },
[PIN_D5] = { output_multiplexing_mode, },
[PIN_D6] = { output_multiplexing_mode, },
[PIN_D7] = { output_multiplexing_mode, },
[PIN_CLKIN] = { P_OUT_CFG::DOUT_DOUTM1, },
[PIN_CAPTURE] = { P_OUT_CFG::DOUT_DOUTM1, },
[PIN_DISABLE] = { P_OUT_CFG::GPIO_OUT, },
[PIN_DIRECTION] = { P_OUT_CFG::GPIO_OUT, },
[PIN_INVERT] = { P_OUT_CFG::GPIO_OUT, },
[PIN_DECIM0] = { P_OUT_CFG::GPIO_OUT, },
[PIN_DECIM1] = { P_OUT_CFG::DOUT_DOUTM1, },
[PIN_DECIM2] = { P_OUT_CFG::GPIO_OUT, },
[PIN_D0] = { output_multiplexing_mode, SLICE_A },
[PIN_D1] = { output_multiplexing_mode, SLICE_I },
[PIN_D2] = { output_multiplexing_mode, },
[PIN_D3] = { output_multiplexing_mode, },
[PIN_D4] = { output_multiplexing_mode, },
[PIN_D5] = { output_multiplexing_mode, },
[PIN_D6] = { output_multiplexing_mode, },
[PIN_D7] = { output_multiplexing_mode, },
[PIN_CLKIN] = { P_OUT_CFG::DOUT_DOUTM1, },
[PIN_CAPTURE] = { P_OUT_CFG::DOUT_DOUTM1, },
[PIN_DISABLE] = { P_OUT_CFG::GPIO_OUT, },
[PIN_DIRECTION] = { P_OUT_CFG::GPIO_OUT, },
[PIN_INVERT] = { P_OUT_CFG::GPIO_OUT, },
[PIN_DECIM0] = { P_OUT_CFG::GPIO_OUT, },
[PIN_DECIM1] = { P_OUT_CFG::DOUT_DOUTM1, },
[PIN_DECIM2] = { P_OUT_CFG::GPIO_OUT, },
} };
*/
/*
static constexpr std::array<LPC_SGPIO_OUT_MUX_CFG_Type, 16> out_mux_cfg_receive {
{ },
{ },
};
static constexpr std::array<LPC_SGPIO_OUT_MUX_CFG_Type, 16> out_mux_cfg_transmit {
{ },
{ },
};
*/
enum class P_OUT_CFG : uint8_t {
DOUT_DOUTM1 = 0x0,
DOUT_DOUTM2A = 0x1,
DOUT_DOUTM2B = 0x2,
DOUT_DOUTM2C = 0x3,
GPIO_OUT = 0x4,
DOUT_DOUTM4A = 0x5,
DOUT_DOUTM4B = 0x6,
DOUT_DOUTM4C = 0x7,
CLK_OUT = 0x8,
DOUT_DOUTM8A = 0x9,
DOUT_DOUTM8B = 0xa,
DOUT_DOUTM8C = 0xb,
DOUT_DOUTM1 = 0x0,
DOUT_DOUTM2A = 0x1,
DOUT_DOUTM2B = 0x2,
DOUT_DOUTM2C = 0x3,
GPIO_OUT = 0x4,
DOUT_DOUTM4A = 0x5,
DOUT_DOUTM4B = 0x6,
DOUT_DOUTM4C = 0x7,
CLK_OUT = 0x8,
DOUT_DOUTM8A = 0x9,
DOUT_DOUTM8B = 0xa,
DOUT_DOUTM8C = 0xb,
};
enum class P_OE_CFG : uint8_t {
GPIO_OE = 0x0,
DOUT_OEM1 = 0x4,
DOUT_OEM2 = 0x5,
DOUT_OEM4 = 0x6,
DOUT_OEM8 = 0x7,
GPIO_OE = 0x0,
DOUT_OEM1 = 0x4,
DOUT_OEM2 = 0x5,
DOUT_OEM4 = 0x6,
DOUT_OEM8 = 0x7,
};
enum class CONCAT_ORDER : uint8_t {
SELF_LOOP = 0x0,
TWO_SLICES = 0x1,
FOUR_SLICES = 0x2,
EIGHT_SLICES = 0x3,
SELF_LOOP = 0x0,
TWO_SLICES = 0x1,
FOUR_SLICES = 0x2,
EIGHT_SLICES = 0x3,
};
enum class CONCAT_ENABLE : uint8_t {
EXTERNAL_DATA_PIN = 0x0,
CONCATENATE_DATA = 0x1,
EXTERNAL_DATA_PIN = 0x0,
CONCATENATE_DATA = 0x1,
};
enum class CLK_CAPTURE_MODE : uint8_t {
RISING_CLOCK_EDGE = 0,
FALLING_CLOCK_EDGE = 1,
RISING_CLOCK_EDGE = 0,
FALLING_CLOCK_EDGE = 1,
};
enum class PARALLEL_MODE : uint8_t {
SHIFT_1_BIT_PER_CLOCK = 0x0,
SHIFT_2_BITS_PER_CLOCK = 0x1,
SHIFT_4_BITS_PER_CLOCK = 0x2,
SHIFT_1_BYTE_PER_CLOCK = 0x3,
SHIFT_1_BIT_PER_CLOCK = 0x0,
SHIFT_2_BITS_PER_CLOCK = 0x1,
SHIFT_4_BITS_PER_CLOCK = 0x2,
SHIFT_1_BYTE_PER_CLOCK = 0x3,
};
enum {
PIN_D0 = 0,
PIN_D1 = 1,
PIN_D2 = 2,
PIN_D3 = 3,
PIN_D4 = 4,
PIN_D5 = 5,
PIN_D6 = 6,
PIN_D7 = 7,
PIN_CLKIN = 8,
PIN_CAPTURE = 9,
PIN_DISABLE = 10,
PIN_DIRECTION = 11,
PIN_INVERT = 12,
PIN_SYNC_EN = 13,
PIN_P81 = 14,
PIN_P78 = 15,
PIN_D0 = 0,
PIN_D1 = 1,
PIN_D2 = 2,
PIN_D3 = 3,
PIN_D4 = 4,
PIN_D5 = 5,
PIN_D6 = 6,
PIN_D7 = 7,
PIN_CLKIN = 8,
PIN_CAPTURE = 9,
PIN_DISABLE = 10,
PIN_DIRECTION = 11,
PIN_INVERT = 12,
PIN_SYNC_EN = 13,
PIN_P81 = 14,
PIN_P78 = 15,
};
enum class Slice : uint8_t {
A = 0,
B = 1,
C = 2,
D = 3,
E = 4,
F = 5,
G = 6,
H = 7,
I = 8,
J = 9,
K = 10,
L = 11,
M = 12,
N = 13,
O = 14,
P = 15,
A = 0,
B = 1,
C = 2,
D = 3,
E = 4,
F = 5,
G = 6,
H = 7,
I = 8,
J = 9,
K = 10,
L = 11,
M = 12,
N = 13,
O = 14,
P = 15,
};
constexpr bool slice_mode_multislice = false;
@@ -164,229 +164,179 @@ constexpr bool slice_mode_multislice = false;
constexpr uint8_t pos_count_multi_slice = 0x1f;
constexpr uint8_t pos_count_single_slice = 0x03;
constexpr Slice slice_order[] {
Slice::A,
Slice::I,
Slice::E,
Slice::J,
Slice::C,
Slice::K,
Slice::F,
Slice::L,
Slice::B,
Slice::M,
Slice::G,
Slice::N,
Slice::D,
Slice::O,
Slice::H,
Slice::P,
constexpr Slice slice_order[]{
Slice::A,
Slice::I,
Slice::E,
Slice::J,
Slice::C,
Slice::K,
Slice::F,
Slice::L,
Slice::B,
Slice::M,
Slice::G,
Slice::N,
Slice::D,
Slice::O,
Slice::H,
Slice::P,
};
constexpr uint32_t gpio_outreg(const Direction direction) {
return ((direction == Direction::Transmit) ? (1U << PIN_DIRECTION) : 0U) | (1U << PIN_DISABLE);
return ((direction == Direction::Transmit) ? (1U << PIN_DIRECTION) : 0U) | (1U << PIN_DISABLE);
}
constexpr uint32_t gpio_oenreg(const Direction direction) {
return
(0U << PIN_P78)
| (0U << PIN_P81)
| (0U << PIN_SYNC_EN)
| (0U << PIN_INVERT)
| (1U << PIN_DIRECTION)
| (1U << PIN_DISABLE)
| (0U << PIN_CAPTURE)
| (0U << PIN_CLKIN)
| ((direction == Direction::Transmit) ? 0xffU : 0x00U)
;
return (0U << PIN_P78) | (0U << PIN_P81) | (0U << PIN_SYNC_EN) | (0U << PIN_INVERT) | (1U << PIN_DIRECTION) | (1U << PIN_DISABLE) | (0U << PIN_CAPTURE) | (0U << PIN_CLKIN) | ((direction == Direction::Transmit) ? 0xffU : 0x00U);
}
constexpr uint32_t out_mux_cfg(const P_OUT_CFG out, const P_OE_CFG oe) {
return
(toUType(out) << 0)
| (toUType(oe) << 4)
;
return (toUType(out) << 0) | (toUType(oe) << 4);
}
constexpr uint32_t data_sgpio_mux_cfg(
const CONCAT_ENABLE concat_enable,
const CONCAT_ORDER concat_order
) {
return
(1U << 0)
| (0U << 1)
| (0U << 3)
| (3U << 5)
| (1U << 7)
| (0U << 9)
| (toUType(concat_enable) << 11)
| (toUType(concat_order) << 12)
;
const CONCAT_ENABLE concat_enable,
const CONCAT_ORDER concat_order) {
return (1U << 0) | (0U << 1) | (0U << 3) | (3U << 5) | (1U << 7) | (0U << 9) | (toUType(concat_enable) << 11) | (toUType(concat_order) << 12);
}
constexpr uint32_t data_slice_mux_cfg(
const PARALLEL_MODE parallel_mode,
const CLK_CAPTURE_MODE clk_capture_mode
) {
return
(0U << 0)
| (toUType(clk_capture_mode) << 1)
| (1U << 2)
| (0U << 3)
| (0U << 4)
| (toUType(parallel_mode) << 6)
| (0U << 8)
;
const PARALLEL_MODE parallel_mode,
const CLK_CAPTURE_MODE clk_capture_mode) {
return (0U << 0) | (toUType(clk_capture_mode) << 1) | (1U << 2) | (0U << 3) | (0U << 4) | (toUType(parallel_mode) << 6) | (0U << 8);
}
constexpr uint32_t pos(
const uint32_t pos,
const uint32_t pos_reset
) {
return
(pos << 0)
| (pos_reset << 8)
;
const uint32_t pos,
const uint32_t pos_reset) {
return (pos << 0) | (pos_reset << 8);
}
constexpr uint32_t data_pos(
const bool multi_slice
) {
return pos(
(multi_slice ? pos_count_multi_slice : pos_count_single_slice),
(multi_slice ? pos_count_multi_slice : pos_count_single_slice)
);
const bool multi_slice) {
return pos(
(multi_slice ? pos_count_multi_slice : pos_count_single_slice),
(multi_slice ? pos_count_multi_slice : pos_count_single_slice));
}
constexpr CONCAT_ENABLE data_concat_enable(
const bool input_slice,
const bool single_slice
) {
return (input_slice || single_slice)
? CONCAT_ENABLE::EXTERNAL_DATA_PIN
: CONCAT_ENABLE::CONCATENATE_DATA
;
const bool input_slice,
const bool single_slice) {
return (input_slice || single_slice)
? CONCAT_ENABLE::EXTERNAL_DATA_PIN
: CONCAT_ENABLE::CONCATENATE_DATA;
}
constexpr CONCAT_ORDER data_concat_order(
const bool input_slice,
const bool single_slice
) {
return (input_slice || single_slice)
? CONCAT_ORDER::SELF_LOOP
: CONCAT_ORDER::EIGHT_SLICES
;
const bool input_slice,
const bool single_slice) {
return (input_slice || single_slice)
? CONCAT_ORDER::SELF_LOOP
: CONCAT_ORDER::EIGHT_SLICES;
}
constexpr CLK_CAPTURE_MODE data_clk_capture_mode(
const Direction direction
) {
return (direction == Direction::Transmit)
? CLK_CAPTURE_MODE::RISING_CLOCK_EDGE
: CLK_CAPTURE_MODE::RISING_CLOCK_EDGE
;
const Direction direction) {
return (direction == Direction::Transmit)
? CLK_CAPTURE_MODE::RISING_CLOCK_EDGE
: CLK_CAPTURE_MODE::RISING_CLOCK_EDGE;
}
constexpr P_OUT_CFG data_p_out_cfg(
const bool multi_slice
) {
return (multi_slice)
? P_OUT_CFG::DOUT_DOUTM8C
: P_OUT_CFG::DOUT_DOUTM8A
;
const bool multi_slice) {
return (multi_slice)
? P_OUT_CFG::DOUT_DOUTM8C
: P_OUT_CFG::DOUT_DOUTM8A;
}
static const sgpio_resources_t sgpio_resources = {
.base = { .clk = &LPC_CGU->BASE_PERIPH_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 6) },
.branch = { .cfg = &LPC_CCU1->CLK_PERIPH_SGPIO_CFG, .stat = &LPC_CCU1->CLK_PERIPH_SGPIO_STAT },
.reset = { .output_index = 57 },
.base = {.clk = &LPC_CGU->BASE_PERIPH_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 6)},
.branch = {.cfg = &LPC_CCU1->CLK_PERIPH_SGPIO_CFG, .stat = &LPC_CCU1->CLK_PERIPH_SGPIO_STAT},
.reset = {.output_index = 57},
};
void SGPIO::init() {
base_clock_enable(&sgpio_resources.base);
branch_clock_enable(&sgpio_resources.branch);
peripheral_reset(&sgpio_resources.reset);
base_clock_enable(&sgpio_resources.base);
branch_clock_enable(&sgpio_resources.branch);
peripheral_reset(&sgpio_resources.reset);
}
void SGPIO::configure(const Direction direction) {
disable_all_slice_counters();
disable_all_slice_counters();
// Set data pins as input, temporarily.
LPC_SGPIO->GPIO_OENREG = gpio_oenreg(Direction::Receive);
// Set data pins as input, temporarily.
LPC_SGPIO->GPIO_OENREG = gpio_oenreg(Direction::Receive);
// Now that data pins are inputs, safe to change CPLD direction.
LPC_SGPIO->GPIO_OUTREG = gpio_outreg(direction);
// Now that data pins are inputs, safe to change CPLD direction.
LPC_SGPIO->GPIO_OUTREG = gpio_outreg(direction);
LPC_SGPIO->OUT_MUX_CFG[ 8] = out_mux_cfg(P_OUT_CFG::DOUT_DOUTM1, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[ 9] = out_mux_cfg(P_OUT_CFG::DOUT_DOUTM1, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[10] = out_mux_cfg(P_OUT_CFG::GPIO_OUT, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[11] = out_mux_cfg(P_OUT_CFG::GPIO_OUT, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[12] = out_mux_cfg(P_OUT_CFG::GPIO_OUT, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[13] = out_mux_cfg(P_OUT_CFG::GPIO_OUT, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[14] = out_mux_cfg(P_OUT_CFG::DOUT_DOUTM1, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[15] = out_mux_cfg(P_OUT_CFG::GPIO_OUT, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[8] = out_mux_cfg(P_OUT_CFG::DOUT_DOUTM1, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[9] = out_mux_cfg(P_OUT_CFG::DOUT_DOUTM1, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[10] = out_mux_cfg(P_OUT_CFG::GPIO_OUT, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[11] = out_mux_cfg(P_OUT_CFG::GPIO_OUT, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[12] = out_mux_cfg(P_OUT_CFG::GPIO_OUT, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[13] = out_mux_cfg(P_OUT_CFG::GPIO_OUT, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[14] = out_mux_cfg(P_OUT_CFG::DOUT_DOUTM1, P_OE_CFG::GPIO_OE);
LPC_SGPIO->OUT_MUX_CFG[15] = out_mux_cfg(P_OUT_CFG::GPIO_OUT, P_OE_CFG::GPIO_OE);
const auto data_out_mux_cfg = out_mux_cfg(data_p_out_cfg(slice_mode_multislice), P_OE_CFG::GPIO_OE);
for(size_t i=0; i<8; i++) {
LPC_SGPIO->OUT_MUX_CFG[i] = data_out_mux_cfg;
}
const auto data_out_mux_cfg = out_mux_cfg(data_p_out_cfg(slice_mode_multislice), P_OE_CFG::GPIO_OE);
for (size_t i = 0; i < 8; i++) {
LPC_SGPIO->OUT_MUX_CFG[i] = data_out_mux_cfg;
}
// Now that output enable sources are set, enable data bus in correct direction.
LPC_SGPIO->GPIO_OENREG = gpio_oenreg(direction);
// Now that output enable sources are set, enable data bus in correct direction.
LPC_SGPIO->GPIO_OENREG = gpio_oenreg(direction);
const auto slice_gpdma = Slice::H;
const auto slice_gpdma = Slice::H;
const size_t slice_count = slice_mode_multislice ? 8 : 1;
const auto clk_capture_mode = data_clk_capture_mode(direction);
const auto single_slice = !slice_mode_multislice;
const size_t slice_count = slice_mode_multislice ? 8 : 1;
const auto clk_capture_mode = data_clk_capture_mode(direction);
const auto single_slice = !slice_mode_multislice;
uint32_t slice_enable_mask = 0;
for(size_t i=0; i<slice_count; i++) {
const auto slice = slice_order[i];
const auto slice_index = toUType(slice);
const auto input_slice = (i == 0) && (direction != Direction::Transmit);
const auto concat_order = data_concat_order(input_slice, single_slice);
const auto concat_enable = data_concat_enable(input_slice, single_slice);
uint32_t slice_enable_mask = 0;
for (size_t i = 0; i < slice_count; i++) {
const auto slice = slice_order[i];
const auto slice_index = toUType(slice);
const auto input_slice = (i == 0) && (direction != Direction::Transmit);
const auto concat_order = data_concat_order(input_slice, single_slice);
const auto concat_enable = data_concat_enable(input_slice, single_slice);
LPC_SGPIO->SGPIO_MUX_CFG[slice_index] = data_sgpio_mux_cfg(
concat_enable,
concat_order
);
LPC_SGPIO->SLICE_MUX_CFG[slice_index] = data_slice_mux_cfg(
PARALLEL_MODE::SHIFT_1_BYTE_PER_CLOCK,
clk_capture_mode
);
LPC_SGPIO->SGPIO_MUX_CFG[slice_index] = data_sgpio_mux_cfg(
concat_enable,
concat_order);
LPC_SGPIO->SLICE_MUX_CFG[slice_index] = data_slice_mux_cfg(
PARALLEL_MODE::SHIFT_1_BYTE_PER_CLOCK,
clk_capture_mode);
LPC_SGPIO->PRESET[slice_index] = 0;
LPC_SGPIO->COUNT[slice_index] = 0;
LPC_SGPIO->POS[slice_index] = data_pos(slice_mode_multislice);
LPC_SGPIO->REG[slice_index] = 0;
LPC_SGPIO->REG_SS[slice_index] = 0;
LPC_SGPIO->PRESET[slice_index] = 0;
LPC_SGPIO->COUNT[slice_index] = 0;
LPC_SGPIO->POS[slice_index] = data_pos(slice_mode_multislice);
LPC_SGPIO->REG[slice_index] = 0;
LPC_SGPIO->REG_SS[slice_index] = 0;
slice_enable_mask |= (1U << slice_index);
}
slice_enable_mask |= (1U << slice_index);
}
if( !slice_mode_multislice ) {
const auto slice_index = toUType(slice_gpdma);
if (!slice_mode_multislice) {
const auto slice_index = toUType(slice_gpdma);
LPC_SGPIO->SGPIO_MUX_CFG[slice_index] = data_sgpio_mux_cfg(
CONCAT_ENABLE::CONCATENATE_DATA,
CONCAT_ORDER::SELF_LOOP
);
LPC_SGPIO->SLICE_MUX_CFG[slice_index] = data_slice_mux_cfg(
PARALLEL_MODE::SHIFT_1_BIT_PER_CLOCK,
clk_capture_mode
);
LPC_SGPIO->SGPIO_MUX_CFG[slice_index] = data_sgpio_mux_cfg(
CONCAT_ENABLE::CONCATENATE_DATA,
CONCAT_ORDER::SELF_LOOP);
LPC_SGPIO->SLICE_MUX_CFG[slice_index] = data_slice_mux_cfg(
PARALLEL_MODE::SHIFT_1_BIT_PER_CLOCK,
clk_capture_mode);
LPC_SGPIO->PRESET[slice_index] = 0;
LPC_SGPIO->COUNT[slice_index] = 0;
LPC_SGPIO->POS[slice_index] = pos(0x1f, 0x1f);
LPC_SGPIO->REG[slice_index] = 0x11111111;
LPC_SGPIO->REG_SS[slice_index] = 0x11111111;
LPC_SGPIO->PRESET[slice_index] = 0;
LPC_SGPIO->COUNT[slice_index] = 0;
LPC_SGPIO->POS[slice_index] = pos(0x1f, 0x1f);
LPC_SGPIO->REG[slice_index] = 0x11111111;
LPC_SGPIO->REG_SS[slice_index] = 0x11111111;
slice_enable_mask |= (1 << slice_index);
}
slice_enable_mask |= (1 << slice_index);
}
set_slice_counter_enables(slice_enable_mask);
set_slice_counter_enables(slice_enable_mask);
}
} /* namespace baseband */

View File

@@ -31,36 +31,36 @@
namespace baseband {
class SGPIO {
public:
void init();
public:
void init();
void configure(const Direction direction);
void configure(const Direction direction);
void streaming_enable() {
/* TODO: Any reason not to control from general GPIO facility? */
LPC_SGPIO->GPIO_OUTREG &= ~(1U << 10);
}
void streaming_enable() {
/* TODO: Any reason not to control from general GPIO facility? */
LPC_SGPIO->GPIO_OUTREG &= ~(1U << 10);
}
void streaming_disable() {
/* TODO: Any reason not to control from general GPIO facility? */
LPC_SGPIO->GPIO_OUTREG |= (1U << 10);
}
void streaming_disable() {
/* TODO: Any reason not to control from general GPIO facility? */
LPC_SGPIO->GPIO_OUTREG |= (1U << 10);
}
bool streaming_is_enabled() const {
/* TODO: Any reason not to control from general GPIO facility? */
return (LPC_SGPIO->GPIO_OUTREG >> 10) & 1;
}
bool streaming_is_enabled() const {
/* TODO: Any reason not to control from general GPIO facility? */
return (LPC_SGPIO->GPIO_OUTREG >> 10) & 1;
}
private:
void disable_all_slice_counters() {
set_slice_counter_enables(0);
}
private:
void disable_all_slice_counters() {
set_slice_counter_enables(0);
}
void set_slice_counter_enables(const uint16_t enable_mask) {
LPC_SGPIO->CTRL_ENABLE = enable_mask;
}
void set_slice_counter_enables(const uint16_t enable_mask) {
LPC_SGPIO->CTRL_ENABLE = enable_mask;
}
};
}
} // namespace baseband
#endif/*__BASEBAND_GPIO_H__*/
#endif /*__BASEBAND_GPIO_H__*/

View File

@@ -3,7 +3,7 @@
* Copyright (C) 2016 Furrtek
*
* BCH Encoder/Decoder - Adapted from GNURadio
*
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
@@ -29,280 +29,264 @@
#include "bch_code.hpp"
void BCHCode::generate_gf() {
/*
* generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m]
* lookup tables: index->polynomial form alpha_to[] contains j=alpha**i;
* polynomial form -> index form index_of[j=alpha**i] = i alpha=2 is the
* primitive element of GF(2**m)
*/
int i, mask;
mask = 1;
alpha_to[m] = 0;
for (i = 0; i < m; i++)
{
alpha_to[i] = mask;
index_of[alpha_to[i]] = i;
if (p[i] != 0)
alpha_to[m] ^= mask;
mask <<= 1;
}
/*
* generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m]
* lookup tables: index->polynomial form alpha_to[] contains j=alpha**i;
* polynomial form -> index form index_of[j=alpha**i] = i alpha=2 is the
* primitive element of GF(2**m)
*/
index_of[alpha_to[m]] = m;
mask >>= 1;
for (i = m + 1; i < n; i++)
{
if (alpha_to[i - 1] >= mask)
alpha_to[i] = alpha_to[m] ^ ((alpha_to[i - 1] ^ mask) << 1);
else
alpha_to[i] = alpha_to[i - 1] << 1;
index_of[alpha_to[i]] = i;
}
index_of[0] = -1;
int i, mask;
mask = 1;
alpha_to[m] = 0;
for (i = 0; i < m; i++) {
alpha_to[i] = mask;
index_of[alpha_to[i]] = i;
if (p[i] != 0)
alpha_to[m] ^= mask;
mask <<= 1;
}
index_of[alpha_to[m]] = m;
mask >>= 1;
for (i = m + 1; i < n; i++) {
if (alpha_to[i - 1] >= mask)
alpha_to[i] = alpha_to[m] ^ ((alpha_to[i - 1] ^ mask) << 1);
else
alpha_to[i] = alpha_to[i - 1] << 1;
index_of[alpha_to[i]] = i;
}
index_of[0] = -1;
}
void BCHCode::gen_poly() {
/*
* Compute generator polynomial of BCH code of length = 31, redundancy = 10
* (OK, this is not very efficient, but we only do it once, right? :)
*/
/*
* Compute generator polynomial of BCH code of length = 31, redundancy = 10
* (OK, this is not very efficient, but we only do it once, right? :)
*/
int ii, jj, ll, kaux;
int test, aux, nocycles, root, noterms, rdncy;
int cycle[15][6], size[15], min[11], zeros[11];
// Generate cycle sets modulo 31
cycle[0][0] = 0; size[0] = 1;
cycle[1][0] = 1; size[1] = 1;
jj = 1; // cycle set index
do
{
// Generate the jj-th cycle set
ii = 0;
do
{
ii++;
cycle[jj][ii] = (cycle[jj][ii - 1] * 2) % n;
size[jj]++;
aux = (cycle[jj][ii] * 2) % n;
int ii, jj, ll, kaux;
int test, aux, nocycles, root, noterms, rdncy;
int cycle[15][6], size[15], min[11], zeros[11];
} while (aux != cycle[jj][0]);
// Next cycle set representative
ll = 0;
do
{
ll++;
test = 0;
for (ii = 1; ((ii <= jj) && (!test)); ii++)
// Examine previous cycle sets
for (kaux = 0; ((kaux < size[ii]) && (!test)); kaux++)
if (ll == cycle[ii][kaux])
test = 1;
}
while ((test) && (ll < (n - 1)));
if (!(test))
{
jj++; // next cycle set index
cycle[jj][0] = ll;
size[jj] = 1;
}
// Generate cycle sets modulo 31
cycle[0][0] = 0;
size[0] = 1;
cycle[1][0] = 1;
size[1] = 1;
jj = 1; // cycle set index
} while (ll < (n - 1));
nocycles = jj; // number of cycle sets modulo n
// Search for roots 1, 2, ..., d-1 in cycle sets
kaux = 0;
rdncy = 0;
for (ii = 1; ii <= nocycles; ii++)
{
min[kaux] = 0;
for (jj = 0; jj < size[ii]; jj++)
for (root = 1; root < d; root++)
if (root == cycle[ii][jj])
min[kaux] = ii;
if (min[kaux])
{
rdncy += size[min[kaux]];
kaux++;
}
}
do {
// Generate the jj-th cycle set
ii = 0;
do {
ii++;
cycle[jj][ii] = (cycle[jj][ii - 1] * 2) % n;
size[jj]++;
aux = (cycle[jj][ii] * 2) % n;
noterms = kaux;
kaux = 1;
for (ii = 0; ii < noterms; ii++)
for (jj = 0; jj < size[min[ii]]; jj++)
{
zeros[kaux] = cycle[min[ii]][jj];
kaux++;
}
// Compute generator polynomial
g[0] = alpha_to[zeros[1]];
g[1] = 1; // g(x) = (X + zeros[1]) initially
for (ii = 2; ii <= rdncy; ii++)
{
g[ii] = 1;
for (jj = ii - 1; jj > 0; jj--)
if (g[jj] != 0)
g[jj] = g[jj - 1] ^ alpha_to[(index_of[g[jj]] + zeros[ii]) % n];
else
g[jj] = g[jj - 1];
g[0] = alpha_to[(index_of[g[0]] + zeros[ii]) % n];
}
} while (aux != cycle[jj][0]);
// Next cycle set representative
ll = 0;
do {
ll++;
test = 0;
for (ii = 1; ((ii <= jj) && (!test)); ii++)
// Examine previous cycle sets
for (kaux = 0; ((kaux < size[ii]) && (!test)); kaux++)
if (ll == cycle[ii][kaux])
test = 1;
} while ((test) && (ll < (n - 1)));
if (!(test)) {
jj++; // next cycle set index
cycle[jj][0] = ll;
size[jj] = 1;
}
} while (ll < (n - 1));
nocycles = jj; // number of cycle sets modulo n
// Search for roots 1, 2, ..., d-1 in cycle sets
kaux = 0;
rdncy = 0;
for (ii = 1; ii <= nocycles; ii++) {
min[kaux] = 0;
for (jj = 0; jj < size[ii]; jj++)
for (root = 1; root < d; root++)
if (root == cycle[ii][jj])
min[kaux] = ii;
if (min[kaux]) {
rdncy += size[min[kaux]];
kaux++;
}
}
noterms = kaux;
kaux = 1;
for (ii = 0; ii < noterms; ii++)
for (jj = 0; jj < size[min[ii]]; jj++) {
zeros[kaux] = cycle[min[ii]][jj];
kaux++;
}
// Compute generator polynomial
g[0] = alpha_to[zeros[1]];
g[1] = 1; // g(x) = (X + zeros[1]) initially
for (ii = 2; ii <= rdncy; ii++) {
g[ii] = 1;
for (jj = ii - 1; jj > 0; jj--)
if (g[jj] != 0)
g[jj] = g[jj - 1] ^ alpha_to[(index_of[g[jj]] + zeros[ii]) % n];
else
g[jj] = g[jj - 1];
g[0] = alpha_to[(index_of[g[0]] + zeros[ii]) % n];
}
}
int * BCHCode::encode(int data[]) {
// Calculate redundant bits bb[]
int* BCHCode::encode(int data[]) {
// Calculate redundant bits bb[]
int h, i, j=0, start=0, end=(n-k); // 10
int Mr[31];
if (!valid) return nullptr;
for (i = 0; i < n; i++) {
Mr[i] = 0;
}
for (h = 0; h < k; ++h)
Mr[h] = data[h];
while (end < n)
{
for (i=end; i>start-2; --i)
{
if (Mr[start] != 0)
{
Mr[i]^=g[j];
++j;
}
else
{
++start;
j = 0;
end = start+(n-k);
break;
}
}
}
j = 0;
for (i = start; i<end; ++i) {
bb[j]=Mr[i];
++j;
}
return bb;
int h, i, j = 0, start = 0, end = (n - k); // 10
int Mr[31];
if (!valid) return nullptr;
for (i = 0; i < n; i++) {
Mr[i] = 0;
}
for (h = 0; h < k; ++h)
Mr[h] = data[h];
while (end < n) {
for (i = end; i > start - 2; --i) {
if (Mr[start] != 0) {
Mr[i] ^= g[j];
++j;
} else {
++start;
j = 0;
end = start + (n - k);
break;
}
}
}
j = 0;
for (i = start; i < end; ++i) {
bb[j] = Mr[i];
++j;
}
return bb;
};
int BCHCode::decode(int recd[]) {
// We do not need the Berlekamp algorithm to decode.
// We solve before hand two equations in two variables.
// We do not need the Berlekamp algorithm to decode.
// We solve before hand two equations in two variables.
int i, j, q;
int elp[3], s[5], s3;
int count = 0, syn_error = 0;
int loc[3], reg[3];
int aux;
int retval=0;
if (!valid) return 0;
for (i = 1; i <= 4; i++) {
s[i] = 0;
for (j = 0; j < n; j++) {
if (recd[j] != 0) {
s[i] ^= alpha_to[(i * j) % n];
}
}
if (s[i] != 0) {
syn_error = 1; // set flag if non-zero syndrome
}
/* NOTE: If only error detection is needed,
* then exit the program here...
*/
// Convert syndrome from polynomial form to index form
s[i] = index_of[s[i]];
};
if (syn_error) { // If there are errors, try to correct them
if (s[1] != -1) {
s3 = (s[1] * 3) % n;
if ( s[3] == s3 ) { // Was it a single error ?
//printf("One error at %d\n", s[1]);
recd[s[1]] ^= 1; // Yes: Correct it
} else {
/* Assume two errors occurred and solve
* for the coefficients of sigma(x), the
* error locator polynomial
*/
if (s[3] != -1) {
aux = alpha_to[s3] ^ alpha_to[s[3]];
} else {
aux = alpha_to[s3];
}
elp[0] = 0;
elp[1] = (s[2] - index_of[aux] + n) % n;
elp[2] = (s[1] - index_of[aux] + n) % n;
//printf("sigma(x) = ");
//for (i = 0; i <= 2; i++) {
// printf("%3d ", elp[i]);
//}
//printf("\n");
//printf("Roots: ");
// Find roots of the error location polynomial
for (i = 1; i <= 2; i++) {
reg[i] = elp[i];
}
count = 0;
for (i = 1; i <= n; i++) { // Chien search
q = 1;
for (j = 1; j <= 2; j++) {
if (reg[j] != -1) {
reg[j] = (reg[j] + j) % n;
q ^= alpha_to[reg[j]];
}
}
if (!q) { // store error location number indices
loc[count] = i % n;
count++;
}
}
if (count == 2) {
// no. roots = degree of elp hence 2 errors
for (i = 0; i < 2; i++)
recd[loc[i]] ^= 1;
} else { // Cannot solve: Error detection
retval=1;
}
}
} else if (s[2] != -1) { // Error detection
retval=1;
}
}
int i, j, q;
int elp[3], s[5], s3;
int count = 0, syn_error = 0;
int loc[3], reg[3];
int aux;
int retval = 0;
return retval;
if (!valid) return 0;
for (i = 1; i <= 4; i++) {
s[i] = 0;
for (j = 0; j < n; j++) {
if (recd[j] != 0) {
s[i] ^= alpha_to[(i * j) % n];
}
}
if (s[i] != 0) {
syn_error = 1; // set flag if non-zero syndrome
}
/* NOTE: If only error detection is needed,
* then exit the program here...
*/
// Convert syndrome from polynomial form to index form
s[i] = index_of[s[i]];
};
if (syn_error) { // If there are errors, try to correct them
if (s[1] != -1) {
s3 = (s[1] * 3) % n;
if (s[3] == s3) { // Was it a single error ?
// printf("One error at %d\n", s[1]);
recd[s[1]] ^= 1; // Yes: Correct it
} else {
/* Assume two errors occurred and solve
* for the coefficients of sigma(x), the
* error locator polynomial
*/
if (s[3] != -1) {
aux = alpha_to[s3] ^ alpha_to[s[3]];
} else {
aux = alpha_to[s3];
}
elp[0] = 0;
elp[1] = (s[2] - index_of[aux] + n) % n;
elp[2] = (s[1] - index_of[aux] + n) % n;
// printf("sigma(x) = ");
// for (i = 0; i <= 2; i++) {
// printf("%3d ", elp[i]);
// }
// printf("\n");
// printf("Roots: ");
// Find roots of the error location polynomial
for (i = 1; i <= 2; i++) {
reg[i] = elp[i];
}
count = 0;
for (i = 1; i <= n; i++) { // Chien search
q = 1;
for (j = 1; j <= 2; j++) {
if (reg[j] != -1) {
reg[j] = (reg[j] + j) % n;
q ^= alpha_to[reg[j]];
}
}
if (!q) { // store error location number indices
loc[count] = i % n;
count++;
}
}
if (count == 2) {
// no. roots = degree of elp hence 2 errors
for (i = 0; i < 2; i++)
recd[loc[i]] ^= 1;
} else { // Cannot solve: Error detection
retval = 1;
}
}
} else if (s[2] != -1) { // Error detection
retval = 1;
}
}
return retval;
}
/*
@@ -321,44 +305,48 @@ int BCHCode::decode(int recd[]) {
* bb[] = coefficients of redundancy polynomial ( x**(10) i(x) ) modulo g(x)
*/
BCHCode::BCHCode(
std::vector<int> p_init, int m, int n, int k, int t
) : m { m },
n { n },
k { k },
t { t } {
size_t i;
d = 5;
alpha_to = (int *)chHeapAlloc(NULL, sizeof(int) * (n + 1));
index_of = (int *)chHeapAlloc(0, sizeof(int) * (n + 1));
p = (int *)chHeapAlloc(0, sizeof(int) * (m + 1));
g = (int *)chHeapAlloc(0, sizeof(int) * (n - k + 1));
bb = (int *)chHeapAlloc(0, sizeof(int) * (n - k + 1));
if (alpha_to == NULL ||
index_of == NULL ||
p == NULL ||
g == NULL ||
bb == NULL)
valid = false;
else
valid = true;
if (valid) {
for (i = 0; i < (size_t)(m + 1); i++) {
p[i] = p_init[i];
}
std::vector<int> p_init,
int m,
int n,
int k,
int t)
: m{m},
n{n},
k{k},
t{t} {
size_t i;
generate_gf(); /* generate the Galois Field GF(2**m) */
gen_poly(); /* Compute the generator polynomial of BCH code */
}
d = 5;
alpha_to = (int*)chHeapAlloc(NULL, sizeof(int) * (n + 1));
index_of = (int*)chHeapAlloc(0, sizeof(int) * (n + 1));
p = (int*)chHeapAlloc(0, sizeof(int) * (m + 1));
g = (int*)chHeapAlloc(0, sizeof(int) * (n - k + 1));
bb = (int*)chHeapAlloc(0, sizeof(int) * (n - k + 1));
if (alpha_to == NULL ||
index_of == NULL ||
p == NULL ||
g == NULL ||
bb == NULL)
valid = false;
else
valid = true;
if (valid) {
for (i = 0; i < (size_t)(m + 1); i++) {
p[i] = p_init[i];
}
generate_gf(); /* generate the Galois Field GF(2**m) */
gen_poly(); /* Compute the generator polynomial of BCH code */
}
}
BCHCode::~BCHCode() {
if (alpha_to != NULL) chHeapFree(alpha_to);
if (index_of != NULL) chHeapFree(index_of);
if (p != NULL) chHeapFree(p);
if (g != NULL) chHeapFree(g);
if (bb != NULL) chHeapFree(bb);
if (alpha_to != NULL) chHeapFree(alpha_to);
if (index_of != NULL) chHeapFree(index_of);
if (p != NULL) chHeapFree(p);
if (g != NULL) chHeapFree(g);
if (bb != NULL) chHeapFree(bb);
}

View File

@@ -3,7 +3,7 @@
* Copyright (C) 2016 Furrtek
*
* BCH Encoder/Decoder - Adapted from GNURadio
*
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
@@ -28,34 +28,34 @@
#include <vector>
class BCHCode {
public:
BCHCode(std::vector<int> p_init, int m, int n, int k, int t);
~BCHCode();
BCHCode(const BCHCode&) = delete;
BCHCode(BCHCode&&) = delete;
BCHCode& operator=(const BCHCode&) = delete;
BCHCode& operator=(BCHCode&&) = delete;
public:
BCHCode(std::vector<int> p_init, int m, int n, int k, int t);
~BCHCode();
int * encode(int data[]);
int decode(int recd[]);
private:
void gen_poly();
void generate_gf();
bool valid { false };
BCHCode(const BCHCode&) = delete;
BCHCode(BCHCode&&) = delete;
BCHCode& operator=(const BCHCode&) = delete;
BCHCode& operator=(BCHCode&&) = delete;
int d { };
int * p { }; // coefficients of primitive polynomial used to generate GF(2**5)
int m { }; // order of the field GF(2**5) = 5
int n { }; // 2**5 - 1 = 31
int k { }; // n - deg(g(x)) = 21 = dimension
int t { }; // 2 = error correcting capability
int * alpha_to { }; // log table of GF(2**5)
int * index_of { }; // antilog table of GF(2**5)
int * g { }; // coefficients of generator polynomial, g(x) [n - k + 1]=[11]
int * bb { }; // coefficients of redundancy polynomial ( x**(10) i(x) ) modulo g(x)
int* encode(int data[]);
int decode(int recd[]);
private:
void gen_poly();
void generate_gf();
bool valid{false};
int d{};
int* p{}; // coefficients of primitive polynomial used to generate GF(2**5)
int m{}; // order of the field GF(2**5) = 5
int n{}; // 2**5 - 1 = 31
int k{}; // n - deg(g(x)) = 21 = dimension
int t{}; // 2 = error correcting capability
int* alpha_to{}; // log table of GF(2**5)
int* index_of{}; // antilog table of GF(2**5)
int* g{}; // coefficients of generator polynomial, g(x) [n - k + 1]=[11]
int* bb{}; // coefficients of redundancy polynomial ( x**(10) i(x) ) modulo g(x)
};
#endif/*__BCHCODE_H__*/
#endif /*__BCHCODE_H__*/

View File

@@ -26,48 +26,46 @@
#include <cstddef>
class BitHistory {
public:
void add(const uint_fast8_t bit) {
history = (history << 1) | (bit & 1);
}
public:
void add(const uint_fast8_t bit) {
history = (history << 1) | (bit & 1);
}
uint64_t value() const {
return history;
}
uint64_t value() const {
return history;
}
private:
uint64_t history { 0 };
private:
uint64_t history{0};
};
class BitPattern {
public:
constexpr BitPattern(
) : code_ { 0 },
mask_ { 0 },
maximum_hanning_distance_ { 0 }
{
}
constexpr BitPattern(
const uint64_t code,
const size_t code_length,
const size_t maximum_hanning_distance = 0
) : code_ { code },
mask_ { (1ULL << code_length) - 1ULL },
maximum_hanning_distance_ { maximum_hanning_distance }
{
}
public:
constexpr BitPattern()
: code_{0},
mask_{0},
maximum_hanning_distance_{0} {
}
bool operator()(const BitHistory& history, const size_t) const {
const auto delta_bits = (history.value() ^ code_) & mask_;
const size_t count = __builtin_popcountll(delta_bits);
return (count <= maximum_hanning_distance_);
}
constexpr BitPattern(
const uint64_t code,
const size_t code_length,
const size_t maximum_hanning_distance = 0)
: code_{code},
mask_{(1ULL << code_length) - 1ULL},
maximum_hanning_distance_{maximum_hanning_distance} {
}
private:
uint64_t code_;
uint64_t mask_;
size_t maximum_hanning_distance_;
bool operator()(const BitHistory& history, const size_t) const {
const auto delta_bits = (history.value() ^ code_) & mask_;
const size_t count = __builtin_popcountll(delta_bits);
return (count <= maximum_hanning_distance_);
}
private:
uint64_t code_;
uint64_t mask_;
size_t maximum_hanning_distance_;
};
#endif/*__BIT_PATTERN_H__*/
#endif /*__BIT_PATTERN_H__*/

View File

@@ -22,32 +22,32 @@
#pragma pack(push, 1)
struct bmp_header_t {
uint16_t signature;
uint32_t size;
uint16_t reserved_1;
uint16_t reserved_2;
uint32_t image_data;
uint32_t BIH_size;
uint32_t width;
uint32_t height;
uint16_t planes;
uint16_t bpp;
uint32_t compression;
uint32_t data_size;
uint32_t h_res;
uint32_t v_res;
uint32_t colors_count;
uint32_t icolors_count;
uint16_t signature;
uint32_t size;
uint16_t reserved_1;
uint16_t reserved_2;
uint32_t image_data;
uint32_t BIH_size;
uint32_t width;
uint32_t height;
uint16_t planes;
uint16_t bpp;
uint32_t compression;
uint32_t data_size;
uint32_t h_res;
uint32_t v_res;
uint32_t colors_count;
uint32_t icolors_count;
};
#pragma pack(pop)
#pragma pack(push, 1)
struct bmp_palette_t {
struct color_t {
uint8_t B;
uint8_t G;
uint8_t R;
uint8_t A;
} color[16];
struct color_t {
uint8_t B;
uint8_t G;
uint8_t R;
uint8_t A;
} color[16];
};
#pragma pack(pop)

View File

@@ -25,12 +25,12 @@
#include "lpc43xx_m4.h"
Timestamp Timestamp::now() {
// Code stolen from LPC43xx rtc_lld.c
Timestamp timestamp;
// Code stolen from LPC43xx rtc_lld.c
Timestamp timestamp;
do {
timestamp.tv_time = LPC_RTC->CTIME0;
timestamp.tv_date = LPC_RTC->CTIME1;
} while( (timestamp.tv_time != LPC_RTC->CTIME0) || (timestamp.tv_date != LPC_RTC->CTIME1) );
timestamp.tv_time = LPC_RTC->CTIME0;
timestamp.tv_date = LPC_RTC->CTIME1;
} while ((timestamp.tv_time != LPC_RTC->CTIME0) || (timestamp.tv_date != LPC_RTC->CTIME1));
return timestamp;
}
#endif

View File

@@ -34,10 +34,10 @@
*/
#if defined(LPC43XX_M4)
struct Timestamp {
uint32_t tv_date { 0 };
uint32_t tv_time { 0 };
uint32_t tv_date{0};
uint32_t tv_time{0};
static Timestamp now();
static Timestamp now();
};
#endif
@@ -47,45 +47,42 @@ struct Timestamp {
using Timestamp = lpc43xx::rtc::RTC;
#endif
template<typename T>
template <typename T>
struct buffer_t {
T* const p;
const size_t count;
const uint32_t sampling_rate;
const Timestamp timestamp;
T* const p;
const size_t count;
const uint32_t sampling_rate;
const Timestamp timestamp;
constexpr buffer_t(
) : p { nullptr },
count { 0 },
sampling_rate { 0 },
timestamp { }
{
}
constexpr buffer_t()
: p{nullptr},
count{0},
sampling_rate{0},
timestamp{} {
}
constexpr buffer_t(
const buffer_t<T>& other
) : p { other.p },
count { other.count },
sampling_rate { other.sampling_rate },
timestamp { other.timestamp }
{
}
constexpr buffer_t(
const buffer_t<T>& other)
: p{other.p},
count{other.count},
sampling_rate{other.sampling_rate},
timestamp{other.timestamp} {
}
constexpr buffer_t(
T* const p,
const size_t count,
const uint32_t sampling_rate = 0,
const Timestamp timestamp = { }
) : p { p },
count { count },
sampling_rate { sampling_rate },
timestamp { timestamp }
{
}
constexpr buffer_t(
T* const p,
const size_t count,
const uint32_t sampling_rate = 0,
const Timestamp timestamp = {})
: p{p},
count{count},
sampling_rate{sampling_rate},
timestamp{timestamp} {
}
operator bool() const {
return (p != nullptr);
}
operator bool() const {
return (p != nullptr);
}
};
#endif/*__BUFFER_H__*/
#endif /*__BUFFER_H__*/

View File

@@ -21,54 +21,52 @@
#include "buffer_exchange.hpp"
BufferExchange* BufferExchange::obj { nullptr };
BufferExchange* BufferExchange::obj{nullptr};
BufferExchange::BufferExchange(
CaptureConfig* const config
) // : config_capture { config }
CaptureConfig* const config) // : config_capture { config }
{
obj = this;
// In capture mode, baseband wants empty buffers, app waits for full buffers
fifo_buffers_for_baseband = config->fifo_buffers_empty;
fifo_buffers_for_application = config->fifo_buffers_full;
obj = this;
// In capture mode, baseband wants empty buffers, app waits for full buffers
fifo_buffers_for_baseband = config->fifo_buffers_empty;
fifo_buffers_for_application = config->fifo_buffers_full;
}
BufferExchange::BufferExchange(
ReplayConfig* const config
) // : config_replay { config }
ReplayConfig* const config) // : config_replay { config }
{
obj = this;
// In replay mode, baseband wants full buffers, app waits for empty buffers
fifo_buffers_for_baseband = config->fifo_buffers_full;
fifo_buffers_for_application = config->fifo_buffers_empty;
obj = this;
// In replay mode, baseband wants full buffers, app waits for empty buffers
fifo_buffers_for_baseband = config->fifo_buffers_full;
fifo_buffers_for_application = config->fifo_buffers_empty;
}
BufferExchange::~BufferExchange() {
obj = nullptr;
fifo_buffers_for_baseband = nullptr;
fifo_buffers_for_application = nullptr;
obj = nullptr;
fifo_buffers_for_baseband = nullptr;
fifo_buffers_for_application = nullptr;
}
StreamBuffer* BufferExchange::get(FIFO<StreamBuffer*>* fifo) {
while(true) {
StreamBuffer* p { nullptr };
fifo->out(p);
if( p ) {
return p;
}
while (true) {
StreamBuffer* p{nullptr};
fifo->out(p);
// Put thread to sleep, woken up by M4 IRQ
chSysLock();
thread = chThdSelf();
chSchGoSleepS(THD_STATE_SUSPENDED);
chSysUnlock();
}
if (p) {
return p;
}
// Put thread to sleep, woken up by M4 IRQ
chSysLock();
thread = chThdSelf();
chSchGoSleepS(THD_STATE_SUSPENDED);
chSysUnlock();
}
}
StreamBuffer* BufferExchange::get_prefill(FIFO<StreamBuffer*>* fifo) {
StreamBuffer* p { nullptr };
fifo->out(p);
return p;
StreamBuffer* p{nullptr};
fifo->out(p);
return p;
}

View File

@@ -28,85 +28,85 @@
#include "io.hpp"
class BufferExchange {
public:
BufferExchange(CaptureConfig* const config);
BufferExchange(ReplayConfig* const config);
~BufferExchange();
public:
BufferExchange(CaptureConfig* const config);
BufferExchange(ReplayConfig* const config);
~BufferExchange();
BufferExchange(const BufferExchange&) = delete;
BufferExchange(BufferExchange&&) = delete;
BufferExchange& operator=(const BufferExchange&) = delete;
BufferExchange& operator=(BufferExchange&&) = delete;
BufferExchange(const BufferExchange&) = delete;
BufferExchange(BufferExchange&&) = delete;
BufferExchange& operator=(const BufferExchange&) = delete;
BufferExchange& operator=(BufferExchange&&) = delete;
#if defined(LPC43XX_M0)
bool empty() const {
return fifo_buffers_for_application->is_empty();
}
bool empty() const {
return fifo_buffers_for_application->is_empty();
}
StreamBuffer* get() {
return get(fifo_buffers_for_application);
}
StreamBuffer* get_prefill() {
return get_prefill(fifo_buffers_for_application);
}
StreamBuffer* get() {
return get(fifo_buffers_for_application);
}
bool put(StreamBuffer* const p) {
return fifo_buffers_for_baseband->in(p);
}
bool put_app(StreamBuffer* const p) {
return fifo_buffers_for_application->in(p);
}
StreamBuffer* get_prefill() {
return get_prefill(fifo_buffers_for_application);
}
bool put(StreamBuffer* const p) {
return fifo_buffers_for_baseband->in(p);
}
bool put_app(StreamBuffer* const p) {
return fifo_buffers_for_application->in(p);
}
#endif
#if defined(LPC43XX_M4)
bool empty() const {
return fifo_buffers_for_baseband->is_empty();
}
bool empty() const {
return fifo_buffers_for_baseband->is_empty();
}
StreamBuffer* get() {
return get(fifo_buffers_for_baseband);
}
StreamBuffer* get() {
return get(fifo_buffers_for_baseband);
}
bool put(StreamBuffer* const p) {
return fifo_buffers_for_application->in(p);
}
bool put(StreamBuffer* const p) {
return fifo_buffers_for_application->in(p);
}
#endif
static void handle_isr() {
if( obj ) {
obj->check_fifo_isr();
}
}
static void handle_isr() {
if (obj) {
obj->check_fifo_isr();
}
}
private:
//CaptureConfig* const config_capture;
//ReplayConfig* const config_replay;
FIFO<StreamBuffer*>* fifo_buffers_for_baseband { nullptr };
FIFO<StreamBuffer*>* fifo_buffers_for_application { nullptr };
Thread* thread { nullptr };
static BufferExchange* obj;
enum {
CAPTURE,
REPLAY
} direction { };
private:
// CaptureConfig* const config_capture;
// ReplayConfig* const config_replay;
FIFO<StreamBuffer*>* fifo_buffers_for_baseband{nullptr};
FIFO<StreamBuffer*>* fifo_buffers_for_application{nullptr};
Thread* thread{nullptr};
static BufferExchange* obj;
void check_fifo_isr() {
if (!empty())
wakeup_isr();
}
enum {
CAPTURE,
REPLAY
} direction{};
void wakeup_isr() {
auto thread_tmp = thread;
if( thread_tmp ) {
thread = nullptr;
chSchReadyI(thread_tmp);
}
}
void check_fifo_isr() {
if (!empty())
wakeup_isr();
}
StreamBuffer* get(FIFO<StreamBuffer*>* fifo);
StreamBuffer* get_prefill(FIFO<StreamBuffer*>* fifo);
void wakeup_isr() {
auto thread_tmp = thread;
if (thread_tmp) {
thread = nullptr;
chSchReadyI(thread_tmp);
}
}
StreamBuffer* get(FIFO<StreamBuffer*>* fifo);
StreamBuffer* get_prefill(FIFO<StreamBuffer*>* fifo);
};

View File

@@ -26,33 +26,33 @@
#include <ch.h>
void* operator new(size_t size) {
void *p = chHeapAlloc(0x0, size);
if (p == nullptr)
chDbgPanic("Out of Memory");
return p;
void* p = chHeapAlloc(0x0, size);
if (p == nullptr)
chDbgPanic("Out of Memory");
return p;
}
void* operator new[](size_t size) {
void *p = chHeapAlloc(0x0, size);
if (p == nullptr)
chDbgPanic("Out of Memory");
return p;
void* p = chHeapAlloc(0x0, size);
if (p == nullptr)
chDbgPanic("Out of Memory");
return p;
}
void operator delete(void* p) noexcept {
chHeapFree(p);
chHeapFree(p);
}
void operator delete[](void* p) noexcept {
chHeapFree(p);
chHeapFree(p);
}
void operator delete(void* ptr, std::size_t) noexcept {
::operator delete(ptr);
::operator delete(ptr);
}
void operator delete[](void* ptr, std::size_t) noexcept {
::operator delete(ptr);
::operator delete(ptr);
}
extern uint8_t __heap_base__[];
@@ -61,14 +61,14 @@ extern uint8_t __heap_end__[];
namespace chibios {
size_t heap_size() {
return __heap_end__ - __heap_base__;
return __heap_end__ - __heap_base__;
}
size_t heap_used() {
const auto core_free = chCoreStatus();
size_t heap_free = 0;
chHeapStatus(NULL, &heap_free);
return heap_size() - (core_free + heap_free);
const auto core_free = chCoreStatus();
size_t heap_free = 0;
chHeapStatus(NULL, &heap_free);
return heap_size() - (core_free + heap_free);
}
} /* namespace chibios */

View File

@@ -40,4 +40,4 @@ size_t heap_used();
} /* namespace chibios */
#endif/*__CHIBIOS_CPP_H__*/
#endif /*__CHIBIOS_CPP_H__*/

View File

@@ -26,109 +26,108 @@
#include <complex>
#include <cmath>
constexpr float pi { 3.141592653589793238462643383279502884f };
constexpr float pi{3.141592653589793238462643383279502884f};
namespace std {
template<> struct complex<int8_t> {
public:
typedef int8_t value_type;
typedef uint16_t rep_type;
template <>
struct complex<int8_t> {
public:
typedef int8_t value_type;
typedef uint16_t rep_type;
// constexpr complex(
// rep_type r
// ) : _rep { r }
// {
// }
// constexpr complex(
// rep_type r
// ) : _rep { r }
// {
// }
constexpr complex(
int8_t re = 0,
int8_t im = 0
) : _v { re, im }
{
}
constexpr complex(
int8_t re = 0,
int8_t im = 0)
: _v{re, im} {
}
// constexpr complex(
// const complex& o
// ) : _rep { o._rep }
// {
// }
// constexpr complex(
// const complex& o
// ) : _rep { o._rep }
// {
// }
constexpr int8_t real() const { return _v[0]; }
constexpr int8_t imag() const { return _v[1]; }
constexpr int8_t real() const { return _v[0]; }
constexpr int8_t imag() const { return _v[1]; }
void real(int8_t v) { _v[0] = v; }
void imag(int8_t v) { _v[1] = v; }
void real(int8_t v) { _v[0] = v; }
void imag(int8_t v) { _v[1] = v; }
constexpr uint16_t __rep() const {
return _rep;
}
constexpr uint16_t __rep() const {
return _rep;
}
private:
union {
value_type _v[2];
rep_type _rep;
};
private:
union {
value_type _v[2];
rep_type _rep;
};
};
template<> struct complex<int16_t> {
public:
typedef int16_t value_type;
typedef uint32_t rep_type;
template <>
struct complex<int16_t> {
public:
typedef int16_t value_type;
typedef uint32_t rep_type;
// constexpr complex(
// rep_type r
// ) : _rep { r }
// {
// }
// constexpr complex(
// rep_type r
// ) : _rep { r }
// {
// }
constexpr complex(
int16_t re = 0,
int16_t im = 0
) : _v { re, im }
{
}
constexpr complex(
int16_t re = 0,
int16_t im = 0)
: _v{re, im} {
}
// constexpr complex(
// const complex& o
// ) : _rep { o._rep }
// {
// }
// constexpr complex(
// const complex& o
// ) : _rep { o._rep }
// {
// }
constexpr int16_t real() const { return _v[0]; }
constexpr int16_t imag() const { return _v[1]; }
constexpr int16_t real() const { return _v[0]; }
constexpr int16_t imag() const { return _v[1]; }
void real(int16_t v) { _v[0] = v; }
void imag(int16_t v) { _v[1] = v; }
void real(int16_t v) { _v[0] = v; }
void imag(int16_t v) { _v[1] = v; }
template<class X>
complex<int16_t>& operator+=(const complex<X>& other) {
_v[0] += other.real();
_v[1] += other.imag();
return *this;
}
template <class X>
complex<int16_t>& operator+=(const complex<X>& other) {
_v[0] += other.real();
_v[1] += other.imag();
return *this;
}
constexpr uint32_t __rep() const {
return _rep;
}
constexpr uint32_t __rep() const {
return _rep;
}
constexpr operator std::complex<float>() const {
return {
static_cast<float>(_v[0]),
static_cast<float>(_v[1])
};
}
constexpr operator std::complex<float>() const {
return {
static_cast<float>(_v[0]),
static_cast<float>(_v[1])};
}
private:
union {
value_type _v[2];
rep_type _rep;
};
private:
union {
value_type _v[2];
rep_type _rep;
};
};
} /* namespace std */
using complex8_t = std::complex<int8_t>;
using complex8_t = std::complex<int8_t>;
using complex16_t = std::complex<int16_t>;
using complex32_t = std::complex<int32_t>;
@@ -136,4 +135,4 @@ static_assert(sizeof(complex8_t) == 2, "complex8_t size wrong");
static_assert(sizeof(complex16_t) == 4, "complex16_t size wrong");
static_assert(sizeof(complex32_t) == 8, "complex32_t size wrong");
#endif/*__COMPLEX_H__*/
#endif /*__COMPLEX_H__*/

View File

@@ -30,42 +30,42 @@ namespace cpld {
namespace max5 {
void CPLD::bypass() {
shift_ir(instruction_t::BYPASS);
jtag.runtest_tck(18003);
shift_ir(instruction_t::BYPASS);
jtag.runtest_tck(18003);
}
void CPLD::sample() {
shift_ir(instruction_t::SAMPLE);
jtag.runtest_tck(93);
for(size_t i=0; i<80; i++) {
jtag.shift_dr(3, 0b111);
}
shift_ir(instruction_t::SAMPLE);
jtag.runtest_tck(93);
for (size_t i = 0; i < 80; i++) {
jtag.shift_dr(3, 0b111);
}
}
void CPLD::sample(std::bitset<240>& value) {
shift_ir(instruction_t::SAMPLE);
jtag.runtest_tck(93);
shift_dr(value);
shift_ir(instruction_t::SAMPLE);
jtag.runtest_tck(93);
shift_dr(value);
}
void CPLD::extest(std::bitset<240>& value) {
shift_ir(instruction_t::EXTEST);
shift_dr(value);
shift_ir(instruction_t::EXTEST);
shift_dr(value);
}
void CPLD::clamp() {
shift_ir(instruction_t::CLAMP);
jtag.runtest_tck(93);
shift_ir(instruction_t::CLAMP);
jtag.runtest_tck(93);
}
void CPLD::enable() {
shift_ir(instruction_t::ISC_ENABLE);
jtag.runtest_tck(18003); // 1ms
shift_ir(instruction_t::ISC_ENABLE);
jtag.runtest_tck(18003); // 1ms
}
void CPLD::disable() {
shift_ir(instruction_t::ISC_DISABLE);
jtag.runtest_tck(18003); // 1ms
shift_ir(instruction_t::ISC_DISABLE);
jtag.runtest_tck(18003); // 1ms
}
/* Sector erase:
@@ -76,96 +76,94 @@ void CPLD::disable() {
* each sector of the user flash memory (UFM) block.
*/
void CPLD::bulk_erase() {
erase_sector(0x0011);
erase_sector(0x0001);
erase_sector(0x0000);
erase_sector(0x0011);
erase_sector(0x0001);
erase_sector(0x0000);
}
bool CPLD::program(
const std::array<uint16_t, 3328>& block_0,
const std::array<uint16_t, 512>& block_1
) {
bulk_erase();
const std::array<uint16_t, 3328>& block_0,
const std::array<uint16_t, 512>& block_1) {
bulk_erase();
/* Program:
* involves shifting in the address, data, and program instruction and
* generating the program pulse to program the flash cells. The program
* pulse is automatically generated internally by waiting in the run/test/
* idle state for the specified program pulse time of 75 μs. This process
* is repeated for each address in the CFM and UFM blocks.
*/
program_block(0x0000, block_0);
program_block(0x0001, block_1);
/* Program:
* involves shifting in the address, data, and program instruction and
* generating the program pulse to program the flash cells. The program
* pulse is automatically generated internally by waiting in the run/test/
* idle state for the specified program pulse time of 75 μs. This process
* is repeated for each address in the CFM and UFM blocks.
*/
program_block(0x0000, block_0);
program_block(0x0001, block_1);
const auto verify_ok = verify(block_0, block_1);
const auto verify_ok = verify(block_0, block_1);
if( verify_ok ) {
/* Do "something". Not sure what, but it happens after verify. */
/* Starts with a sequence the same as Program: Block 0. */
/* Perhaps it is a write to tell the CPLD that the bitstream
* verified OK, and it's OK to load and execute? And despite only
* one bit changing, a write must be a multiple of a particular
* length (64 bits)? */
sector_select(0x0000);
shift_ir(instruction_t::ISC_PROGRAM);
jtag.runtest_tck(93); // 5 us
if (verify_ok) {
/* Do "something". Not sure what, but it happens after verify. */
/* Starts with a sequence the same as Program: Block 0. */
/* Perhaps it is a write to tell the CPLD that the bitstream
* verified OK, and it's OK to load and execute? And despite only
* one bit changing, a write must be a multiple of a particular
* length (64 bits)? */
sector_select(0x0000);
shift_ir(instruction_t::ISC_PROGRAM);
jtag.runtest_tck(93); // 5 us
/* TODO: Use data from cpld_block_0, with appropriate bit(s) changed */
/* Perhaps this is the "ISP_DONE" bit? */
jtag.shift_dr(16, block_0[0] & 0xfbff);
jtag.runtest_tck(1800); // 100us
jtag.shift_dr(16, block_0[1]);
jtag.runtest_tck(1800); // 100us
jtag.shift_dr(16, block_0[2]);
jtag.runtest_tck(1800); // 100us
jtag.shift_dr(16, block_0[3]);
jtag.runtest_tck(1800); // 100us
}
/* TODO: Use data from cpld_block_0, with appropriate bit(s) changed */
/* Perhaps this is the "ISP_DONE" bit? */
jtag.shift_dr(16, block_0[0] & 0xfbff);
jtag.runtest_tck(1800); // 100us
jtag.shift_dr(16, block_0[1]);
jtag.runtest_tck(1800); // 100us
jtag.shift_dr(16, block_0[2]);
jtag.runtest_tck(1800); // 100us
jtag.shift_dr(16, block_0[3]);
jtag.runtest_tck(1800); // 100us
}
return verify_ok;
return verify_ok;
}
bool CPLD::verify(
const std::array<uint16_t, 3328>& block_0,
const std::array<uint16_t, 512>& block_1
) {
/* Verify */
const auto block_0_success = verify_block(0x0000, block_0);
const auto block_1_success = verify_block(0x0001, block_1);
return block_0_success && block_1_success;
const std::array<uint16_t, 3328>& block_0,
const std::array<uint16_t, 512>& block_1) {
/* Verify */
const auto block_0_success = verify_block(0x0000, block_0);
const auto block_1_success = verify_block(0x0001, block_1);
return block_0_success && block_1_success;
}
uint32_t CPLD::crc() {
crc_t crc { 0x04c11db7, 0xffffffff, 0xffffffff };
block_crc(0, 3328, crc);
block_crc(1, 512, crc);
return crc.checksum();
crc_t crc{0x04c11db7, 0xffffffff, 0xffffffff};
block_crc(0, 3328, crc);
block_crc(1, 512, crc);
return crc.checksum();
}
void CPLD::sector_select(const uint16_t id) {
shift_ir(instruction_t::ISC_ADDRESS_SHIFT);
jtag.runtest_tck(93); // 5us
jtag.shift_dr(13, id); // Sector ID
shift_ir(instruction_t::ISC_ADDRESS_SHIFT);
jtag.runtest_tck(93); // 5us
jtag.shift_dr(13, id); // Sector ID
}
bool CPLD::idcode_ok() {
shift_ir(instruction_t::IDCODE);
const auto idcode_read = jtag.shift_dr(idcode_length, 0);
return (idcode_read == idcode);
shift_ir(instruction_t::IDCODE);
const auto idcode_read = jtag.shift_dr(idcode_length, 0);
return (idcode_read == idcode);
}
std::array<uint16_t, 5> CPLD::read_silicon_id() {
sector_select(0x0089);
shift_ir(instruction_t::ISC_READ);
jtag.runtest_tck(93); // 5us
sector_select(0x0089);
shift_ir(instruction_t::ISC_READ);
jtag.runtest_tck(93); // 5us
std::array<uint16_t, 5> silicon_id;
silicon_id[0] = jtag.shift_dr(16, 0xffff);
silicon_id[1] = jtag.shift_dr(16, 0xffff);
silicon_id[2] = jtag.shift_dr(16, 0xffff);
silicon_id[3] = jtag.shift_dr(16, 0xffff);
silicon_id[4] = jtag.shift_dr(16, 0xffff);
return silicon_id;
std::array<uint16_t, 5> silicon_id;
silicon_id[0] = jtag.shift_dr(16, 0xffff);
silicon_id[1] = jtag.shift_dr(16, 0xffff);
silicon_id[2] = jtag.shift_dr(16, 0xffff);
silicon_id[3] = jtag.shift_dr(16, 0xffff);
silicon_id[4] = jtag.shift_dr(16, 0xffff);
return silicon_id;
}
/* Check ID:
@@ -174,100 +172,97 @@ std::array<uint16_t, 5> CPLD::read_silicon_id() {
* the overall programming time.
*/
bool CPLD::silicon_id_ok() {
const auto silicon_id = read_silicon_id();
const auto silicon_id = read_silicon_id();
return (
(silicon_id[0] == 0x8232) &&
(silicon_id[1] == 0x2aa2) &&
(silicon_id[2] == 0x4a82) &&
(silicon_id[3] == 0x8c0c) &&
(silicon_id[4] == 0x0000)
);
return (
(silicon_id[0] == 0x8232) &&
(silicon_id[1] == 0x2aa2) &&
(silicon_id[2] == 0x4a82) &&
(silicon_id[3] == 0x8c0c) &&
(silicon_id[4] == 0x0000));
}
uint32_t CPLD::usercode() {
shift_ir(instruction_t::USERCODE);
jtag.runtest_tck(93); // 5us
return jtag.shift_dr(32, 0xffffffff);
shift_ir(instruction_t::USERCODE);
jtag.runtest_tck(93); // 5us
return jtag.shift_dr(32, 0xffffffff);
}
void CPLD::erase_sector(const uint16_t id) {
sector_select(id);
shift_ir(instruction_t::ISC_ERASE);
jtag.runtest_tck(9000003); // 500ms
sector_select(id);
shift_ir(instruction_t::ISC_ERASE);
jtag.runtest_tck(9000003); // 500ms
}
void CPLD::program_block(
const uint16_t id,
const uint16_t* const data,
const size_t count
) {
sector_select(id);
shift_ir(instruction_t::ISC_PROGRAM);
jtag.runtest_tck(93); // 5us
const uint16_t id,
const uint16_t* const data,
const size_t count) {
sector_select(id);
shift_ir(instruction_t::ISC_PROGRAM);
jtag.runtest_tck(93); // 5us
for(size_t i=0; i<count; i++) {
jtag.shift_dr(16, data[i]);
jtag.runtest_tck(1800);
}
for (size_t i = 0; i < count; i++) {
jtag.shift_dr(16, data[i]);
jtag.runtest_tck(1800);
}
}
bool CPLD::verify_block(
const uint16_t id,
const uint16_t* const data,
const size_t count
) {
sector_select(id);
shift_ir(instruction_t::ISC_READ);
jtag.runtest_tck(93); // 5us
const uint16_t id,
const uint16_t* const data,
const size_t count) {
sector_select(id);
shift_ir(instruction_t::ISC_READ);
jtag.runtest_tck(93); // 5us
bool success = true;
for(size_t i=0; i<count; i++) {
const auto from_device = jtag.shift_dr(16, 0xffff);
if( from_device != data[i] ) {
if( (id == 0) && (i == 0) ) {
// Account for bit that indicates bitstream is valid.
if( (from_device & 0xfbff) != (data[i] & 0xfbff) ) {
success = false;
}
} else {
success = false;
}
}
}
return success;
bool success = true;
for (size_t i = 0; i < count; i++) {
const auto from_device = jtag.shift_dr(16, 0xffff);
if (from_device != data[i]) {
if ((id == 0) && (i == 0)) {
// Account for bit that indicates bitstream is valid.
if ((from_device & 0xfbff) != (data[i] & 0xfbff)) {
success = false;
}
} else {
success = false;
}
}
}
return success;
}
bool CPLD::is_blank_block(const uint16_t id, const size_t count) {
sector_select(id);
shift_ir(instruction_t::ISC_READ);
jtag.runtest_tck(93); // 5us
sector_select(id);
shift_ir(instruction_t::ISC_READ);
jtag.runtest_tck(93); // 5us
bool success = true;
for(size_t i=0; i<count; i++) {
const auto from_device = jtag.shift_dr(16, 0xffff);
if( from_device != 0xffff ) {
success = false;
}
}
return success;
bool success = true;
for (size_t i = 0; i < count; i++) {
const auto from_device = jtag.shift_dr(16, 0xffff);
if (from_device != 0xffff) {
success = false;
}
}
return success;
}
void CPLD::block_crc(const uint16_t id, const size_t count, crc_t& crc) {
sector_select(id);
shift_ir(instruction_t::ISC_READ);
jtag.runtest_tck(93); // 5us
sector_select(id);
shift_ir(instruction_t::ISC_READ);
jtag.runtest_tck(93); // 5us
for(size_t i=0; i<count; i++) {
const uint16_t from_device = jtag.shift_dr(16, 0xffff);
crc.process_bytes(&from_device, sizeof(from_device));
}
for (size_t i = 0; i < count; i++) {
const uint16_t from_device = jtag.shift_dr(16, 0xffff);
crc.process_bytes(&from_device, sizeof(from_device));
}
}
bool CPLD::is_blank() {
const auto block_0_blank = is_blank_block(0x0000, 3328);
const auto block_1_blank = is_blank_block(0x0001, 512);
return block_0_blank && block_1_blank;
const auto block_0_blank = is_blank_block(0x0000, 3328);
const auto block_1_blank = is_blank_block(0x0001, 512);
return block_0_blank && block_1_blank;
}
} /* namespace max5 */

View File

@@ -34,170 +34,163 @@ namespace cpld {
namespace max5 {
struct Config {
const std::array<uint16_t, 3328>& block_0;
const std::array<uint16_t, 512>& block_1;
const std::array<uint16_t, 3328>& block_0;
const std::array<uint16_t, 512>& block_1;
};
class CPLD {
public:
constexpr CPLD(
jtag::JTAG& jtag
) : jtag(jtag)
{
}
public:
constexpr CPLD(
jtag::JTAG& jtag)
: jtag(jtag) {
}
void bypass();
void sample();
void sample(std::bitset<240>& value);
void extest(std::bitset<240>& value);
void clamp();
void bypass();
void sample();
void sample(std::bitset<240>& value);
void extest(std::bitset<240>& value);
void clamp();
void reset() {
jtag.reset();
}
void reset() {
jtag.reset();
}
void run_test_idle() {
jtag.run_test_idle();
}
void run_test_idle() {
jtag.run_test_idle();
}
bool idcode_ok();
bool idcode_ok();
void enable();
void enable();
/* Check ID:
* The silicon ID is checked before any Program or Verify process. The
* time required to read this silicon ID is relatively small compared to
* the overall programming time.
*/
bool silicon_id_ok();
/* Check ID:
* The silicon ID is checked before any Program or Verify process. The
* time required to read this silicon ID is relatively small compared to
* the overall programming time.
*/
bool silicon_id_ok();
uint32_t usercode();
uint32_t usercode();
void disable();
void disable();
void bulk_erase();
void bulk_erase();
bool program(
const std::array<uint16_t, 3328>& block_0,
const std::array<uint16_t, 512>& block_1
);
bool program(
const std::array<uint16_t, 3328>& block_0,
const std::array<uint16_t, 512>& block_1);
bool verify(
const std::array<uint16_t, 3328>& block_0,
const std::array<uint16_t, 512>& block_1
);
bool verify(
const std::array<uint16_t, 3328>& block_0,
const std::array<uint16_t, 512>& block_1);
bool is_blank();
bool is_blank();
uint32_t crc();
uint32_t crc();
std::pair<bool, uint8_t> boundary_scan();
std::pair<bool, uint8_t> boundary_scan();
private:
using idcode_t = uint32_t;
static constexpr size_t idcode_length = 32;
static constexpr idcode_t idcode = 0b00000010000010100101000011011101;
static constexpr idcode_t idcode_mask = 0b11111111111111111111111111111111;
static constexpr size_t ir_length = 10;
private:
using idcode_t = uint32_t;
static constexpr size_t idcode_length = 32;
static constexpr idcode_t idcode = 0b00000010000010100101000011011101;
static constexpr idcode_t idcode_mask = 0b11111111111111111111111111111111;
using ir_t = uint16_t;
static constexpr size_t ir_length = 10;
enum class instruction_t : ir_t {
BYPASS = 0b1111111111, // 0x3ff
EXTEST = 0b0000001111, // 0x00f
SAMPLE = 0b0000000101, // 0x005
IDCODE = 0b0000000110, // 0x006
USERCODE = 0b0000000111, // 0x007
CLAMP = 0b0000001010, // 0x00a
HIGHZ = 0b0000001011, // 0x00b
ISC_ENABLE = 0b1011001100, // 0x2cc
ISC_DISABLE = 0b1000000001, // 0x201
ISC_PROGRAM = 0b1011110100, // 0x2f4
ISC_ERASE = 0b1011110010, // 0x2f2
ISC_ADDRESS_SHIFT = 0b1000000011, // 0x203
ISC_READ = 0b1000000101, // 0x205
ISC_NOOP = 0b1000010000, // 0x210
};
using ir_t = uint16_t;
void shift_ir(const instruction_t instruction) {
shift_ir(static_cast<ir_t>(instruction));
}
void shift_ir(const uint32_t value) {
jtag.shift_ir(ir_length, value);
}
enum class instruction_t : ir_t {
BYPASS = 0b1111111111, // 0x3ff
EXTEST = 0b0000001111, // 0x00f
SAMPLE = 0b0000000101, // 0x005
IDCODE = 0b0000000110, // 0x006
USERCODE = 0b0000000111, // 0x007
CLAMP = 0b0000001010, // 0x00a
HIGHZ = 0b0000001011, // 0x00b
ISC_ENABLE = 0b1011001100, // 0x2cc
ISC_DISABLE = 0b1000000001, // 0x201
ISC_PROGRAM = 0b1011110100, // 0x2f4
ISC_ERASE = 0b1011110010, // 0x2f2
ISC_ADDRESS_SHIFT = 0b1000000011, // 0x203
ISC_READ = 0b1000000101, // 0x205
ISC_NOOP = 0b1000010000, // 0x210
};
void shift_dr(std::bitset<240>& value) {
for(size_t i=0; i<value.size(); i++) {
value[i] = shift_dr(1, value[i]);
}
}
void shift_ir(const instruction_t instruction) {
shift_ir(static_cast<ir_t>(instruction));
}
uint32_t shift_dr(const size_t count, const uint32_t value) {
return jtag.shift_dr(count, value);
}
void shift_ir(const uint32_t value) {
jtag.shift_ir(ir_length, value);
}
jtag::JTAG& jtag;
void shift_dr(std::bitset<240>& value) {
for (size_t i = 0; i < value.size(); i++) {
value[i] = shift_dr(1, value[i]);
}
}
std::array<uint16_t, 5> read_silicon_id();
uint32_t shift_dr(const size_t count, const uint32_t value) {
return jtag.shift_dr(count, value);
}
void sector_select(const uint16_t id);
jtag::JTAG& jtag;
void erase_sector(const uint16_t id);
std::array<uint16_t, 5> read_silicon_id();
void program_block(
const uint16_t id,
const uint16_t* const data,
const size_t count
);
void sector_select(const uint16_t id);
template<size_t N>
void program_block(
const uint16_t id,
const std::array<uint16_t, N>& data
) {
program_block(id, data.data(), data.size());
}
void erase_sector(const uint16_t id);
bool verify_block(
const uint16_t id,
const uint16_t* const data,
const size_t count
);
void program_block(
const uint16_t id,
const uint16_t* const data,
const size_t count);
template<size_t N>
bool verify_block(
const uint16_t id,
const std::array<uint16_t, N>& data
) {
return verify_block(id, data.data(), data.size());
}
template <size_t N>
void program_block(
const uint16_t id,
const std::array<uint16_t, N>& data) {
program_block(id, data.data(), data.size());
}
bool is_blank_block(const uint16_t id, const size_t count);
bool verify_block(
const uint16_t id,
const uint16_t* const data,
const size_t count);
using crc_t = CRC<32, true, true>;
void block_crc(const uint16_t id, const size_t count, crc_t& crc);
template <size_t N>
bool verify_block(
const uint16_t id,
const std::array<uint16_t, N>& data) {
return verify_block(id, data.data(), data.size());
}
bool is_blank_block(const uint16_t id, const size_t count);
using crc_t = CRC<32, true, true>;
void block_crc(const uint16_t id, const size_t count, crc_t& crc);
};
/*
class ModeISP {
public:
ModeISP(
CPLD& cpld
) : cpld(cpld)
{
cpld.enter_isp();
}
ModeISP(
CPLD& cpld
) : cpld(cpld)
{
cpld.enter_isp();
}
~ModeISP() {
cpld.exit_isp();
}
~ModeISP() {
cpld.exit_isp();
}
private:
CPLD& cpld;
CPLD& cpld;
};
*/
} /* namespace max5 */
} /* namespace cpld */
#endif/*__CPLD_MAX5_H__*/
#endif /*__CPLD_MAX5_H__*/

View File

@@ -34,59 +34,57 @@ namespace portapack {
namespace cpld {
CpldUpdateStatus update_if_necessary(
const Config config
) {
jtag::GPIOTarget target {
portapack::gpio_cpld_tck,
portapack::gpio_cpld_tms,
portapack::gpio_cpld_tdi,
portapack::gpio_cpld_tdo
};
jtag::JTAG jtag { target };
CPLD cpld { jtag };
const Config config) {
jtag::GPIOTarget target{
portapack::gpio_cpld_tck,
portapack::gpio_cpld_tms,
portapack::gpio_cpld_tdi,
portapack::gpio_cpld_tdo};
jtag::JTAG jtag{target};
CPLD cpld{jtag};
/* Unknown state */
cpld.reset();
cpld.run_test_idle();
/* Unknown state */
cpld.reset();
cpld.run_test_idle();
/* Run-Test/Idle */
if( !cpld.idcode_ok() ) {
return CpldUpdateStatus::Idcode_check_failed;
}
/* Run-Test/Idle */
if (!cpld.idcode_ok()) {
return CpldUpdateStatus::Idcode_check_failed;
}
cpld.sample();
cpld.bypass();
cpld.enable();
cpld.sample();
cpld.bypass();
cpld.enable();
/* If silicon ID doesn't match, there's a serious problem. Leave CPLD
* in passive state.
*/
if( !cpld.silicon_id_ok() ) {
return CpldUpdateStatus::Silicon_id_check_failed;
}
/* If silicon ID doesn't match, there's a serious problem. Leave CPLD
* in passive state.
*/
if (!cpld.silicon_id_ok()) {
return CpldUpdateStatus::Silicon_id_check_failed;
}
/* Verify CPLD contents against current bitstream. */
auto ok = cpld.verify(config.block_0, config.block_1);
/* Verify CPLD contents against current bitstream. */
auto ok = cpld.verify(config.block_0, config.block_1);
/* CPLD verifies incorrectly. Erase and program with current bitstream. */
if( !ok ) {
ok = cpld.program(config.block_0, config.block_1);
}
/* CPLD verifies incorrectly. Erase and program with current bitstream. */
if (!ok) {
ok = cpld.program(config.block_0, config.block_1);
}
/* If programming OK, reset CPLD to user mode. Otherwise leave it in
* passive (ISP) state.
*/
if( ok ) {
cpld.disable();
cpld.bypass();
/* If programming OK, reset CPLD to user mode. Otherwise leave it in
* passive (ISP) state.
*/
if (ok) {
cpld.disable();
cpld.bypass();
/* Initiate SRAM reload from flash we just programmed. */
cpld.sample();
cpld.clamp();
cpld.disable();
}
/* Initiate SRAM reload from flash we just programmed. */
cpld.sample();
cpld.clamp();
cpld.disable();
}
return ok ? CpldUpdateStatus::Success : CpldUpdateStatus::Program_failed;
return ok ? CpldUpdateStatus::Success : CpldUpdateStatus::Program_failed;
}
} /* namespace cpld */
@@ -96,52 +94,52 @@ namespace hackrf {
namespace cpld {
static jtag::GPIOTarget jtag_target_hackrf() {
return {
hackrf::one::gpio_cpld_tck,
hackrf::one::gpio_cpld_tms,
hackrf::one::gpio_cpld_tdi,
hackrf::one::gpio_cpld_tdo,
};
return {
hackrf::one::gpio_cpld_tck,
hackrf::one::gpio_cpld_tms,
hackrf::one::gpio_cpld_tdi,
hackrf::one::gpio_cpld_tdo,
};
}
bool load_sram() {
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
hackrf::one::cpld::CPLD hackrf_cpld { jtag_target_hackrf_cpld };
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
hackrf::one::cpld::CPLD hackrf_cpld{jtag_target_hackrf_cpld};
hackrf_cpld.write_sram(hackrf::one::cpld::verify_blocks);
const auto ok = hackrf_cpld.verify_sram(hackrf::one::cpld::verify_blocks);
hackrf_cpld.write_sram(hackrf::one::cpld::verify_blocks);
const auto ok = hackrf_cpld.verify_sram(hackrf::one::cpld::verify_blocks);
return ok;
return ok;
}
void load_sram_no_verify() {
// CoolRunner II family has Hybrid memory CPLD arquitecture (SRAM+NVM)
// It seems that after using TX App somehow , I do not why , the CPLD_SRAM part needs to be re_loaded to solve #637 ghost beat
// CoolRunner II family has Hybrid memory CPLD arquitecture (SRAM+NVM)
// It seems that after using TX App somehow , I do not why , the CPLD_SRAM part needs to be re_loaded to solve #637 ghost beat
// load_sram() it is already called at each boot in portapack.cpp ,including verify CPLD part.
// Here we skipped CPLD verify part,just to be quicker (in case any CPLD problem it will be detected in the boot process).
// Here we skipped CPLD verify part,just to be quicker (in case any CPLD problem it will be detected in the boot process).
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
hackrf::one::cpld::CPLD hackrf_cpld { jtag_target_hackrf_cpld };
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
hackrf::one::cpld::CPLD hackrf_cpld{jtag_target_hackrf_cpld};
hackrf_cpld.write_sram(hackrf::one::cpld::verify_blocks);
hackrf_cpld.write_sram(hackrf::one::cpld::verify_blocks);
return;
return;
}
bool verify_eeprom() {
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
hackrf::one::cpld::CPLD hackrf_cpld { jtag_target_hackrf_cpld };
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
hackrf::one::cpld::CPLD hackrf_cpld{jtag_target_hackrf_cpld};
const auto ok = hackrf_cpld.verify_eeprom(hackrf::one::cpld::verify_blocks);
return ok;
const auto ok = hackrf_cpld.verify_eeprom(hackrf::one::cpld::verify_blocks);
return ok;
}
void init_from_eeprom() {
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
hackrf::one::cpld::CPLD hackrf_cpld { jtag_target_hackrf_cpld };
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
hackrf::one::cpld::CPLD hackrf_cpld{jtag_target_hackrf_cpld};
hackrf_cpld.init_from_eeprom();
hackrf_cpld.init_from_eeprom();
}
} /* namespace cpld */

View File

@@ -28,15 +28,14 @@ namespace portapack {
namespace cpld {
enum class CpldUpdateStatus {
Success = 0,
Idcode_check_failed = 1,
Silicon_id_check_failed = 2,
Program_failed = 3
Success = 0,
Idcode_check_failed = 1,
Silicon_id_check_failed = 2,
Program_failed = 3
};
CpldUpdateStatus update_if_necessary(
const Config config
);
const Config config);
} /* namespace cpld */
} /* namespace portapack */
@@ -45,11 +44,11 @@ namespace hackrf {
namespace cpld {
bool load_sram();
void load_sram_no_verify(); // added to solve issue #637 , "ghost" signal at RX , after using any TX App
void load_sram_no_verify(); // added to solve issue #637 , "ghost" signal at RX , after using any TX App
bool verify_eeprom();
void init_from_eeprom();
} /* namespace cpld */
} /* namespace hackrf */
#endif/*__CPLD_UPDATE_H__*/
#endif /*__CPLD_UPDATE_H__*/

View File

@@ -25,154 +25,154 @@ namespace cpld {
namespace xilinx {
void XC2C64A::write_sram(const verify_blocks_t& blocks) {
tap.set_repeat(0);
tap.set_end_ir(state_t::run_test_idle);
tap.set_end_dr(state_t::run_test_idle);
tap.set_repeat(0);
tap.set_end_ir(state_t::run_test_idle);
tap.set_end_dr(state_t::run_test_idle);
reset();
enable();
reset();
enable();
shift_ir(instruction_t::ISC_WRITE);
for(const auto& block : blocks) {
tap.state(state_t::shift_dr);
tap.shift({ block.data.data(), block_length }, false);
tap.shift({ &block.id, block_id_length }, true);
tap.state(state_t::run_test_idle);
}
shift_ir(instruction_t::ISC_WRITE);
for (const auto& block : blocks) {
tap.state(state_t::shift_dr);
tap.shift({block.data.data(), block_length}, false);
tap.shift({&block.id, block_id_length}, true);
tap.state(state_t::run_test_idle);
}
disable();
bypass();
disable();
bypass();
tap.state(state_t::test_logic_reset);
tap.state(state_t::test_logic_reset);
}
bool XC2C64A::verify_sram(const verify_blocks_t& blocks) {
tap.set_repeat(0);
tap.set_end_ir(state_t::run_test_idle);
tap.set_end_dr(state_t::run_test_idle);
tap.set_repeat(0);
tap.set_end_ir(state_t::run_test_idle);
tap.set_end_dr(state_t::run_test_idle);
reset();
enable();
reset();
enable();
shift_ir(instruction_t::ISC_SRAM_READ);
shift_ir(instruction_t::ISC_SRAM_READ);
// Prime the operation with a read of an empty row.
const jtag::tap::bits_t empty_row { block_length };
// Prime the operation with a read of an empty row.
const jtag::tap::bits_t empty_row{block_length};
tap.state(state_t::shift_dr);
tap.shift(empty_row, false);
auto error = false;
for(const auto& block : blocks) {
tap.shift({ &block.id, block_id_length }, true);
tap.state(state_t::run_test_idle);
tap.state(state_t::shift_dr);
error |= tap.shift(empty_row, { block.data.data(), block_length }, { block.mask.data(), block_length }, false);
}
// Redundant operation to finish the row.
tap.shift({ &blocks[0].id, block_id_length }, true);
tap.state(state_t::run_test_idle);
tap.set_end_dr(state_t::run_test_idle);
tap.state(state_t::shift_dr);
tap.shift(empty_row, false);
disable();
bypass();
auto error = false;
for (const auto& block : blocks) {
tap.shift({&block.id, block_id_length}, true);
tap.state(state_t::run_test_idle);
tap.state(state_t::test_logic_reset);
tap.state(state_t::shift_dr);
error |= tap.shift(empty_row, {block.data.data(), block_length}, {block.mask.data(), block_length}, false);
}
// Redundant operation to finish the row.
tap.shift({&blocks[0].id, block_id_length}, true);
tap.state(state_t::run_test_idle);
tap.set_end_dr(state_t::run_test_idle);
return !error;
disable();
bypass();
tap.state(state_t::test_logic_reset);
return !error;
}
bool XC2C64A::verify_eeprom(const verify_blocks_t& blocks) {
tap.set_repeat(0);
tap.set_end_ir(state_t::run_test_idle);
tap.set_end_dr(state_t::run_test_idle);
tap.set_repeat(0);
tap.set_end_ir(state_t::run_test_idle);
tap.set_end_dr(state_t::run_test_idle);
reset();
bypass();
enable();
reset();
bypass();
enable();
shift_ir(instruction_t::ISC_READ);
shift_ir(instruction_t::ISC_READ);
const jtag::tap::bits_t empty_row { block_length };
const jtag::tap::bits_t empty_row{block_length};
auto error = false;
for(const auto& block : blocks) {
tap.set_end_dr(state_t::pause_dr);
tap.shift_dr({ &block.id, block_id_length });
tap.set_end_ir(state_t::run_test_idle);
tap.wait(state_t::pause_dr, state_t::pause_dr, 20);
tap.set_end_ir(state_t::run_test_idle);
tap.wait(state_t::run_test_idle, state_t::run_test_idle, 100);
error |= tap.shift_dr(empty_row, { block.data.data(), block_length }, { block.mask.data(), block_length });
tap.wait(state_t::run_test_idle, state_t::run_test_idle, 100);
}
auto error = false;
for (const auto& block : blocks) {
tap.set_end_dr(state_t::pause_dr);
tap.shift_dr({&block.id, block_id_length});
tap.set_end_ir(state_t::run_test_idle);
tap.wait(state_t::pause_dr, state_t::pause_dr, 20);
tap.set_end_ir(state_t::run_test_idle);
tap.wait(state_t::run_test_idle, state_t::run_test_idle, 100);
error |= tap.shift_dr(empty_row, {block.data.data(), block_length}, {block.mask.data(), block_length});
tap.wait(state_t::run_test_idle, state_t::run_test_idle, 100);
}
disable();
bypass();
disable();
bypass();
tap.state(state_t::test_logic_reset);
tap.state(state_t::test_logic_reset);
return !error;
return !error;
}
void XC2C64A::init_from_eeprom() {
tap.set_repeat(0);
tap.set_end_ir(state_t::run_test_idle);
tap.set_end_dr(state_t::run_test_idle);
tap.set_repeat(0);
tap.set_end_ir(state_t::run_test_idle);
tap.set_end_dr(state_t::run_test_idle);
reset();
enable();
reset();
enable();
discharge();
init();
disable();
bypass();
discharge();
init();
tap.state(state_t::test_logic_reset);
disable();
bypass();
tap.state(state_t::test_logic_reset);
}
bool XC2C64A::shift_ir(const instruction_t instruction) {
const ir_t ir_buffer = toUType(instruction);
const jtag::tap::bits_t bits { &ir_buffer, ir_length };
return tap.shift_ir(bits);
const ir_t ir_buffer = toUType(instruction);
const jtag::tap::bits_t bits{&ir_buffer, ir_length};
return tap.shift_ir(bits);
}
void XC2C64A::reset() {
tap.state(state_t::test_logic_reset);
tap.state(state_t::run_test_idle);
tap.state(state_t::test_logic_reset);
tap.state(state_t::run_test_idle);
}
void XC2C64A::enable() {
shift_ir(instruction_t::ISC_ENABLE);
tap.wait(state_t::run_test_idle, state_t::run_test_idle, 800);
shift_ir(instruction_t::ISC_ENABLE);
tap.wait(state_t::run_test_idle, state_t::run_test_idle, 800);
}
void XC2C64A::enable_otf() {
shift_ir(instruction_t::ISC_ENABLE_OTF);
shift_ir(instruction_t::ISC_ENABLE_OTF);
}
void XC2C64A::discharge() {
shift_ir(instruction_t::ISC_INIT);
tap.wait(state_t::run_test_idle, state_t::run_test_idle, 20);
shift_ir(instruction_t::ISC_INIT);
tap.wait(state_t::run_test_idle, state_t::run_test_idle, 20);
}
void XC2C64A::init() {
tap.set_end_ir(state_t::update_ir);
shift_ir(instruction_t::ISC_INIT);
tap.set_end_ir(state_t::run_test_idle);
tap.state(state_t::capture_dr);
tap.wait(state_t::run_test_idle, state_t::run_test_idle, 800);
tap.set_end_ir(state_t::update_ir);
shift_ir(instruction_t::ISC_INIT);
tap.set_end_ir(state_t::run_test_idle);
tap.state(state_t::capture_dr);
tap.wait(state_t::run_test_idle, state_t::run_test_idle, 800);
}
void XC2C64A::disable() {
shift_ir(instruction_t::ISC_DISABLE);
tap.wait(state_t::run_test_idle, state_t::run_test_idle, 100);
shift_ir(instruction_t::ISC_DISABLE);
tap.wait(state_t::run_test_idle, state_t::run_test_idle, 100);
}
bool XC2C64A::bypass() {
return shift_ir(instruction_t::BYPASS);
return shift_ir(instruction_t::BYPASS);
}
} /* namespace xilinx */

View File

@@ -36,91 +36,90 @@ namespace xilinx {
using jtag::tap::state_t;
class XC2C64A {
public:
using block_id_t = uint8_t;
public:
using block_id_t = uint8_t;
static constexpr size_t block_length = 274;
static constexpr size_t blocks_count = 98;
static constexpr size_t block_length = 274;
static constexpr size_t blocks_count = 98;
static constexpr size_t block_bytes = (block_length + 7) >> 3;
static constexpr size_t block_bytes = (block_length + 7) >> 3;
struct verify_block_t {
block_id_t id;
std::array<uint8_t, block_bytes> data;
std::array<uint8_t, block_bytes> mask;
};
struct verify_block_t {
block_id_t id;
std::array<uint8_t, block_bytes> data;
std::array<uint8_t, block_bytes> mask;
};
struct program_block_t {
block_id_t id;
std::array<uint8_t, block_bytes> data;
};
struct program_block_t {
block_id_t id;
std::array<uint8_t, block_bytes> data;
};
using verify_blocks_t = std::array<verify_block_t, blocks_count>;
using verify_blocks_t = std::array<verify_block_t, blocks_count>;
constexpr XC2C64A(
jtag::Target& jtag_interface
) : tap { jtag_interface }
{
}
constexpr XC2C64A(
jtag::Target& jtag_interface)
: tap{jtag_interface} {
}
void write_sram(const verify_blocks_t& blocks);
bool verify_sram(const verify_blocks_t& blocks);
void write_sram(const verify_blocks_t& blocks);
bool verify_sram(const verify_blocks_t& blocks);
bool verify_eeprom(const verify_blocks_t& blocks);
void init_from_eeprom();
bool verify_eeprom(const verify_blocks_t& blocks);
void init_from_eeprom();
private:
static constexpr size_t idcode_length = 32;
using idcode_t = uint32_t;
private:
static constexpr size_t idcode_length = 32;
using idcode_t = uint32_t;
static constexpr size_t ir_length = 8;
static constexpr size_t block_id_length = 7;
static constexpr size_t ir_length = 8;
static constexpr size_t block_id_length = 7;
static constexpr idcode_t idcode = 0x06e58093;
static constexpr idcode_t idcode_mask = 0x0fff8fff;
static constexpr idcode_t idcode = 0x06e58093;
static constexpr idcode_t idcode_mask = 0x0fff8fff;
using ir_t = uint8_t;
using ir_t = uint8_t;
jtag::tap::TAPMachine tap;
jtag::tap::TAPMachine tap;
enum class instruction_t : ir_t {
INTEST = 0b00000010, // -> boundary-scan
BYPASS = 0b11111111, // -> bypass
SAMPLE = 0b00000011, // -> boundary-scan
EXTEST = 0b00000000, // -> boundary-scan
IDCODE = 0b00000001, // -> device ID
USERCODE = 0b11111101, // -> device ID
HIGHZ = 0b11111100, // -> bypass
ISC_ENABLE_CLAMP = 0b11101001, // -> ISC shift
ISC_ENABLE_OTF = 0b11100100, // -> ISC shift
ISC_ENABLE = 0b11101000, // -> ISC shift
ISC_SRAM_READ = 0b11100111, // -> ISC shift
ISC_WRITE = 0b11100110, // -> ISC shift, alias ISC_SRAM_WRITE
ISC_ERASE = 0b11101101, // -> ISC shift
ISC_PROGRAM = 0b11101010, // -> ISC shift
ISC_READ = 0b11101110, // -> ISC shift, alias ISC_VERIFY
ISC_INIT = 0b11110000, // -> ISC shift
ISC_DISABLE = 0b11000000, // -> ISC shift
TEST_ENABLE = 0b00010001, // alias Private1
BULKPROG = 0b00010010, // alias Private2
ERASE_ALL = 0b00010100, // alias Private4
MVERIFY = 0b00010011, // alias Private3
TEST_DISABLE = 0b00010101, // alias Private5
ISC_NOOP = 0b11100000, // -> bypass
};
enum class instruction_t : ir_t {
INTEST = 0b00000010, // -> boundary-scan
BYPASS = 0b11111111, // -> bypass
SAMPLE = 0b00000011, // -> boundary-scan
EXTEST = 0b00000000, // -> boundary-scan
IDCODE = 0b00000001, // -> device ID
USERCODE = 0b11111101, // -> device ID
HIGHZ = 0b11111100, // -> bypass
ISC_ENABLE_CLAMP = 0b11101001, // -> ISC shift
ISC_ENABLE_OTF = 0b11100100, // -> ISC shift
ISC_ENABLE = 0b11101000, // -> ISC shift
ISC_SRAM_READ = 0b11100111, // -> ISC shift
ISC_WRITE = 0b11100110, // -> ISC shift, alias ISC_SRAM_WRITE
ISC_ERASE = 0b11101101, // -> ISC shift
ISC_PROGRAM = 0b11101010, // -> ISC shift
ISC_READ = 0b11101110, // -> ISC shift, alias ISC_VERIFY
ISC_INIT = 0b11110000, // -> ISC shift
ISC_DISABLE = 0b11000000, // -> ISC shift
TEST_ENABLE = 0b00010001, // alias Private1
BULKPROG = 0b00010010, // alias Private2
ERASE_ALL = 0b00010100, // alias Private4
MVERIFY = 0b00010011, // alias Private3
TEST_DISABLE = 0b00010101, // alias Private5
ISC_NOOP = 0b11100000, // -> bypass
};
bool shift_ir(const instruction_t instruction);
bool shift_ir(const instruction_t instruction);
void reset();
void enable();
void enable_otf();
void discharge();
void init();
void disable();
bool bypass();
void reset();
void enable();
void enable_otf();
void discharge();
void init();
void disable();
bool bypass();
};
} /* namespace xilinx */
} /* namespace cpld */
#endif/*__CPLD_XILINX_H__*/
#endif /*__CPLD_XILINX_H__*/

View File

@@ -40,156 +40,154 @@
*
*/
template<size_t Width, bool RevIn = false, bool RevOut = false>
template <size_t Width, bool RevIn = false, bool RevOut = false>
class CRC {
public:
using value_type = uint32_t;
public:
using value_type = uint32_t;
constexpr CRC(
const value_type truncated_polynomial,
const value_type initial_remainder = 0,
const value_type final_xor_value = 0
) : truncated_polynomial { truncated_polynomial },
initial_remainder { initial_remainder },
final_xor_value { final_xor_value },
remainder { initial_remainder }
{
}
constexpr CRC(
const value_type truncated_polynomial,
const value_type initial_remainder = 0,
const value_type final_xor_value = 0)
: truncated_polynomial{truncated_polynomial},
initial_remainder{initial_remainder},
final_xor_value{final_xor_value},
remainder{initial_remainder} {
}
value_type get_initial_remainder() const {
return initial_remainder;
}
value_type get_initial_remainder() const {
return initial_remainder;
}
void reset(value_type new_initial_remainder) {
remainder = new_initial_remainder;
}
void reset(value_type new_initial_remainder) {
remainder = new_initial_remainder;
}
void reset() {
remainder = initial_remainder;
}
void reset() {
remainder = initial_remainder;
}
void process_bit(bool bit) {
remainder ^= (bit ? top_bit() : 0U);
const auto do_poly_div = static_cast<bool>(remainder & top_bit());
remainder <<= 1;
if( do_poly_div ) {
remainder ^= truncated_polynomial;
}
}
void process_bit(bool bit) {
remainder ^= (bit ? top_bit() : 0U);
const auto do_poly_div = static_cast<bool>(remainder & top_bit());
remainder <<= 1;
if (do_poly_div) {
remainder ^= truncated_polynomial;
}
}
void process_bits(value_type bits, size_t bit_count) {
if( RevIn ) {
process_bits_lsb_first(bits, bit_count);
} else {
process_bits_msb_first(bits, bit_count);
}
}
void process_bits(value_type bits, size_t bit_count) {
if (RevIn) {
process_bits_lsb_first(bits, bit_count);
} else {
process_bits_msb_first(bits, bit_count);
}
}
void process_byte(const uint8_t byte) {
process_bits(byte, 8);
}
void process_byte(const uint8_t byte) {
process_bits(byte, 8);
}
void process_bytes(const void* const data, const size_t length) {
const uint8_t* const p = reinterpret_cast<const uint8_t*>(data);
for(size_t i=0; i<length; i++) {
process_byte(p[i]);
}
}
void process_bytes(const void* const data, const size_t length) {
const uint8_t* const p = reinterpret_cast<const uint8_t*>(data);
for (size_t i = 0; i < length; i++) {
process_byte(p[i]);
}
}
template<size_t N>
void process_bytes(const std::array<uint8_t, N>& data) {
process_bytes(data.data(), data.size());
}
template <size_t N>
void process_bytes(const std::array<uint8_t, N>& data) {
process_bytes(data.data(), data.size());
}
value_type checksum() const {
return ((RevOut ? reflect(remainder) : remainder) ^ final_xor_value) & mask();
}
value_type checksum() const {
return ((RevOut ? reflect(remainder) : remainder) ^ final_xor_value) & mask();
}
private:
const value_type truncated_polynomial;
const value_type initial_remainder;
const value_type final_xor_value;
value_type remainder;
private:
const value_type truncated_polynomial;
const value_type initial_remainder;
const value_type final_xor_value;
value_type remainder;
static constexpr size_t width() {
return Width;
}
static constexpr size_t width() {
return Width;
}
static constexpr value_type top_bit() {
return 1U << (width() - 1);
}
static constexpr value_type top_bit() {
return 1U << (width() - 1);
}
static constexpr value_type mask() {
static constexpr value_type mask() {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
return (~(~(0UL) << width()));
return (~(~(0UL) << width()));
#pragma GCC diagnostic pop
}
}
static value_type reflect(value_type x) {
value_type reflection = 0;
for(size_t i=0; i<width(); ++i) {
reflection <<= 1;
reflection |= (x & 1);
x >>= 1;
}
return reflection;
}
static value_type reflect(value_type x) {
value_type reflection = 0;
for (size_t i = 0; i < width(); ++i) {
reflection <<= 1;
reflection |= (x & 1);
x >>= 1;
}
return reflection;
}
void process_bits_msb_first(value_type bits, size_t bit_count) {
constexpr auto digits = std::numeric_limits<value_type>::digits;
constexpr auto mask = static_cast<value_type>(1) << (digits - 1);
void process_bits_msb_first(value_type bits, size_t bit_count) {
constexpr auto digits = std::numeric_limits<value_type>::digits;
constexpr auto mask = static_cast<value_type>(1) << (digits - 1);
bits <<= (std::numeric_limits<value_type>::digits - bit_count);
for(size_t i=bit_count; i>0; --i, bits <<= 1) {
process_bit(static_cast<bool>(bits & mask));
}
}
bits <<= (std::numeric_limits<value_type>::digits - bit_count);
for (size_t i = bit_count; i > 0; --i, bits <<= 1) {
process_bit(static_cast<bool>(bits & mask));
}
}
void process_bits_lsb_first(value_type bits, size_t bit_count) {
for(size_t i=bit_count; i>0; --i, bits >>= 1) {
process_bit(static_cast<bool>(bits & 0x01));
}
}
void process_bits_lsb_first(value_type bits, size_t bit_count) {
for (size_t i = bit_count; i > 0; --i, bits >>= 1) {
process_bit(static_cast<bool>(bits & 0x01));
}
}
};
class Adler32 {
public:
void feed(const uint8_t v) {
feed_one(v);
}
public:
void feed(const uint8_t v) {
feed_one(v);
}
void feed(const void* const data, const size_t n) {
const uint8_t* const p = reinterpret_cast<const uint8_t*>(data);
for(size_t i=0; i<n; i++) {
feed_one(p[i]);
}
}
void feed(const void* const data, const size_t n) {
const uint8_t* const p = reinterpret_cast<const uint8_t*>(data);
for (size_t i = 0; i < n; i++) {
feed_one(p[i]);
}
}
template<typename T>
void feed(const T& a) {
feed(a.data(), sizeof(T));
}
template <typename T>
void feed(const T& a) {
feed(a.data(), sizeof(T));
}
std::array<uint8_t, 4> bytes() const {
return {
static_cast<uint8_t>((b >> 8) & 0xff),
static_cast<uint8_t>((b >> 0) & 0xff),
static_cast<uint8_t>((a >> 8) & 0xff),
static_cast<uint8_t>((a >> 0) & 0xff)
};
}
std::array<uint8_t, 4> bytes() const {
return {
static_cast<uint8_t>((b >> 8) & 0xff),
static_cast<uint8_t>((b >> 0) & 0xff),
static_cast<uint8_t>((a >> 8) & 0xff),
static_cast<uint8_t>((a >> 0) & 0xff)};
}
private:
static constexpr uint32_t mod = 65521;
private:
static constexpr uint32_t mod = 65521;
uint32_t a { 1 };
uint32_t b { 0 };
uint32_t a{1};
uint32_t b{0};
void feed_one(const uint8_t c) {
a = (a + c) % mod;
b = (b + a) % mod;
}
void feed_one(const uint8_t c) {
a = (a + c) % mod;
b = (b + a) % mod;
}
};
#endif/*__CRC_H__*/
#endif /*__CRC_H__*/

View File

@@ -36,107 +36,104 @@
#include "sine_table_int8.hpp"
namespace std {
/* https://github.com/AE9RB/fftbench/blob/master/cxlr.hpp
* Nice trick from AE9RB (David Turnbull) to get compiler to produce simpler
* fma (fused multiply-accumulate) instead of worrying about NaN handling
*/
inline complex<float>
operator*(const complex<float>& v1, const complex<float>& v2) {
return complex<float> {
v1.real() * v2.real() - v1.imag() * v2.imag(),
v1.real() * v2.imag() + v1.imag() * v2.real()
};
}
/* https://github.com/AE9RB/fftbench/blob/master/cxlr.hpp
* Nice trick from AE9RB (David Turnbull) to get compiler to produce simpler
* fma (fused multiply-accumulate) instead of worrying about NaN handling
*/
inline complex<float>
operator*(const complex<float>& v1, const complex<float>& v2) {
return complex<float>{
v1.real() * v2.real() - v1.imag() * v2.imag(),
v1.real() * v2.imag() + v1.imag() * v2.real()};
}
} /* namespace std */
template<typename T, size_t N>
template <typename T, size_t N>
void fft_swap(const buffer_c16_t src, std::array<T, N>& dst) {
static_assert(power_of_two(N), "only defined for N == power of two");
static_assert(power_of_two(N), "only defined for N == power of two");
for(size_t i=0; i<N; i++) {
const size_t i_rev = __RBIT(i) >> (32 - log_2(N));
const auto s = src.p[i];
dst[i_rev] = {
static_cast<typename T::value_type>(s.real()),
static_cast<typename T::value_type>(s.imag())
};
}
for (size_t i = 0; i < N; i++) {
const size_t i_rev = __RBIT(i) >> (32 - log_2(N));
const auto s = src.p[i];
dst[i_rev] = {
static_cast<typename T::value_type>(s.real()),
static_cast<typename T::value_type>(s.imag())};
}
}
template<typename T, size_t N>
template <typename T, size_t N>
void fft_swap(const std::array<complex16_t, N>& src, std::array<T, N>& dst) {
static_assert(power_of_two(N), "only defined for N == power of two");
static_assert(power_of_two(N), "only defined for N == power of two");
for(size_t i=0; i<N; i++) {
const size_t i_rev = __RBIT(i) >> (32 - log_2(N));
const auto s = src[i];
dst[i_rev] = {
static_cast<typename T::value_type>(s.real()),
static_cast<typename T::value_type>(s.imag())
};
}
for (size_t i = 0; i < N; i++) {
const size_t i_rev = __RBIT(i) >> (32 - log_2(N));
const auto s = src[i];
dst[i_rev] = {
static_cast<typename T::value_type>(s.real()),
static_cast<typename T::value_type>(s.imag())};
}
}
template<typename T, size_t N>
template <typename T, size_t N>
void fft_swap(const std::array<T, N>& src, std::array<T, N>& dst) {
static_assert(power_of_two(N), "only defined for N == power of two");
static_assert(power_of_two(N), "only defined for N == power of two");
for(size_t i=0; i<N; i++) {
const size_t i_rev = __RBIT(i) >> (32 - log_2(N));
dst[i_rev] = src[i];
}
for (size_t i = 0; i < N; i++) {
const size_t i_rev = __RBIT(i) >> (32 - log_2(N));
dst[i_rev] = src[i];
}
}
template<typename T, size_t N>
template <typename T, size_t N>
void fft_swap_in_place(std::array<T, N>& data) {
static_assert(power_of_two(N), "only defined for N == power of two");
static_assert(power_of_two(N), "only defined for N == power of two");
for(size_t i=0; i<N/2; i++) {
const size_t i_rev = __RBIT(i) >> (32 - log_2(N));
std::swap(data[i], data[i_rev]);
}
for (size_t i = 0; i < N / 2; i++) {
const size_t i_rev = __RBIT(i) >> (32 - log_2(N));
std::swap(data[i], data[i_rev]);
}
}
/* http://beige.ucs.indiana.edu/B673/node14.html */
/* http://www.drdobbs.com/cpp/a-simple-and-efficient-fft-implementatio/199500857?pgno=3 */
template<typename T, size_t N>
template <typename T, size_t N>
void fft_c_preswapped(std::array<T, N>& data, const size_t from, const size_t to) {
static_assert(power_of_two(N), "only defined for N == power of two");
constexpr auto K = log_2(N);
if ((to > K) || (from > K)) return;
static_assert(power_of_two(N), "only defined for N == power of two");
constexpr auto K = log_2(N);
if ((to > K) || (from > K)) return;
constexpr size_t K_max = 8;
static_assert(K <= K_max, "No FFT twiddle factors for K > 8");
static constexpr std::array<std::complex<float>, K_max> wp_table { {
{ -2.0f, 0.0f }, // 2
{ -1.0f, -1.0f }, // 4
{ -0.2928932188134524756f, -0.7071067811865475244f }, // 8
{ -0.076120467488713243872f, -0.38268343236508977173f }, // 16
{ -0.019214719596769550874f, -0.19509032201612826785f }, // 32
{ -0.0048152733278031137552f, -0.098017140329560601994f }, // 64
{ -0.0012045437948276072852f, -0.049067674327418014255f }, // 128
{ -0.00030118130379577988423f, -0.024541228522912288032f }, // 256
} };
constexpr size_t K_max = 8;
static_assert(K <= K_max, "No FFT twiddle factors for K > 8");
static constexpr std::array<std::complex<float>, K_max> wp_table{{
{-2.0f, 0.0f}, // 2
{-1.0f, -1.0f}, // 4
{-0.2928932188134524756f, -0.7071067811865475244f}, // 8
{-0.076120467488713243872f, -0.38268343236508977173f}, // 16
{-0.019214719596769550874f, -0.19509032201612826785f}, // 32
{-0.0048152733278031137552f, -0.098017140329560601994f}, // 64
{-0.0012045437948276072852f, -0.049067674327418014255f}, // 128
{-0.00030118130379577988423f, -0.024541228522912288032f}, // 256
}};
/* Provide data to this function, pre-swapped. */
for(size_t k = from; k < to; k++) {
const size_t mmax = 1 << k;
const auto wp = wp_table[k];
T w { 1.0f, 0.0f };
for(size_t m = 0; m < mmax; ++m) {
for(size_t i = m; i < N; i += mmax * 2) {
const size_t j = i + mmax;
const T temp = w * data[j];
data[j] = data[i] - temp;
data[i] += temp;
}
w += w * wp;
}
}
/* Provide data to this function, pre-swapped. */
for (size_t k = from; k < to; k++) {
const size_t mmax = 1 << k;
const auto wp = wp_table[k];
T w{1.0f, 0.0f};
for (size_t m = 0; m < mmax; ++m) {
for (size_t i = m; i < N; i += mmax * 2) {
const size_t j = i + mmax;
const T temp = w * data[j];
data[j] = data[i] - temp;
data[i] += temp;
}
w += w * wp;
}
}
}
/*
/*
ifft(v,N):
[0] If N==1 then return.
[1] For k = 0 to N/2-1, let ve[k] = v[2*k]
@@ -149,32 +146,32 @@ void fft_c_preswapped(std::array<T, N>& data, const size_t from, const size_t to
[8] Let v[m] = ve[m] + w*vo[m]
[9] Let v[m+N/2] = ve[m] - w*vo[m]
*/
template<typename T>
void ifft( T *v, int n, T *tmp )
{
if(n>1) {
int k,m;
T z, w, *vo, *ve;
ve = tmp; vo = tmp+n/2;
for(k=0; k<n/2; k++) {
ve[k] = v[2*k];
vo[k] = v[2*k+1];
template <typename T>
void ifft(T* v, int n, T* tmp) {
if (n > 1) {
int k, m;
T z, w, *vo, *ve;
ve = tmp;
vo = tmp + n / 2;
for (k = 0; k < n / 2; k++) {
ve[k] = v[2 * k];
vo[k] = v[2 * k + 1];
}
ifft( ve, n/2, v ); /* FFT on even-indexed elements of v[] */
ifft( vo, n/2, v ); /* FFT on odd-indexed elements of v[] */
for(m=0; m<n/2; m++) {
w.real(sine_table_i8[((int)(m/(double)n * 0x100 + 0x40)) & 0xFF]);
w.imag(sine_table_i8[((int)(m/(double)n * 0x100)) & 0xFF]);
ifft(ve, n / 2, v); /* FFT on even-indexed elements of v[] */
ifft(vo, n / 2, v); /* FFT on odd-indexed elements of v[] */
for (m = 0; m < n / 2; m++) {
w.real(sine_table_i8[((int)(m / (double)n * 0x100 + 0x40)) & 0xFF]);
w.imag(sine_table_i8[((int)(m / (double)n * 0x100)) & 0xFF]);
z.real((w.real()*vo[m].real() - w.imag()*vo[m].imag())/127); /* Re(w*vo[m]) */
z.imag((w.real()*vo[m].imag() + w.imag()*vo[m].real())/127); /* Im(w*vo[m]) */
v[ m ].real(ve[m].real() + z.real());
v[ m ].imag(ve[m].imag() + z.imag());
v[m+n/2].real(ve[m].real() - z.real());
v[m+n/2].imag(ve[m].imag() - z.imag());
z.real((w.real() * vo[m].real() - w.imag() * vo[m].imag()) / 127); /* Re(w*vo[m]) */
z.imag((w.real() * vo[m].imag() + w.imag() * vo[m].real()) / 127); /* Im(w*vo[m]) */
v[m].real(ve[m].real() + z.real());
v[m].imag(ve[m].imag() + z.imag());
v[m + n / 2].real(ve[m].real() - z.real());
v[m + n / 2].imag(ve[m].imag() - z.imag());
}
}
return;
}
#endif/*__DSP_FFT_H__*/
#endif /*__DSP_FFT_H__*/

File diff suppressed because it is too large Load Diff

View File

@@ -24,60 +24,59 @@
#include <hal.h>
void IIRBiquadFilter::configure(const iir_biquad_config_t& new_config) {
config = new_config;
config = new_config;
}
void IIRBiquadFilter::execute(const buffer_f32_t& buffer_in, const buffer_f32_t& buffer_out) {
const auto a_ = config.a;
const auto b_ = config.b;
auto x_ = x;
auto y_ = y;
const auto a_ = config.a;
const auto b_ = config.b;
// TODO: Assert that buffer_out.count == buffer_in.count.
for(size_t i=0; i<buffer_out.count; i++) {
x_[0] = x_[1];
x_[1] = x_[2];
x_[2] = buffer_in.p[i];
auto x_ = x;
auto y_ = y;
y_[0] = y_[1];
y_[1] = y_[2];
y_[2] = b_[0] * x_[2] + b_[1] * x_[1] + b_[2] * x_[0]
- a_[1] * y_[1] - a_[2] * y_[0];
// TODO: Assert that buffer_out.count == buffer_in.count.
for (size_t i = 0; i < buffer_out.count; i++) {
x_[0] = x_[1];
x_[1] = x_[2];
x_[2] = buffer_in.p[i];
buffer_out.p[i] = y_[2];
}
y_[0] = y_[1];
y_[1] = y_[2];
y_[2] = b_[0] * x_[2] + b_[1] * x_[1] + b_[2] * x_[0] - a_[1] * y_[1] - a_[2] * y_[0];
x = x_;
y = y_;
buffer_out.p[i] = y_[2];
}
x = x_;
y = y_;
}
void IIRBiquadFilter::execute_in_place(const buffer_f32_t& buffer) {
execute(buffer, buffer);
execute(buffer, buffer);
}
void IIRBiquadDF2Filter::configure(const iir_biquad_df2_config_t& config) {
b0 = config[0] / config[3];
b1 = config[1] / config[3];
b2 = config[2] / config[3];
a1 = config[4] / config[3];
a2 = config[5] / config[3];
b0 = config[0] / config[3];
b1 = config[1] / config[3];
b2 = config[2] / config[3];
a1 = config[4] / config[3];
a2 = config[5] / config[3];
}
// scipy.signal.sosfilt
// scipy.signal.sosfilt
//
// x_n = x[i, n] # make a temporary copy
// # Use direct II transposed structure:
// x[i, n] = b[s, 0] * x_n + zi[i, s, 0]
// zi[i, s, 0] = (b[s, 1] * x_n - a[s, 0] * x[i, n] + zi[i, s, 1])
// zi[i, s, 1] = (b[s, 2] * x_n - a[s, 1] * x[i, n])
// x_n = x[i, n] # make a temporary copy
// # Use direct II transposed structure:
// x[i, n] = b[s, 0] * x_n + zi[i, s, 0]
// zi[i, s, 0] = (b[s, 1] * x_n - a[s, 0] * x[i, n] + zi[i, s, 1])
// zi[i, s, 1] = (b[s, 2] * x_n - a[s, 1] * x[i, n])
float IIRBiquadDF2Filter::execute(float x) {
float y;
y = b0 * x + z0;
z0 = b1 * x - a1 * y + z1;
z1 = b2 * x - a2 * y;
float y;
return y;
y = b0 * x + z0;
z0 = b1 * x - a1 * y + z1;
z1 = b2 * x - a2 * y;
return y;
}

View File

@@ -27,64 +27,61 @@
#include "dsp_types.hpp"
struct iir_biquad_config_t {
std::array<float, 3> b;
std::array<float, 3> a;
std::array<float, 3> b;
std::array<float, 3> a;
};
// 0..2 - b, 3..5 - a
typedef std::array<float, 6> iir_biquad_df2_config_t;
constexpr iir_biquad_config_t iir_config_passthrough {
{ { 1.0f, 0.0f, 0.0f } },
{ { 0.0f, 0.0f, 0.0f } },
constexpr iir_biquad_config_t iir_config_passthrough{
{{1.0f, 0.0f, 0.0f}},
{{0.0f, 0.0f, 0.0f}},
};
constexpr iir_biquad_config_t iir_config_no_pass {
{ { 0.0f, 0.0f, 0.0f } },
{ { 0.0f, 0.0f, 0.0f } },
constexpr iir_biquad_config_t iir_config_no_pass{
{{0.0f, 0.0f, 0.0f}},
{{0.0f, 0.0f, 0.0f}},
};
class IIRBiquadFilter {
public:
// http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
constexpr IIRBiquadFilter(
) : IIRBiquadFilter(iir_config_no_pass)
{
}
public:
// http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
constexpr IIRBiquadFilter()
: IIRBiquadFilter(iir_config_no_pass) {
}
// Assume all coefficients are normalized so that a0=1.0
constexpr IIRBiquadFilter(
const iir_biquad_config_t& config
) : config(config)
{
}
// Assume all coefficients are normalized so that a0=1.0
constexpr IIRBiquadFilter(
const iir_biquad_config_t& config)
: config(config) {
}
void configure(const iir_biquad_config_t& new_config);
void configure(const iir_biquad_config_t& new_config);
void execute(const buffer_f32_t& buffer_in, const buffer_f32_t& buffer_out);
void execute_in_place(const buffer_f32_t& buffer);
void execute(const buffer_f32_t& buffer_in, const buffer_f32_t& buffer_out);
void execute_in_place(const buffer_f32_t& buffer);
private:
iir_biquad_config_t config;
std::array<float, 3> x { { 0.0f, 0.0f, 0.0f } };
std::array<float, 3> y { { 0.0f, 0.0f, 0.0f } };
private:
iir_biquad_config_t config;
std::array<float, 3> x{{0.0f, 0.0f, 0.0f}};
std::array<float, 3> y{{0.0f, 0.0f, 0.0f}};
};
class IIRBiquadDF2Filter {
public:
public:
void configure(const iir_biquad_df2_config_t& config);
float execute(float z);
void configure(const iir_biquad_df2_config_t& config);
float execute(float z);
private:
float b0 = 0;
float b1 = 0;
float b2 = 0;
float a1 = 0;
float a2 = 0;
private:
float b0 = 0;
float b1 = 0;
float b2 = 0;
float a1 = 0;
float a2 = 0;
float z0 = 0;
float z1 = 0;
float z0 = 0;
float z1 = 0;
};
#endif/*__DSP_IIR_H__*/
#endif /*__DSP_IIR_H__*/

View File

@@ -26,95 +26,82 @@
#include "dsp_iir.hpp"
// scipy.signal.butter(2, 30 / 24000.0, 'highpass', analog=False)
constexpr iir_biquad_config_t audio_48k_hpf_30hz_config {
{ 0.99722705f, -1.99445410f, 0.99722705f },
{ 1.00000000f, -1.99444641f, 0.99446179f }
};
constexpr iir_biquad_config_t audio_48k_hpf_30hz_config{
{0.99722705f, -1.99445410f, 0.99722705f},
{1.00000000f, -1.99444641f, 0.99446179f}};
// scipy.signal.butter(2, 300 / 24000.0, 'highpass', analog=False)
constexpr iir_biquad_config_t audio_48k_hpf_300hz_config {
{ 0.97261390f, -1.94522780f, 0.97261390f },
{ 1.00000000f, -1.94447766f, 0.94597794f }
};
constexpr iir_biquad_config_t audio_48k_hpf_300hz_config{
{0.97261390f, -1.94522780f, 0.97261390f},
{1.00000000f, -1.94447766f, 0.94597794f}};
// scipy.signal.butter(2, 300 / 12000.0, 'highpass', analog=False)
constexpr iir_biquad_config_t audio_24k_hpf_300hz_config {
{ 0.94597686f, -1.89195371f, 0.94597686f },
{ 1.00000000f, -1.88903308f, 0.89487434f }
constexpr iir_biquad_config_t audio_24k_hpf_300hz_config{
{0.94597686f, -1.89195371f, 0.94597686f},
{1.00000000f, -1.88903308f, 0.89487434f}
};
// scipy.signal.butter(2, 30 / 12000.0, 'highpass', analog=False)
constexpr iir_biquad_config_t audio_24k_hpf_30hz_config {
{ 0.99446179f, -1.98892358f, 0.99446179f },
{ 1.00000000f, -1.98889291f, 0.98895425f }
};
constexpr iir_biquad_config_t audio_24k_hpf_30hz_config{
{0.99446179f, -1.98892358f, 0.99446179f},
{1.00000000f, -1.98889291f, 0.98895425f}};
// scipy.signal.butter(2, 300 / 8000.0, 'highpass', analog=False)
constexpr iir_biquad_config_t audio_16k_hpf_300hz_config {
{ 0.92006616f, -1.84013232f, 0.92006616f },
{ 1.00000000f, -1.83373266f, 0.84653197f }
};
constexpr iir_biquad_config_t audio_16k_hpf_300hz_config{
{0.92006616f, -1.84013232f, 0.92006616f},
{1.00000000f, -1.83373266f, 0.84653197f}};
// scipy.signal.butter(2, 300 / 6000.0, 'highpass', analog=False)
constexpr iir_biquad_config_t audio_12k_hpf_300hz_config {
{ 0.89485861f, -1.78971721f, 0.89485861f },
{ 1.00000000f, -1.77863178f, 0.80080265f }
};
constexpr iir_biquad_config_t audio_12k_hpf_300hz_config{
{0.89485861f, -1.78971721f, 0.89485861f},
{1.00000000f, -1.77863178f, 0.80080265f}};
// scipy.signal.butter(2, 300 / 4000.0, 'highpass', analog=False)
constexpr iir_biquad_config_t audio_8k_hpf_300hz_config {
{ 0.84645925f, -1.69291851f, 0.84645925f },
{ 1.00000000f, -1.66920314f, 0.71663387f }
};
constexpr iir_biquad_config_t audio_8k_hpf_300hz_config{
{0.84645925f, -1.69291851f, 0.84645925f},
{1.00000000f, -1.66920314f, 0.71663387f}};
// scipy.signal.iirdesign(wp=8000 / 24000.0, ws= 4000 / 24000.0, gpass=1, gstop=18, ftype='ellip')
constexpr iir_biquad_config_t non_audio_hpf_config {
{ 0.51891061f, -0.95714180f, 0.51891061f },
{ 1.0f , -0.79878302f, 0.43960231f }
};
constexpr iir_biquad_config_t non_audio_hpf_config{
{0.51891061f, -0.95714180f, 0.51891061f},
{1.0f, -0.79878302f, 0.43960231f}};
// scipy.signal.butter(1, 300 / 24000.0, 'lowpass', analog=False)
// NOTE: Technically, order-1 filter, b[2] = a[2] = 0.
constexpr iir_biquad_config_t audio_48k_deemph_300_6_config {
{ 0.01925927f, 0.01925927f, 0.00000000f },
{ 1.00000000f, -0.96148145f, 0.00000000f }
};
constexpr iir_biquad_config_t audio_48k_deemph_300_6_config{
{0.01925927f, 0.01925927f, 0.00000000f},
{1.00000000f, -0.96148145f, 0.00000000f}};
// scipy.signal.butter(1, 300 / 12000.0, 'lowpass', analog=False)
// NOTE: Technically, order-1 filter, b[2] = a[2] = 0.
constexpr iir_biquad_config_t audio_24k_deemph_300_6_config {
{ 0.03780475f, 0.03780475f, 0.00000000f },
{ 1.00000000f, -0.92439049f, 0.00000000f }
};
constexpr iir_biquad_config_t audio_24k_deemph_300_6_config{
{0.03780475f, 0.03780475f, 0.00000000f},
{1.00000000f, -0.92439049f, 0.00000000f}};
// scipy.signal.butter(1, 300 / 8000.0, 'lowpass', analog=False)
// NOTE: Technically, order-1 filter, b[2] = a[2] = 0.
constexpr iir_biquad_config_t audio_16k_deemph_300_6_config {
{ 0.05568894f, 0.05568894f, 0.00000000f },
{ 1.00000000f, -0.88862213f, 0.00000000f }
};
constexpr iir_biquad_config_t audio_16k_deemph_300_6_config{
{0.05568894f, 0.05568894f, 0.00000000f},
{1.00000000f, -0.88862213f, 0.00000000f}};
// scipy.signal.butter(1, 300 / 6000.0, 'lowpass', analog=False)
// NOTE: Technically, order-1 filter, b[2] = a[2] = 0.
constexpr iir_biquad_config_t audio_12k_deemph_300_6_config {
{ 0.07295966f, 0.07295966f, 0.00000000f },
{ 1.00000000f, -0.85408069f, 0.00000000f }
};
constexpr iir_biquad_config_t audio_12k_deemph_300_6_config{
{0.07295966f, 0.07295966f, 0.00000000f},
{1.00000000f, -0.85408069f, 0.00000000f}};
// scipy.signal.butter(1, 300 / 4000.0, 'lowpass', analog=False)
// NOTE: Technically, order-1 filter, b[2] = a[2] = 0.
constexpr iir_biquad_config_t audio_8k_deemph_300_6_config {
{ 0.10583178f, 0.10583178f, 0.00000000f },
{ 1.00000000f, -0.78833643f, 0.00000000f }
};
constexpr iir_biquad_config_t audio_8k_deemph_300_6_config{
{0.10583178f, 0.10583178f, 0.00000000f},
{1.00000000f, -0.78833643f, 0.00000000f}};
// 75us RC time constant, used in broadcast FM in Americas, South Korea
// scipy.signal.butter(1, 2122 / 24000.0, 'lowpass', analog=False)
// NOTE: Technically, order-1 filter, b[2] = a[2] = 0.
constexpr iir_biquad_config_t audio_48k_deemph_2122_6_config {
{ 0.12264116f, 0.12264116f, 0.00000000f },
{ 1.00000000f, -0.75471767f, 0.00000000f }
};
constexpr iir_biquad_config_t audio_48k_deemph_2122_6_config{
{0.12264116f, 0.12264116f, 0.00000000f},
{1.00000000f, -0.75471767f, 0.00000000f}};
#endif/*__DSP_IIR_CONFIG_H__*/
#endif /*__DSP_IIR_CONFIG_H__*/

View File

@@ -29,23 +29,20 @@
template <size_t N>
class SOSFilter {
public:
public:
void configure(const iir_biquad_df2_config_t config[N]) {
for (size_t i = 0; i < N; i++)
filters[i].configure(config[i]);
}
float execute(float value) {
for (auto &filter : filters)
for (auto& filter : filters)
value = filter.execute(value);
return value;
}
private:
private:
IIRBiquadDF2Filter filters[N];
};
#endif/*__DSP_SOS_H__*/
#endif /*__DSP_SOS_H__*/

View File

@@ -27,11 +27,10 @@
// scipy.signal.iirfilter(ftype="ellip", N = 10, rp = 0.5, rs = 60.0, Wn = 0.5, btype = 'lowpass', output="sos")
constexpr iir_biquad_df2_config_t half_band_lpf_config[5] = {
{ 0.02339042f, 0.0411599f, 0.02339042f, 1.0f, -0.95317621f, 0.33446485f },
{ 1.0f, 0.82196114f, 1.0f, 1.0f, -0.50327735f, 0.63611027f },
{ 1.0f, 0.32515305f, 1.0f, 1.0f, -0.18144446f, 0.85269598f },
{ 1.0f, 0.14394122f, 1.0f, 1.0f, -0.04368236f, 0.94798064f },
{ 1.0f, 0.08720754, 1.0f, 1.0f, 0.00220944f, 0.98743139f }
};
{0.02339042f, 0.0411599f, 0.02339042f, 1.0f, -0.95317621f, 0.33446485f},
{1.0f, 0.82196114f, 1.0f, 1.0f, -0.50327735f, 0.63611027f},
{1.0f, 0.32515305f, 1.0f, 1.0f, -0.18144446f, 0.85269598f},
{1.0f, 0.14394122f, 1.0f, 1.0f, -0.04368236f, 0.94798064f},
{1.0f, 0.08720754, 1.0f, 1.0f, 0.00220944f, 0.98743139f}};
#endif/*__DSP_SOS_CONFIG_H__*/
#endif /*__DSP_SOS_CONFIG_H__*/

View File

@@ -33,4 +33,4 @@ using buffer_s16_t = buffer_t<int16_t>;
using buffer_c32_t = buffer_t<complex32_t>;
using buffer_f32_t = buffer_t<float>;
#endif/*__DSP_TYPES_H__*/
#endif /*__DSP_TYPES_H__*/

View File

@@ -29,7 +29,7 @@
#include "utility.hpp"
namespace cc1101 {
// Data rate (Bauds)
// Whitening: Everything except preamble and sync word, init value = 111111111
// Packet format: preamble, sync word, (opt) length, (opt) address, payload, (opt) CRC
@@ -43,70 +43,69 @@ namespace cc1101 {
// FEC: ?
class CC1101Emu {
public:
//CC1101Emu();
//~CC1101Emu();
enum packet_mode_t {
FIXED_LENGTH,
VARIABLE_LENGTH,
INFINITE_LENGTH
};
enum modulation_t {
TWO_FSK,
GFSK,
OOK,
FOUR_FSK,
MSK,
};
void set_sync_word(const uint16_t sync_word) {
sync_word_ = sync_word;
};
void set_address(const uint8_t address) {
address_ = address;
};
void set_packet_length(const uint8_t packet_length) {
packet_length_ = packet_length;
};
void set_data_config(const bool CRC, const bool manchester, const bool whitening) {
CRC_ = CRC;
manchester_ = manchester;
whitening_ = whitening;
};
void set_packet_mode(const packet_mode_t packet_mode) {
packet_mode_ = packet_mode;
};
void set_modulation(const modulation_t modulation) {
modulation_ = modulation;
}
void set_num_preamble(const uint8_t num_preamble) { // 2, 3, 4, 6, 8, 12, 16, or 24
num_preamble_ = num_preamble;
};
void set_deviation(const size_t deviation) {
deviation_ = deviation;
};
public:
// CC1101Emu();
//~CC1101Emu();
private:
uint16_t sync_word_ { 0xD391 };
uint8_t address_ { 0x00 };
uint8_t packet_length_ { 0 };
bool CRC_ { false };
bool manchester_ { false };
bool whitening_ { true };
packet_mode_t packet_mode_ { VARIABLE_LENGTH };
modulation_t modulation_ { TWO_FSK };
uint8_t num_preamble_ { 4 };
size_t deviation_ { 4000 };
uint16_t whitening_pn { 0x1FF };
void whitening_init();
uint8_t whiten_byte(uint8_t byte);
enum packet_mode_t {
FIXED_LENGTH,
VARIABLE_LENGTH,
INFINITE_LENGTH
};
enum modulation_t {
TWO_FSK,
GFSK,
OOK,
FOUR_FSK,
MSK,
};
void set_sync_word(const uint16_t sync_word) {
sync_word_ = sync_word;
};
void set_address(const uint8_t address) {
address_ = address;
};
void set_packet_length(const uint8_t packet_length) {
packet_length_ = packet_length;
};
void set_data_config(const bool CRC, const bool manchester, const bool whitening) {
CRC_ = CRC;
manchester_ = manchester;
whitening_ = whitening;
};
void set_packet_mode(const packet_mode_t packet_mode) {
packet_mode_ = packet_mode;
};
void set_modulation(const modulation_t modulation) {
modulation_ = modulation;
}
void set_num_preamble(const uint8_t num_preamble) { // 2, 3, 4, 6, 8, 12, 16, or 24
num_preamble_ = num_preamble;
};
void set_deviation(const size_t deviation) {
deviation_ = deviation;
};
private:
uint16_t sync_word_{0xD391};
uint8_t address_{0x00};
uint8_t packet_length_{0};
bool CRC_{false};
bool manchester_{false};
bool whitening_{true};
packet_mode_t packet_mode_{VARIABLE_LENGTH};
modulation_t modulation_{TWO_FSK};
uint8_t num_preamble_{4};
size_t deviation_{4000};
uint16_t whitening_pn{0x1FF};
void whitening_init();
uint8_t whiten_byte(uint8_t byte);
};
} /* namespace cc1101 */
#endif/*__EMU_CC1101_H__*/
#endif /*__EMU_CC1101_H__*/

View File

@@ -26,91 +26,94 @@
namespace ert {
size_t Packet::length() const {
return decoder_.symbols_count();
return decoder_.symbols_count();
}
bool Packet::is_valid() const {
return true;
return true;
}
Timestamp Packet::received_at() const {
return packet_.timestamp();
return packet_.timestamp();
}
Packet::Type Packet::type() const {
return type_;
return type_;
}
ID Packet::id() const {
if( type() == Type::SCM ) {
const auto msb = reader_.read(0, 2);
const auto lsb = reader_.read(35, 24);
return (msb << 24) | lsb;
}
if( type() == Type::SCMPLUS ) {
return reader_.read(2 * 8, 32);
}
if( type() == Type::IDM ) {
return reader_.read(5 * 8, 32);
}
return invalid_id;
if (type() == Type::SCM) {
const auto msb = reader_.read(0, 2);
const auto lsb = reader_.read(35, 24);
return (msb << 24) | lsb;
}
if (type() == Type::SCMPLUS) {
return reader_.read(2 * 8, 32);
}
if (type() == Type::IDM) {
return reader_.read(5 * 8, 32);
}
return invalid_id;
}
Consumption Packet::consumption() const {
if( type() == Type::SCM ) {
return reader_.read(11, 24);
}
if( type() == Type::SCMPLUS ) {
return reader_.read(6 * 8, 32);
}
if( type() == Type::IDM ) {
return reader_.read(25 * 8, 32);
}
return invalid_consumption;
if (type() == Type::SCM) {
return reader_.read(11, 24);
}
if (type() == Type::SCMPLUS) {
return reader_.read(6 * 8, 32);
}
if (type() == Type::IDM) {
return reader_.read(25 * 8, 32);
}
return invalid_consumption;
}
CommodityType Packet::commodity_type() const {
if( type() == Type::SCM ) {
return reader_.read(5, 4);
}
if( type() == Type::SCMPLUS ) {
return reader_.read(1 * 8 + 4, 4);
}
if( type() == Type::IDM ) {
return reader_.read(4 * 8 + 4, 4);
}
return invalid_commodity_type;
if (type() == Type::SCM) {
return reader_.read(5, 4);
}
if (type() == Type::SCMPLUS) {
return reader_.read(1 * 8 + 4, 4);
}
if (type() == Type::IDM) {
return reader_.read(4 * 8 + 4, 4);
}
return invalid_commodity_type;
}
FormattedSymbols Packet::symbols_formatted() const {
return format_symbols(decoder_);
return format_symbols(decoder_);
}
bool Packet::crc_ok() const {
switch(type()) {
case Type::SCM: return crc_ok_scm();
case Type::SCMPLUS:
case Type::IDM: return crc_ok_ccitt();
default: return false;
}
switch (type()) {
case Type::SCM:
return crc_ok_scm();
case Type::SCMPLUS:
case Type::IDM:
return crc_ok_ccitt();
default:
return false;
}
}
bool Packet::crc_ok_scm() const {
CRC<16> ert_bch { 0x6f63 };
size_t start_bit = 5;
ert_bch.process_byte(reader_.read(0, start_bit));
for(size_t i=start_bit; i<length(); i+=8) {
ert_bch.process_byte(reader_.read(i, 8));
}
return ert_bch.checksum() == 0x0000;
CRC<16> ert_bch{0x6f63};
size_t start_bit = 5;
ert_bch.process_byte(reader_.read(0, start_bit));
for (size_t i = start_bit; i < length(); i += 8) {
ert_bch.process_byte(reader_.read(i, 8));
}
return ert_bch.checksum() == 0x0000;
}
bool Packet::crc_ok_ccitt() const {
CRC<16> ert_crc_ccitt { 0x1021, 0xffff, 0x1d0f };
for(size_t i=0; i<length(); i+=8) {
ert_crc_ccitt.process_byte(reader_.read(i, 8));
}
return ert_crc_ccitt.checksum() == 0x0000;
CRC<16> ert_crc_ccitt{0x1021, 0xffff, 0x1d0f};
for (size_t i = 0; i < length(); i += 8) {
ert_crc_ccitt.process_byte(reader_.read(i, 8));
}
return ert_crc_ccitt.checksum() == 0x0000;
}
} /* namespace ert */

View File

@@ -40,51 +40,50 @@ constexpr CommodityType invalid_commodity_type = -1;
constexpr Consumption invalid_consumption = 0;
class Packet {
public:
enum class Type : uint32_t {
Unknown = 0,
IDM = 1,
SCM = 2,
SCMPLUS = 3,
};
public:
enum class Type : uint32_t {
Unknown = 0,
IDM = 1,
SCM = 2,
SCMPLUS = 3,
};
Packet(
const Type type,
const baseband::Packet& packet
) : packet_ { packet },
decoder_ { packet_ },
reader_ { decoder_ },
type_ { type }
{
}
Packet(
const Type type,
const baseband::Packet& packet)
: packet_{packet},
decoder_{packet_},
reader_{decoder_},
type_{type} {
}
size_t length() const;
bool is_valid() const;
size_t length() const;
Timestamp received_at() const;
bool is_valid() const;
Type type() const;
ID id() const;
CommodityType commodity_type() const;
Consumption consumption() const;
Timestamp received_at() const;
FormattedSymbols symbols_formatted() const;
Type type() const;
ID id() const;
CommodityType commodity_type() const;
Consumption consumption() const;
bool crc_ok() const;
FormattedSymbols symbols_formatted() const;
private:
using Reader = FieldReader<ManchesterDecoder, BitRemapNone>;
bool crc_ok() const;
const baseband::Packet packet_;
const ManchesterDecoder decoder_;
const Reader reader_;
const Type type_;
private:
using Reader = FieldReader<ManchesterDecoder, BitRemapNone>;
bool crc_ok_ccitt() const;
bool crc_ok_scm() const;
const baseband::Packet packet_;
const ManchesterDecoder decoder_;
const Reader reader_;
const Type type_;
bool crc_ok_ccitt() const;
bool crc_ok_scm() const;
};
} /* namespace ert */
#endif/*__ERT_PACKET_H__*/
#endif /*__ERT_PACKET_H__*/

View File

@@ -24,4 +24,4 @@
#include "ch.h"
#endif/*__EVENT_H__*/
#endif /*__EVENT_H__*/

View File

@@ -5,20 +5,19 @@
/ FatFs - FAT file system module configuration file
/---------------------------------------------------------------------------*/
#define _FFCONF 68300 /* Revision ID */
#define _FFCONF 68300 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
/---------------------------------------------------------------------------*/
#define _FS_READONLY 0
#define _FS_READONLY 0
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ and optional writing functions as well. */
#define _FS_MINIMIZE 0
#define _FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions.
/
/ 0: All basic functions are enabled.
@@ -27,8 +26,7 @@
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/ 3: f_lseek() function is removed in addition to 2. */
#define _USE_STRFUNC 1
#define _USE_STRFUNC 1
/* This option switches string functions, f_gets(), f_putc(), f_puts() and
/ f_printf().
/
@@ -36,43 +34,35 @@
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define _USE_FIND 1
#define _USE_FIND 1
/* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
#define _USE_MKFS 0
#define _USE_MKFS 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define _USE_FASTSEEK 1
#define _USE_FASTSEEK 1
/* This option switches fast seek function. (0:Disable or 1:Enable) */
#define _USE_EXPAND 0
#define _USE_EXPAND 0
/* This option switches f_expand function. (0:Disable or 1:Enable) */
#define _USE_CHMOD 0
#define _USE_CHMOD 0
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */
#define _USE_LABEL 0
#define _USE_LABEL 0
/* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */
#define _USE_FORWARD 0
#define _USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
#define _CODE_PAGE 437
#define _CODE_PAGE 437
/* This option specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure.
/
@@ -100,9 +90,8 @@
/ 950 - Traditional Chinese (DBCS)
*/
#define _USE_LFN 2
#define _MAX_LFN 255
#define _USE_LFN 2
#define _MAX_LFN 255
/* The _USE_LFN switches the support of long file name (LFN).
/
/ 0: Disable support of LFN. _MAX_LFN has no effect.
@@ -118,14 +107,12 @@
/ memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree(), must be added to the project. */
#define _LFN_UNICODE 1
#define _LFN_UNICODE 1
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16)
/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
/ This option also affects behavior of string I/O functions. */
#define _STRF_ENCODE 3
#define _STRF_ENCODE 3
/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
/
@@ -136,8 +123,7 @@
/
/ This option has no effect when _LFN_UNICODE == 0. */
#define _FS_RPATH 0
#define _FS_RPATH 0
/* This option configures support of relative path.
/
/ 0: Disable relative path and remove related functions.
@@ -145,25 +131,22 @@
/ 2: f_getcwd() function is available in addition to 1.
*/
/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/
#define _VOLUMES 1
#define _VOLUMES 1
/* Number of volumes (logical drives) to be used. (1-10) */
#define _STR_VOLUME_ID 0
#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
#define _STR_VOLUME_ID 0
#define _VOLUME_STRS "RAM", "NAND", "CF", "SD", "SD2", "USB", "USB2", "USB3"
/* _STR_VOLUME_ID switches string support of volume ID.
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
/ the drive ID strings are: A-Z and 0-9. */
#define _MULTI_PARTITION 0
#define _MULTI_PARTITION 0
/* This option switches support of multi-partition on a physical drive.
/ By default (0), each logical drive number is bound to the same physical drive
/ number and only an FAT volume found on the physical drive will be mounted.
@@ -171,9 +154,8 @@
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ funciton will be available. */
#define _MIN_SS 512
#define _MAX_SS 512
#define _MIN_SS 512
#define _MAX_SS 512
/* These options configure the range of sector size to be supported. (512, 1024,
/ 2048 or 4096) Always set both 512 for most systems, generic memory card and
/ harddisk. But a larger value may be required for on-board flash memory and some
@@ -181,14 +163,12 @@
/ to variable sector size and GET_SECTOR_SIZE command needs to be implemented to
/ the disk_ioctl() function. */
#define _USE_TRIM 0
#define _USE_TRIM 0
/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable)
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
/ disk_ioctl() function. */
#define _FS_NOFSINFO 0
#define _FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
@@ -199,29 +179,25 @@
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/
/*---------------------------------------------------------------------------/
/ System Configurations
/---------------------------------------------------------------------------*/
#define _FS_TINY 0
#define _FS_TINY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of file object (FIL) is shrinked _MAX_SS bytes.
/ Instead of private sector buffer eliminated from the file object, common sector
/ buffer in the file system object (FATFS) is used for the file data transfer. */
#define _FS_EXFAT 0
#define _FS_EXFAT 0
/* This option switches support of exFAT file system. (0:Disable or 1:Enable)
/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1)
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
#define _FS_NORTC 0
#define _NORTC_MON 1
#define _NORTC_MDAY 1
#define _NORTC_YEAR 2016
#define _FS_NORTC 0
#define _NORTC_MON 1
#define _NORTC_MDAY 1
#define _NORTC_YEAR 2016
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable
/ the timestamp function. All objects modified by FatFs will have a fixed timestamp
@@ -231,8 +207,7 @@
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
/ These options have no effect at read-only configuration (_FS_READONLY = 1). */
#define _FS_LOCK 0
#define _FS_LOCK 0
/* The option _FS_LOCK switches file lock function to control duplicated file open
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY
/ is 1.
@@ -243,10 +218,9 @@
/ can be opened simultaneously under file lock control. Note that the file
/ lock control is independent of re-entrancy. */
#define _FS_REENTRANT 1
#define _FS_TIMEOUT 1000
#define _SYNC_t Semaphore *
#define _FS_REENTRANT 1
#define _FS_TIMEOUT 1000
#define _SYNC_t Semaphore*
/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
@@ -266,6 +240,4 @@
/* #include <windows.h> // O/S definitions */
/*--- End of configuration options ---*/

View File

@@ -26,40 +26,39 @@
#include <cstddef>
struct BitRemapNone {
constexpr size_t operator()(const size_t& bit_index) const {
return bit_index;
}
constexpr size_t operator()(const size_t& bit_index) const {
return bit_index;
}
};
struct BitRemapByteReverse {
constexpr size_t operator()(const size_t bit_index) const {
return bit_index ^ 7;
}
constexpr size_t operator()(const size_t bit_index) const {
return bit_index ^ 7;
}
};
template<typename T, typename BitRemap>
template <typename T, typename BitRemap>
class FieldReader {
public:
constexpr FieldReader(
const T& data
) : data { data }
{
}
public:
constexpr FieldReader(
const T& data)
: data{data} {
}
/* The "start_bit" winds up being the MSB of the returned field value. */
/* The BitRemap functor determines which bits are read from the source
* packet. */
int32_t read(const size_t start_bit, const size_t length) const { //Euquiq: was uint32_t, used for calculating lat / lon in radiosondes, can be negative too
uint32_t value = 0;
for(size_t i=start_bit; i<(start_bit + length); i++) {
value = (value << 1) | data[bit_remap(i)];
}
return value;
}
/* The "start_bit" winds up being the MSB of the returned field value. */
/* The BitRemap functor determines which bits are read from the source
* packet. */
int32_t read(const size_t start_bit, const size_t length) const { // Euquiq: was uint32_t, used for calculating lat / lon in radiosondes, can be negative too
uint32_t value = 0;
for (size_t i = start_bit; i < (start_bit + length); i++) {
value = (value << 1) | data[bit_remap(i)];
}
return value;
}
private:
const T& data;
const BitRemap bit_remap { };
private:
const T& data;
const BitRemap bit_remap{};
};
#endif/*__FIELD_READER_H__*/
#endif /*__FIELD_READER_H__*/

View File

@@ -31,209 +31,208 @@
/* FIFO implementation inspired by Linux kfifo. */
template<typename T>
template <typename T>
class FIFO {
public:
constexpr FIFO(
T* data,
size_t k
) : _data { data },
_size { 1U << k },
_in { 0 },
_out { 0 }
{
}
public:
constexpr FIFO(
T* data,
size_t k)
: _data{data},
_size{1U << k},
_in{0},
_out{0} {
}
void reset() {
_in = _out = 0;
}
void reset() {
_in = _out = 0;
}
void reset_in() {
_in = _out;
}
void reset_out() {
_out = _in;
}
void reset_in() {
_in = _out;
}
size_t len() const {
return _in - _out;
}
void reset_out() {
_out = _in;
}
size_t unused() const {
return size() - (_in - _out);
}
size_t len() const {
return _in - _out;
}
bool is_empty() const {
return _in == _out;
}
size_t unused() const {
return size() - (_in - _out);
}
bool is_full() const {
return unused() == 0;
}
bool is_empty() const {
return _in == _out;
}
bool in(const T& val) {
if( is_full() ) {
return false;
}
bool is_full() const {
return unused() == 0;
}
_data[_in & mask()] = val;
smp_wmb();
_in += 1;
return true;
}
bool in(const T& val) {
if (is_full()) {
return false;
}
size_t in(const T* const buf, size_t len) {
const size_t l = unused();
if( len > l ) {
len = l;
}
_data[_in & mask()] = val;
smp_wmb();
_in += 1;
copy_in(buf, len, _in);
_in += len;
return len;
}
return true;
}
size_t in_r(const void* const buf, const size_t len) {
if( (len + recsize()) > unused() ) {
return 0;
}
size_t in(const T* const buf, size_t len) {
const size_t l = unused();
if (len > l) {
len = l;
}
poke_n(len);
copy_in((const T*)buf, len, _in + recsize());
_in += len + recsize();
return len;
}
copy_in(buf, len, _in);
_in += len;
return len;
}
bool out(T& val) {
if( is_empty() ) {
return false;
}
size_t in_r(const void* const buf, const size_t len) {
if ((len + recsize()) > unused()) {
return 0;
}
val = _data[_out & mask()]; // Crashes
smp_wmb(); // Ok
_out += 1; // Crashes
poke_n(len);
copy_in((const T*)buf, len, _in + recsize());
_in += len + recsize();
return len;
}
return true;
}
bool out(T& val) {
if (is_empty()) {
return false;
}
size_t out(T* const buf, size_t len) {
len = out_peek(buf, len);
_out += len;
return len;
}
val = _data[_out & mask()]; // Crashes
smp_wmb(); // Ok
_out += 1; // Crashes
bool skip() {
if( is_empty() ) {
return false;
}
return true;
}
size_t len = peek_n();
_out += len + recsize();
return true;
}
size_t out(T* const buf, size_t len) {
len = out_peek(buf, len);
_out += len;
return len;
}
size_t peek_r(void* const buf, size_t len) {
if( is_empty() ) {
return 0;
}
bool skip() {
if (is_empty()) {
return false;
}
size_t n;
len = out_copy_r((T*)buf, len, &n);
return len;
}
size_t len = peek_n();
_out += len + recsize();
return true;
}
size_t out_r(void* const buf, size_t len) {
if( is_empty() ) {
return 0;
}
size_t peek_r(void* const buf, size_t len) {
if (is_empty()) {
return 0;
}
size_t n;
len = out_copy_r((T*)buf, len, &n);
_out += n + recsize();
return len;
}
size_t n;
len = out_copy_r((T*)buf, len, &n);
return len;
}
private:
size_t size() const {
return _size;
}
size_t out_r(void* const buf, size_t len) {
if (is_empty()) {
return 0;
}
static constexpr size_t esize() {
return sizeof(T);
}
size_t n;
len = out_copy_r((T*)buf, len, &n);
_out += n + recsize();
return len;
}
size_t mask() const {
return size() - 1;
}
private:
size_t size() const {
return _size;
}
static constexpr size_t recsize() {
return 2;
}
static constexpr size_t esize() {
return sizeof(T);
}
void smp_wmb() {
__DMB();
}
size_t mask() const {
return size() - 1;
}
size_t peek_n() {
size_t l = _data[_out & mask()];
if( recsize() > 1 ) {
l |= _data[(_out + 1) & mask()] << 8;
}
return l;
}
static constexpr size_t recsize() {
return 2;
}
void poke_n(const size_t n) {
_data[_in & mask()] = n & 0xff;
if( recsize() > 1 ) {
_data[(_in + 1) & mask()] = (n >> 8) & 0xff;
}
}
void smp_wmb() {
__DMB();
}
void copy_in(const T* const src, const size_t len, size_t off) {
off &= mask();
const size_t l = std::min(len, size() - off);
size_t peek_n() {
size_t l = _data[_out & mask()];
if (recsize() > 1) {
l |= _data[(_out + 1) & mask()] << 8;
}
return l;
}
memcpy(&_data[off], &src[0], l * esize());
memcpy(&_data[0], &src[l], (len - l) * esize());
smp_wmb();
}
void poke_n(const size_t n) {
_data[_in & mask()] = n & 0xff;
if (recsize() > 1) {
_data[(_in + 1) & mask()] = (n >> 8) & 0xff;
}
}
void copy_out(T* const dst, const size_t len, size_t off) {
off &= mask();
const size_t l = std::min(len, size() - off);
void copy_in(const T* const src, const size_t len, size_t off) {
off &= mask();
const size_t l = std::min(len, size() - off);
memcpy(&dst[0], &_data[off], l * esize());
memcpy(&dst[l], &_data[0], (len - l) * esize());
smp_wmb();
}
memcpy(&_data[off], &src[0], l * esize());
memcpy(&_data[0], &src[l], (len - l) * esize());
smp_wmb();
}
size_t out_copy_r(void *buf, size_t len, size_t* const n) {
*n = peek_n();
void copy_out(T* const dst, const size_t len, size_t off) {
off &= mask();
const size_t l = std::min(len, size() - off);
if( len > *n ) {
len = *n;
}
memcpy(&dst[0], &_data[off], l * esize());
memcpy(&dst[l], &_data[0], (len - l) * esize());
smp_wmb();
}
copy_out((T*)buf, len, _out + recsize());
return len;
}
size_t out_copy_r(void* buf, size_t len, size_t* const n) {
*n = peek_n();
size_t out_peek(T* const buf, size_t buf_len) {
const size_t l = len();
if( buf_len > l ) {
buf_len = l;
}
if (len > *n) {
len = *n;
}
copy_out(buf, buf_len, _out);
return buf_len;
}
copy_out((T*)buf, len, _out + recsize());
return len;
}
T* const _data;
const size_t _size;
volatile size_t _in;
volatile size_t _out;
size_t out_peek(T* const buf, size_t buf_len) {
const size_t l = len();
if (buf_len > l) {
buf_len = l;
}
copy_out(buf, buf_len, _out);
return buf_len;
}
T* const _data;
const size_t _size;
volatile size_t _in;
volatile size_t _out;
};
#endif/*__FIFO_H__*/
#endif /*__FIFO_H__*/

View File

@@ -29,18 +29,18 @@
* undefined reference to `__dso_handle'.
* Comes up when using random C++ features, e.g. lambdas or std::function?
*/
void *__dso_handle;
void* __dso_handle;
/* prevents the exception handling name demangling code getting pulled in */
namespace __gnu_cxx {
void __verbose_terminate_handler() {
}
void __verbose_terminate_handler() {
}
} // namespace __gnu_cxx
/* NOTE: Hack to address bloat when using C++ class virtual destructors.
*/
extern "C" __attribute__((weak)) void __cxa_pure_virtual(void) {
chSysHalt();
chSysHalt();
}
#endif
@@ -49,6 +49,8 @@ extern "C" __attribute__((weak)) void __cxa_pure_virtual(void) {
* _exit().
*/
extern "C" void abort() {
/* while() loop to avoid noreturn-is-returning warning. */
while(1) { chSysHalt(); }
/* while() loop to avoid noreturn-is-returning warning. */
while (1) {
chSysHalt();
}
}

View File

@@ -22,4 +22,4 @@
#ifndef __GCC_H__
#define __GCC_H__
#endif/*__GCC_H__*/
#endif /*__GCC_H__*/

View File

@@ -29,40 +29,38 @@ namespace gpdma {
namespace {
struct ChannelHandlers {
TCHandler tc;
ErrHandler err;
TCHandler tc;
ErrHandler err;
constexpr ChannelHandlers(
) : tc(nullptr),
err(nullptr)
{
}
constexpr ChannelHandlers()
: tc(nullptr),
err(nullptr) {
}
};
}
} // namespace
static std::array<ChannelHandlers, channels.size()> handlers_table { {} };
static std::array<ChannelHandlers, channels.size()> handlers_table{{}};
namespace channel {
void Channel::set_handlers(const TCHandler tc_handler, const ErrHandler err_handler) const {
handlers_table[number].tc = tc_handler;
handlers_table[number].err = err_handler;
handlers_table[number].tc = tc_handler;
handlers_table[number].err = err_handler;
}
void Channel::configure(
const LLI& first_lli,
const uint32_t config
) const {
disable();
clear_interrupts();
const LLI& first_lli,
const uint32_t config) const {
disable();
clear_interrupts();
LPC_GPDMA_Channel_Type* const channel = &LPC_GPDMA->CH[number];
channel->SRCADDR = first_lli.srcaddr;
channel->DESTADDR = first_lli.destaddr;
channel->LLI = first_lli.lli;
channel->CONTROL = first_lli.control;
channel->CONFIG = config;
LPC_GPDMA_Channel_Type* const channel = &LPC_GPDMA->CH[number];
channel->SRCADDR = first_lli.srcaddr;
channel->DESTADDR = first_lli.destaddr;
channel->LLI = first_lli.lli;
channel->CONTROL = first_lli.control;
channel->CONFIG = config;
}
} /* namespace channel */
@@ -70,42 +68,42 @@ void Channel::configure(
extern "C" {
CH_IRQ_HANDLER(DMA_IRQHandler) {
CH_IRQ_PROLOGUE();
CH_IRQ_PROLOGUE();
chSysLockFromIsr();
chSysLockFromIsr();
const auto tc_stat = LPC_GPDMA->INTTCSTAT;
/* TODO: Service the higher channel numbers first, they're higher priority
* right?!?
*/
for(size_t i=0; i<handlers_table.size(); i++) {
if( (tc_stat >> i) & 1 ) {
if( handlers_table[i].tc ) {
handlers_table[i].tc();
}
}
}
LPC_GPDMA->INTTCCLR = tc_stat;
const auto tc_stat = LPC_GPDMA->INTTCSTAT;
/* TODO: Service the higher channel numbers first, they're higher priority
* right?!?
*/
for (size_t i = 0; i < handlers_table.size(); i++) {
if ((tc_stat >> i) & 1) {
if (handlers_table[i].tc) {
handlers_table[i].tc();
}
}
}
LPC_GPDMA->INTTCCLR = tc_stat;
/* Test for *any* error first, before looping, since errors should be
* exceptional and we should spend as little time on them in the common
* case.
*/
const auto err_stat = LPC_GPDMA->INTERRSTAT;
if( err_stat ) {
for(size_t i=0; i<handlers_table.size(); i++) {
if( (err_stat >> i) & 1 ) {
if( handlers_table[i].err ) {
handlers_table[i].err();
}
}
}
LPC_GPDMA->INTERRCLR = err_stat;
}
/* Test for *any* error first, before looping, since errors should be
* exceptional and we should spend as little time on them in the common
* case.
*/
const auto err_stat = LPC_GPDMA->INTERRSTAT;
if (err_stat) {
for (size_t i = 0; i < handlers_table.size(); i++) {
if ((err_stat >> i) & 1) {
if (handlers_table[i].err) {
handlers_table[i].err();
}
}
}
LPC_GPDMA->INTERRCLR = err_stat;
}
chSysUnlockFromIsr();
chSysUnlockFromIsr();
CH_IRQ_EPILOGUE();
CH_IRQ_EPILOGUE();
}
}

View File

@@ -39,177 +39,160 @@ namespace gpdma {
*/
constexpr size_t buffer_words(const size_t bytes, const size_t word_size) {
return (bytes + word_size - 1) / word_size;
return (bytes + word_size - 1) / word_size;
}
using TCHandler = void (*)(void);
using ErrHandler = void (*)(void);
enum class FlowControl {
MemoryToMemory_DMAControl = 0x0,
MemoryToPeripheral_DMAControl = 0x1,
PeripheralToMemory_DMAControl = 0x2,
SourcePeripheralToDestinationPeripheral_DMAControl = 0x3,
SourcePeripheralToDestinationPeripheral_DestinationControl = 0x4,
MemoryToPeripheral_PeripheralControl = 0x5,
PeripheralToMemory_PeripheralControl = 0x6,
SourcePeripheralToDestinationPeripheral_SourceControl = 0x7,
MemoryToMemory_DMAControl = 0x0,
MemoryToPeripheral_DMAControl = 0x1,
PeripheralToMemory_DMAControl = 0x2,
SourcePeripheralToDestinationPeripheral_DMAControl = 0x3,
SourcePeripheralToDestinationPeripheral_DestinationControl = 0x4,
MemoryToPeripheral_PeripheralControl = 0x5,
PeripheralToMemory_PeripheralControl = 0x6,
SourcePeripheralToDestinationPeripheral_SourceControl = 0x7,
};
static const uint_fast8_t flow_control_peripheral_source_map = 0b11011100;
constexpr uint_fast8_t source_endpoint_type(const FlowControl flow_control) {
return (flow_control_peripheral_source_map >> toUType(flow_control)) & 1;
return (flow_control_peripheral_source_map >> toUType(flow_control)) & 1;
}
static const uint_fast8_t flow_control_peripheral_destination_map = 0b11111010;
constexpr uint_fast8_t destination_endpoint_type(const FlowControl flow_control) {
return (flow_control_peripheral_destination_map >> toUType(flow_control)) & 1;
return (flow_control_peripheral_destination_map >> toUType(flow_control)) & 1;
}
namespace mux {
enum class Peripheral0 {
SPIFI = 0,
SCT_CTOUT_2 = 1,
SGPIO14 = 2,
TIMER3_MATCH_1 = 3,
SPIFI = 0,
SCT_CTOUT_2 = 1,
SGPIO14 = 2,
TIMER3_MATCH_1 = 3,
};
enum class Peripheral1 {
TIMER0_MATCH_0 = 0,
USART0_TX = 1,
TIMER0_MATCH_0 = 0,
USART0_TX = 1,
};
enum class Peripheral2 {
TIMER0_MATCH_1 = 0,
USART0_RX = 1,
TIMER0_MATCH_1 = 0,
USART0_RX = 1,
};
enum class Peripheral3 {
TIMER1_MATCH_0 = 0,
UART1_TX = 1,
I2S1_DMAREQ_1 = 2,
SSP1_TX = 3,
TIMER1_MATCH_0 = 0,
UART1_TX = 1,
I2S1_DMAREQ_1 = 2,
SSP1_TX = 3,
};
enum class Peripheral4 {
TIMER1_MATCH_1 = 0,
UART1_RX = 1,
I2S1_DMAREQ_2 = 2,
SSP1_RX = 3,
TIMER1_MATCH_1 = 0,
UART1_RX = 1,
I2S1_DMAREQ_2 = 2,
SSP1_RX = 3,
};
enum class Peripheral5 {
TIMER2_MATCH_0 = 0,
USART2_TX = 1,
SSP1_TX = 2,
SGPIO15 = 3,
TIMER2_MATCH_0 = 0,
USART2_TX = 1,
SSP1_TX = 2,
SGPIO15 = 3,
};
enum class Peripheral6 {
TIMER2_MATCH_1 = 0,
USART2_RX = 1,
SSP1_RX = 2,
SGPIO14 = 3,
TIMER2_MATCH_1 = 0,
USART2_RX = 1,
SSP1_RX = 2,
SGPIO14 = 3,
};
enum class Peripheral7 {
TIMER3_MATCH_0 = 0,
USART3_TX = 1,
SCT_DMAREQ_0 = 2,
ADCHS_WRITE = 3,
TIMER3_MATCH_0 = 0,
USART3_TX = 1,
SCT_DMAREQ_0 = 2,
ADCHS_WRITE = 3,
};
enum class Peripheral8 {
TIMER3_MATCH_1 = 0,
USART3_RX = 1,
SCT_DMAREQ_1 = 2,
ADCHS_READ = 3,
TIMER3_MATCH_1 = 0,
USART3_RX = 1,
SCT_DMAREQ_1 = 2,
ADCHS_READ = 3,
};
enum class Peripheral9 {
SSP0_RX = 0,
I2S0_DMAREQ_1 = 1,
SCT_DMAREQ_1 = 2,
SSP0_RX = 0,
I2S0_DMAREQ_1 = 1,
SCT_DMAREQ_1 = 2,
};
enum class Peripheral10 {
SSP0_TX = 0,
I2S0_DMAREQ_2 = 1,
SCT_DMAREQ_0 = 2,
SSP0_TX = 0,
I2S0_DMAREQ_2 = 1,
SCT_DMAREQ_0 = 2,
};
enum class Peripheral11 {
SSP1_RX = 0,
SGPIO14 = 1,
USART0_TX = 2,
SSP1_RX = 0,
SGPIO14 = 1,
USART0_TX = 2,
};
enum class Peripheral12 {
SSP1_TX = 0,
SGPIO15 = 1,
USART0_RX = 2,
SSP1_TX = 0,
SGPIO15 = 1,
USART0_RX = 2,
};
enum class Peripheral13 {
ADC0 = 0,
SSP1_RX = 2,
USART3_RX = 3,
ADC0 = 0,
SSP1_RX = 2,
USART3_RX = 3,
};
enum class Peripheral14 {
ADC1 = 0,
SSP1_TX = 2,
USART3_TX = 3,
ADC1 = 0,
SSP1_TX = 2,
USART3_TX = 3,
};
enum class Peripheral15 {
DAC = 0,
SCT_CTOUT_3 = 1,
SGPIO15 = 2,
TIMER3_MATCH_0 = 3,
DAC = 0,
SCT_CTOUT_3 = 1,
SGPIO15 = 2,
TIMER3_MATCH_0 = 3,
};
struct MUX {
Peripheral0 peripheral_0;
Peripheral1 peripheral_1;
Peripheral2 peripheral_2;
Peripheral3 peripheral_3;
Peripheral4 peripheral_4;
Peripheral5 peripheral_5;
Peripheral6 peripheral_6;
Peripheral7 peripheral_7;
Peripheral8 peripheral_8;
Peripheral9 peripheral_9;
Peripheral10 peripheral_10;
Peripheral11 peripheral_11;
Peripheral12 peripheral_12;
Peripheral13 peripheral_13;
Peripheral14 peripheral_14;
Peripheral15 peripheral_15;
Peripheral0 peripheral_0;
Peripheral1 peripheral_1;
Peripheral2 peripheral_2;
Peripheral3 peripheral_3;
Peripheral4 peripheral_4;
Peripheral5 peripheral_5;
Peripheral6 peripheral_6;
Peripheral7 peripheral_7;
Peripheral8 peripheral_8;
Peripheral9 peripheral_9;
Peripheral10 peripheral_10;
Peripheral11 peripheral_11;
Peripheral12 peripheral_12;
Peripheral13 peripheral_13;
Peripheral14 peripheral_14;
Peripheral15 peripheral_15;
constexpr operator uint32_t() const {
return
(toUType(peripheral_0 ) << 0)
| (toUType(peripheral_1 ) << 2)
| (toUType(peripheral_2 ) << 4)
| (toUType(peripheral_3 ) << 6)
| (toUType(peripheral_4 ) << 8)
| (toUType(peripheral_5 ) << 10)
| (toUType(peripheral_6 ) << 12)
| (toUType(peripheral_7 ) << 14)
| (toUType(peripheral_8 ) << 16)
| (toUType(peripheral_9 ) << 18)
| (toUType(peripheral_10) << 20)
| (toUType(peripheral_11) << 22)
| (toUType(peripheral_12) << 24)
| (toUType(peripheral_13) << 26)
| (toUType(peripheral_14) << 28)
| (toUType(peripheral_15) << 30)
;
}
constexpr operator uint32_t() const {
return (toUType(peripheral_0) << 0) | (toUType(peripheral_1) << 2) | (toUType(peripheral_2) << 4) | (toUType(peripheral_3) << 6) | (toUType(peripheral_4) << 8) | (toUType(peripheral_5) << 10) | (toUType(peripheral_6) << 12) | (toUType(peripheral_7) << 14) | (toUType(peripheral_8) << 16) | (toUType(peripheral_9) << 18) | (toUType(peripheral_10) << 20) | (toUType(peripheral_11) << 22) | (toUType(peripheral_12) << 24) | (toUType(peripheral_13) << 26) | (toUType(peripheral_14) << 28) | (toUType(peripheral_15) << 30);
}
};
} /* namespace mux */
@@ -217,154 +200,131 @@ struct MUX {
namespace channel {
struct LLI {
uint32_t srcaddr;
uint32_t destaddr;
uint32_t lli;
uint32_t control;
uint32_t srcaddr;
uint32_t destaddr;
uint32_t lli;
uint32_t control;
};
struct LLIPointer {
uint32_t lm;
uint32_t r;
uint32_t lli;
uint32_t lm;
uint32_t r;
uint32_t lli;
constexpr operator uint32_t() const {
return
((lm & 1) << 0)
| ((r & 1) << 1)
| (lli & 0xfffffffc)
;
}
constexpr operator uint32_t() const {
return ((lm & 1) << 0) | ((r & 1) << 1) | (lli & 0xfffffffc);
}
};
struct Control {
uint32_t transfersize;
uint32_t sbsize;
uint32_t dbsize;
uint32_t swidth;
uint32_t dwidth;
uint32_t s;
uint32_t d;
uint32_t si;
uint32_t di;
uint32_t prot1;
uint32_t prot2;
uint32_t prot3;
uint32_t i;
uint32_t transfersize;
uint32_t sbsize;
uint32_t dbsize;
uint32_t swidth;
uint32_t dwidth;
uint32_t s;
uint32_t d;
uint32_t si;
uint32_t di;
uint32_t prot1;
uint32_t prot2;
uint32_t prot3;
uint32_t i;
constexpr operator uint32_t() const {
return
((transfersize & 0xfff) << 0)
| ((sbsize & 7) << 12)
| ((dbsize & 7) << 15)
| ((swidth & 7) << 18)
| ((dwidth & 7) << 21)
| ((s & 1) << 24)
| ((d & 1) << 25)
| ((si & 1) << 26)
| ((di & 1) << 27)
| ((prot1 & 1) << 28)
| ((prot2 & 1) << 29)
| ((prot3 & 1) << 30)
| ((i & 1) << 31)
;
}
constexpr operator uint32_t() const {
return ((transfersize & 0xfff) << 0) | ((sbsize & 7) << 12) | ((dbsize & 7) << 15) | ((swidth & 7) << 18) | ((dwidth & 7) << 21) | ((s & 1) << 24) | ((d & 1) << 25) | ((si & 1) << 26) | ((di & 1) << 27) | ((prot1 & 1) << 28) | ((prot2 & 1) << 29) | ((prot3 & 1) << 30) | ((i & 1) << 31);
}
};
struct Config {
uint32_t e;
uint32_t srcperipheral;
uint32_t destperipheral;
FlowControl flowcntrl;
uint32_t ie;
uint32_t itc;
uint32_t l;
uint32_t a;
uint32_t h;
uint32_t e;
uint32_t srcperipheral;
uint32_t destperipheral;
FlowControl flowcntrl;
uint32_t ie;
uint32_t itc;
uint32_t l;
uint32_t a;
uint32_t h;
constexpr operator uint32_t() const {
return
((e & 1) << 0)
| ((srcperipheral & 0x1f) << 1)
| ((destperipheral & 0x1f) << 6)
| ((toUType(flowcntrl) & 7) << 11)
| ((ie & 1) << 14)
| ((itc & 1) << 15)
| ((l & 1) << 16)
| ((a & 1) << 17)
| ((h & 1) << 18)
;
}
constexpr operator uint32_t() const {
return ((e & 1) << 0) | ((srcperipheral & 0x1f) << 1) | ((destperipheral & 0x1f) << 6) | ((toUType(flowcntrl) & 7) << 11) | ((ie & 1) << 14) | ((itc & 1) << 15) | ((l & 1) << 16) | ((a & 1) << 17) | ((h & 1) << 18);
}
};
class Channel {
public:
constexpr Channel(
const size_t number
) : number(number)
{
}
public:
constexpr Channel(
const size_t number)
: number(number) {
}
void enable() const {
LPC_GPDMA->CH[number].CONFIG |= (1U << 0);
}
void enable() const {
LPC_GPDMA->CH[number].CONFIG |= (1U << 0);
}
bool is_enabled() const {
return LPC_GPDMA->CH[number].CONFIG & (1U << 0);
}
bool is_enabled() const {
return LPC_GPDMA->CH[number].CONFIG & (1U << 0);
}
void disable() const {
LPC_GPDMA->CH[number].CONFIG &= ~(1U << 0);
}
void disable() const {
LPC_GPDMA->CH[number].CONFIG &= ~(1U << 0);
}
void clear_interrupts() const {
LPC_GPDMA->INTTCCLR = (1U << number);
LPC_GPDMA->INTERRCLR = (1U << number);
}
void clear_interrupts() const {
LPC_GPDMA->INTTCCLR = (1U << number);
LPC_GPDMA->INTERRCLR = (1U << number);
}
void set_handlers(const TCHandler tc_handler, const ErrHandler err_handler) const;
void set_handlers(const TCHandler tc_handler, const ErrHandler err_handler) const;
void configure(const LLI& first_lli, const uint32_t config) const;
void configure(const LLI& first_lli, const uint32_t config) const;
const LLI* next_lli() const {
return reinterpret_cast<LLI*>(LPC_GPDMA->CH[number].LLI);
}
const LLI* next_lli() const {
return reinterpret_cast<LLI*>(LPC_GPDMA->CH[number].LLI);
}
private:
const size_t number;
private:
const size_t number;
};
} /* namespace channel */
constexpr std::array<channel::Channel, 8> channels { {
{ 0 }, { 1 }, { 2 }, { 3 },
{ 4 }, { 5 }, { 6 }, { 7 },
} };
constexpr std::array<channel::Channel, 8> channels{{
{0},
{1},
{2},
{3},
{4},
{5},
{6},
{7},
}};
static const gpdma_resources_t gpdma_resources = {
.base = { .clk = &LPC_CGU->BASE_M4_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 3) },
.branch = { .cfg = &LPC_CCU1->CLK_M4_DMA_CFG, .stat = &LPC_CCU1->CLK_M4_DMA_STAT },
.reset = { .output_index = 19 },
.base = {.clk = &LPC_CGU->BASE_M4_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 3)},
.branch = {.cfg = &LPC_CCU1->CLK_M4_DMA_CFG, .stat = &LPC_CCU1->CLK_M4_DMA_STAT},
.reset = {.output_index = 19},
};
class Controller {
public:
void enable() const {
base_clock_enable(&gpdma_resources.base);
branch_clock_enable(&gpdma_resources.branch);
peripheral_reset(&gpdma_resources.reset);
LPC_GPDMA->CONFIG |= (1U << 0);
}
public:
void enable() const {
base_clock_enable(&gpdma_resources.base);
branch_clock_enable(&gpdma_resources.branch);
peripheral_reset(&gpdma_resources.reset);
LPC_GPDMA->CONFIG |= (1U << 0);
}
void disable() const {
for(const auto& channel : channels) {
channel.disable();
}
LPC_GPDMA->CONFIG &= ~(1U << 0);
peripheral_reset(&gpdma_resources.reset);
branch_clock_disable(&gpdma_resources.branch);
base_clock_disable(&gpdma_resources.base);
}
void disable() const {
for (const auto& channel : channels) {
channel.disable();
}
LPC_GPDMA->CONFIG &= ~(1U << 0);
peripheral_reset(&gpdma_resources.reset);
branch_clock_disable(&gpdma_resources.branch);
base_clock_disable(&gpdma_resources.base);
}
};
constexpr Controller controller;
@@ -372,4 +332,4 @@ constexpr Controller controller;
} /* namespace gpdma */
} /* namespace lpc43xx */
#endif/*__GPDMA_H__*/
#endif /*__GPDMA_H__*/

View File

@@ -28,276 +28,256 @@
#include "hal.h"
struct PinConfig {
const uint32_t mode;
const uint32_t pd;
const uint32_t pu;
const uint32_t fast;
const uint32_t input;
const uint32_t ifilt;
const uint32_t mode;
const uint32_t pd;
const uint32_t pu;
const uint32_t fast;
const uint32_t input;
const uint32_t ifilt;
constexpr operator uint16_t() const {
return
(((~ifilt) & 1) << 7)
| ((input & 1) << 6)
| ((fast & 1) << 5)
| (((~pu) & 1) << 4)
| ((pd & 1) << 3)
| ((mode & 7) << 0);
}
/*
constexpr operator uint32_t() {
return scu::sfs::mode::value(mode)
<< scu::sfs::epd::value(pd)
<< scu::sfs::epun::value(~pu)
<< scu::sfs::ehs::value(fast)
<< scu::sfs::ezi::value(input)
<< scu::sfs::zif::value(~ifilt)
;
}
constexpr operator uint16_t() const {
return (((~ifilt) & 1) << 7) | ((input & 1) << 6) | ((fast & 1) << 5) | (((~pu) & 1) << 4) | ((pd & 1) << 3) | ((mode & 7) << 0);
}
/*
constexpr operator uint32_t() {
return scu::sfs::mode::value(mode)
<< scu::sfs::epd::value(pd)
<< scu::sfs::epun::value(~pu)
<< scu::sfs::ehs::value(fast)
<< scu::sfs::ezi::value(input)
<< scu::sfs::zif::value(~ifilt)
;
}
*/
static constexpr PinConfig reset() {
return { .mode = 0, .pd = 0, .pu = 1, .fast = 0, .input = 0, .ifilt = 1 };
}
static constexpr PinConfig reset() {
return {.mode = 0, .pd = 0, .pu = 1, .fast = 0, .input = 0, .ifilt = 1};
}
static constexpr PinConfig floating(
const uint32_t mode
) {
return {
.mode = mode,
.pd = 0,
.pu = 0,
.fast = 0,
.input = 0,
.ifilt = 1
};
}
static constexpr PinConfig floating(
const uint32_t mode) {
return {
.mode = mode,
.pd = 0,
.pu = 0,
.fast = 0,
.input = 0,
.ifilt = 1};
}
static constexpr PinConfig floating_input(
const uint32_t mode
) {
return {
.mode = mode,
.pd = 0,
.pu = 0,
.fast = 0,
.input = 1,
.ifilt = 1
};
}
static constexpr PinConfig floating_input(
const uint32_t mode) {
return {
.mode = mode,
.pd = 0,
.pu = 0,
.fast = 0,
.input = 1,
.ifilt = 1};
}
static constexpr PinConfig floating_input_with_pull(
const uint32_t pull_direction,
const uint32_t mode
) {
return {
.mode = mode,
.pd = (pull_direction == 0) ? 1U : 0U,
.pu = (pull_direction == 1) ? 1U : 0U,
.fast = 0,
.input = 1,
.ifilt = 1
};
}
static constexpr PinConfig floating_input_with_pull(
const uint32_t pull_direction,
const uint32_t mode) {
return {
.mode = mode,
.pd = (pull_direction == 0) ? 1U : 0U,
.pu = (pull_direction == 1) ? 1U : 0U,
.fast = 0,
.input = 1,
.ifilt = 1};
}
static constexpr PinConfig gpio_led(const uint32_t mode) {
return { .mode = mode, .pd = 0, .pu = 0, .fast = 0, .input = 0, .ifilt = 1 };
}
static constexpr PinConfig gpio_led(const uint32_t mode) {
return {.mode = mode, .pd = 0, .pu = 0, .fast = 0, .input = 0, .ifilt = 1};
}
static constexpr PinConfig gpio_inout_with_pull(
const uint32_t mode,
const uint32_t pull_direction
) {
return {
.mode = mode,
.pd = (pull_direction == 0) ? 1U : 0U,
.pu = (pull_direction == 1) ? 1U : 0U,
.fast = 0,
.input = 1,
.ifilt = 1
};
}
static constexpr PinConfig gpio_inout_with_pull(
const uint32_t mode,
const uint32_t pull_direction) {
return {
.mode = mode,
.pd = (pull_direction == 0) ? 1U : 0U,
.pu = (pull_direction == 1) ? 1U : 0U,
.fast = 0,
.input = 1,
.ifilt = 1};
}
static constexpr PinConfig gpio_inout_with_pullup(const uint32_t mode) {
return gpio_inout_with_pull(mode, 1);
}
static constexpr PinConfig gpio_inout_with_pullup(const uint32_t mode) {
return gpio_inout_with_pull(mode, 1);
}
static constexpr PinConfig gpio_inout_with_pulldown(const uint32_t mode) {
return gpio_inout_with_pull(mode, 0);
}
static constexpr PinConfig gpio_inout_with_pulldown(const uint32_t mode) {
return gpio_inout_with_pull(mode, 0);
}
static constexpr PinConfig gpio_out_with_pull(
const uint32_t mode,
const uint32_t pull_direction
) {
return {
.mode = mode,
.pd = (pull_direction == 0) ? 1U : 0U,
.pu = (pull_direction == 1) ? 1U : 0U,
.fast = 0,
.input = 0,
.ifilt = 1
};
}
static constexpr PinConfig gpio_out_with_pull(
const uint32_t mode,
const uint32_t pull_direction) {
return {
.mode = mode,
.pd = (pull_direction == 0) ? 1U : 0U,
.pu = (pull_direction == 1) ? 1U : 0U,
.fast = 0,
.input = 0,
.ifilt = 1};
}
static constexpr PinConfig gpio_out_with_pulldown(const uint32_t mode) {
return gpio_out_with_pull(mode, 0);
}
static constexpr PinConfig gpio_out_with_pulldown(const uint32_t mode) {
return gpio_out_with_pull(mode, 0);
}
static constexpr PinConfig gpio_out_with_pullup(const uint32_t mode) {
return gpio_out_with_pull(mode, 1);
}
static constexpr PinConfig gpio_out_with_pullup(const uint32_t mode) {
return gpio_out_with_pull(mode, 1);
}
static constexpr PinConfig sgpio_in_fast(const uint32_t mode) {
return { .mode = mode, .pd = 0, .pu = 0, .fast = 0, .input = 1, .ifilt = 0 };
}
static constexpr PinConfig sgpio_in_fast(const uint32_t mode) {
return {.mode = mode, .pd = 0, .pu = 0, .fast = 0, .input = 1, .ifilt = 0};
}
static constexpr PinConfig sgpio_out_fast_with_pull(
const uint32_t mode,
const uint32_t pull_direction
) {
return {
.mode = mode,
.pd = (pull_direction == 0) ? 1U : 0U,
.pu = (pull_direction == 1) ? 1U : 0U,
.fast = 1,
.input = 0,
.ifilt = 1
};
}
static constexpr PinConfig sgpio_out_fast_with_pull(
const uint32_t mode,
const uint32_t pull_direction) {
return {
.mode = mode,
.pd = (pull_direction == 0) ? 1U : 0U,
.pu = (pull_direction == 1) ? 1U : 0U,
.fast = 1,
.input = 0,
.ifilt = 1};
}
static constexpr PinConfig sgpio_out_fast_with_pullup(const uint32_t mode) {
return sgpio_out_fast_with_pull(mode, 1);
}
static constexpr PinConfig sgpio_out_fast_with_pullup(const uint32_t mode) {
return sgpio_out_fast_with_pull(mode, 1);
}
static constexpr PinConfig sgpio_inout_fast(const uint32_t mode) {
return { .mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 1, .ifilt = 0 };
}
static constexpr PinConfig sgpio_inout_fast(const uint32_t mode) {
return {.mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 1, .ifilt = 0};
}
static constexpr PinConfig i2c(const uint32_t mode) {
return { .mode = mode, .pd = 0, .pu = 0, .fast = 0, .input = 1, .ifilt = 1 };
}
static constexpr PinConfig i2c(const uint32_t mode) {
return {.mode = mode, .pd = 0, .pu = 0, .fast = 0, .input = 1, .ifilt = 1};
}
static constexpr PinConfig spifi_sck(const uint32_t mode ) {
return { .mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 1, .ifilt = 0 };
}
static constexpr PinConfig spifi_sck(const uint32_t mode) {
return {.mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 1, .ifilt = 0};
}
static constexpr PinConfig spifi_inout(const uint32_t mode) {
return { .mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 1, .ifilt = 0 };
}
static constexpr PinConfig spifi_inout(const uint32_t mode) {
return {.mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 1, .ifilt = 0};
}
static constexpr PinConfig spifi_cs(const uint32_t mode) {
return { .mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 1, .ifilt = 0 };
}
static constexpr PinConfig spifi_cs(const uint32_t mode) {
return {.mode = mode, .pd = 0, .pu = 0, .fast = 1, .input = 1, .ifilt = 0};
}
};
struct Pin {
// Pin() = delete;
// Pin(const Pin&) = delete;
// Pin(Pin&&) = delete;
// Pin() = delete;
// Pin(const Pin&) = delete;
// Pin(Pin&&) = delete;
constexpr Pin(
const uint8_t port,
const uint8_t pad
) : _pin_port { port },
_pin_pad { pad }
{
}
constexpr Pin(
const uint8_t port,
const uint8_t pad)
: _pin_port{port},
_pin_pad{pad} {
}
void mode(const uint_fast16_t mode) const {
LPC_SCU->SFSP[_pin_port][_pin_pad] =
(LPC_SCU->SFSP[_pin_port][_pin_pad] & 0xfffffff8) | mode;
}
void mode(const uint_fast16_t mode) const {
LPC_SCU->SFSP[_pin_port][_pin_pad] =
(LPC_SCU->SFSP[_pin_port][_pin_pad] & 0xfffffff8) | mode;
}
void configure(const PinConfig config) const {
LPC_SCU->SFSP[_pin_port][_pin_pad] = config;
}
void configure(const PinConfig config) const {
LPC_SCU->SFSP[_pin_port][_pin_pad] = config;
}
uint8_t _pin_port;
uint8_t _pin_pad;
uint8_t _pin_port;
uint8_t _pin_pad;
};
struct GPIO {
// GPIO() = delete;
// GPIO(const GPIO& gpio) = delete;
// GPIO(GPIO&&) = delete;
// GPIO() = delete;
// GPIO(const GPIO& gpio) = delete;
// GPIO(GPIO&&) = delete;
constexpr GPIO(
const Pin& pin,
const ioportid_t gpio_port,
const iopadid_t gpio_pad,
const uint16_t gpio_mode
) : _pin { pin },
_gpio_port { gpio_port },
_gpio_pad { gpio_pad },
_gpio_mode { gpio_mode }
{
}
/*
constexpr GPIO(
const GPIO& gpio
) : _pin { gpio._pin },
_gpio_port { gpio._gpio_port },
_gpio_pad { gpio._gpio_pad },
_gpio_mode { gpio._gpio_mode }
{
}
constexpr GPIO(
const Pin& pin,
const ioportid_t gpio_port,
const iopadid_t gpio_pad,
const uint16_t gpio_mode)
: _pin{pin},
_gpio_port{gpio_port},
_gpio_pad{gpio_pad},
_gpio_mode{gpio_mode} {
}
/*
constexpr GPIO(
const GPIO& gpio
) : _pin { gpio._pin },
_gpio_port { gpio._gpio_port },
_gpio_pad { gpio._gpio_pad },
_gpio_mode { gpio._gpio_mode }
{
}
*/
constexpr ioportid_t port() const {
return _gpio_port;
}
constexpr ioportid_t port() const {
return _gpio_port;
}
constexpr iopadid_t pad() const {
return _gpio_pad;
}
constexpr iopadid_t pad() const {
return _gpio_pad;
}
constexpr Pin pin() const {
return _pin;
}
constexpr Pin pin() const {
return _pin;
}
void configure() const {
_pin.mode(_gpio_mode);
}
void configure() const {
_pin.mode(_gpio_mode);
}
uint_fast16_t mode() const {
return _gpio_mode;
}
uint_fast16_t mode() const {
return _gpio_mode;
}
void set() const {
palSetPad(_gpio_port, _gpio_pad);
}
void set() const {
palSetPad(_gpio_port, _gpio_pad);
}
void clear() const {
palClearPad(_gpio_port, _gpio_pad);
}
void clear() const {
palClearPad(_gpio_port, _gpio_pad);
}
void toggle() const {
palTogglePad(_gpio_port, _gpio_pad);
}
void toggle() const {
palTogglePad(_gpio_port, _gpio_pad);
}
void output() const {
palSetPadMode(_gpio_port, _gpio_pad, PAL_MODE_OUTPUT_PUSHPULL);
}
void output() const {
palSetPadMode(_gpio_port, _gpio_pad, PAL_MODE_OUTPUT_PUSHPULL);
}
void input() const {
palSetPadMode(_gpio_port, _gpio_pad, PAL_MODE_INPUT);
}
void input() const {
palSetPadMode(_gpio_port, _gpio_pad, PAL_MODE_INPUT);
}
void write(const bool value) const {
palWritePad(_gpio_port, _gpio_pad, value);
}
void write(const bool value) const {
palWritePad(_gpio_port, _gpio_pad, value);
}
bool read() const {
return palReadPad(_gpio_port, _gpio_pad);
}
bool read() const {
return palReadPad(_gpio_port, _gpio_pad);
}
bool operator!=(const GPIO& other) const {
return (port() != other.port()) || (pad() != other.pad());
}
bool operator!=(const GPIO& other) const {
return (port() != other.port()) || (pad() != other.pad());
}
const Pin _pin;
const ioportid_t _gpio_port;
const iopadid_t _gpio_pad;
const uint16_t _gpio_mode;
const Pin _pin;
const ioportid_t _gpio_port;
const iopadid_t _gpio_pad;
const uint16_t _gpio_mode;
};
#endif/*__GPIO_H__*/
#endif /*__GPIO_H__*/

View File

@@ -32,8 +32,8 @@ using CPLD = ::cpld::xilinx::XC2C64A;
extern const CPLD::verify_blocks_t verify_blocks;
} /* namespace hackrf */
} // namespace cpld
} /* namespace one */
} /* namespace cpld */
} // namespace hackrf
#endif/*__HACKRF_CPLD_DATA_H__*/
#endif /*__HACKRF_CPLD_DATA_H__*/

View File

@@ -89,11 +89,11 @@ constexpr GPIO gpio_r9_not_ant_pwr = gpio[GPIO2_4];
/* LEDs */
constexpr LED led_usb { gpio_led_usb };
constexpr LED led_rx { gpio_led_rx };
constexpr LED led_tx { gpio_led_tx };
constexpr LED led_usb{gpio_led_usb};
constexpr LED led_rx{gpio_led_rx};
constexpr LED led_tx{gpio_led_tx};
} /* namespace one */
} /* namespace hackrf */
#endif/*__HACKRF_GPIO_H__*/
#endif /*__HACKRF_GPIO_H__*/

View File

@@ -35,40 +35,40 @@ namespace one {
using ClockFrequency = uint32_t;
constexpr ClockFrequency si5351_xtal_f = 25000000U;
constexpr ClockFrequency si5351_clkin_f = 10000000U;
constexpr ClockFrequency si5351_xtal_f = 25000000U;
constexpr ClockFrequency si5351_clkin_f = 10000000U;
/* TODO: Use this many other places. */
/* TODO: M4/M0 and peripheral rates may be more PortaPack-specific? Move out
* of HackRF header? */
constexpr ClockFrequency base_m4_clk_f = 200000000U;
constexpr ClockFrequency base_m0_clk_f = base_m4_clk_f;
constexpr ClockFrequency base_apb3_clk_f = base_m4_clk_f;
constexpr ClockFrequency ssp1_pclk_f = base_m4_clk_f;
constexpr ClockFrequency base_m4_clk_f = 200000000U;
constexpr ClockFrequency base_m0_clk_f = base_m4_clk_f;
constexpr ClockFrequency base_apb3_clk_f = base_m4_clk_f;
constexpr ClockFrequency ssp1_pclk_f = base_m4_clk_f;
constexpr ClockFrequency max5864_spi_f = 20000000U;
constexpr ClockFrequency max283x_spi_f = 20000000U;
constexpr ClockFrequency max5864_spi_f = 20000000U;
constexpr ClockFrequency max283x_spi_f = 20000000U;
constexpr ClockFrequency rffc5072_reference_f = 40000000U;
constexpr ClockFrequency max283x_reference_f = 40000000U;
constexpr ClockFrequency mcu_clkin_og_f = 40000000U;
constexpr ClockFrequency mcu_clkin_r9_f = 10000000U;
constexpr ClockFrequency rffc5072_reference_f = 40000000U;
constexpr ClockFrequency max283x_reference_f = 40000000U;
constexpr ClockFrequency mcu_clkin_og_f = 40000000U;
constexpr ClockFrequency mcu_clkin_r9_f = 10000000U;
constexpr uint8_t si5351_i2c_address = 0x60;
/* Clock Generator */
constexpr size_t clock_generator_output_og_codec = 0;
constexpr size_t clock_generator_output_og_cpld = 1;
constexpr size_t clock_generator_output_og_sgpio = 2;
constexpr size_t clock_generator_output_og_clkout = 3;
constexpr size_t clock_generator_output_og_first_if = 4;
constexpr size_t clock_generator_output_og_second_if = 5;
constexpr size_t clock_generator_output_og_mcu_clkin = 7;
constexpr size_t clock_generator_output_og_codec = 0;
constexpr size_t clock_generator_output_og_cpld = 1;
constexpr size_t clock_generator_output_og_sgpio = 2;
constexpr size_t clock_generator_output_og_clkout = 3;
constexpr size_t clock_generator_output_og_first_if = 4;
constexpr size_t clock_generator_output_og_second_if = 5;
constexpr size_t clock_generator_output_og_mcu_clkin = 7;
constexpr size_t clock_generator_output_r9_if = 0;
constexpr size_t clock_generator_output_r9_sgpio = 1;
constexpr size_t clock_generator_output_r9_mcu_clkin = 2;
constexpr size_t clock_generator_output_r9_if = 0;
constexpr size_t clock_generator_output_r9_sgpio = 1;
constexpr size_t clock_generator_output_r9_mcu_clkin = 2;
/* ADC0 */
@@ -81,4 +81,4 @@ using adc1 = adc::ADC<LPC_ADC1_BASE>;
} /* namespace one */
} /* namespace hackrf */
#endif/*__HACKRF_HAL_H__*/
#endif /*__HACKRF_HAL_H__*/

View File

@@ -22,44 +22,43 @@
#include "i2c_pp.hpp"
void I2C::start(const I2CConfig& config) {
i2cStart(_driver, &config);
i2cStart(_driver, &config);
}
void I2C::stop() {
i2cStop(_driver);
i2cStop(_driver);
}
bool I2C::transfer(
const address_t slave_address,
const uint8_t* const data_tx, const size_t count_tx,
uint8_t* const data_rx, const size_t count_rx,
systime_t timeout
) {
i2cAcquireBus(_driver);
const msg_t status = i2cMasterTransmitTimeout(
_driver, slave_address, data_tx, count_tx, data_rx, count_rx, timeout
);
i2cReleaseBus(_driver);
return (status == RDY_OK);
const address_t slave_address,
const uint8_t* const data_tx,
const size_t count_tx,
uint8_t* const data_rx,
const size_t count_rx,
systime_t timeout) {
i2cAcquireBus(_driver);
const msg_t status = i2cMasterTransmitTimeout(
_driver, slave_address, data_tx, count_tx, data_rx, count_rx, timeout);
i2cReleaseBus(_driver);
return (status == RDY_OK);
}
bool I2C::receive(
const address_t slave_address,
uint8_t* const data, const size_t count,
systime_t timeout
) {
i2cAcquireBus(_driver);
const msg_t status = i2cMasterReceiveTimeout(
_driver, slave_address, data, count, timeout
);
i2cReleaseBus(_driver);
return (status == RDY_OK);
const address_t slave_address,
uint8_t* const data,
const size_t count,
systime_t timeout) {
i2cAcquireBus(_driver);
const msg_t status = i2cMasterReceiveTimeout(
_driver, slave_address, data, count, timeout);
i2cReleaseBus(_driver);
return (status == RDY_OK);
}
bool I2C::transmit(
const address_t slave_address,
const uint8_t* const data, const size_t count,
systime_t timeout
) {
return transfer(slave_address, data, count, NULL, 0, timeout);
const address_t slave_address,
const uint8_t* const data,
const size_t count,
systime_t timeout) {
return transfer(slave_address, data, count, NULL, 0, timeout);
}

View File

@@ -28,59 +28,60 @@
#include "hal.h"
struct I2CClockConfig {
float clock_source_f;
float bus_f;
float high_period_ns;
float clock_source_f;
float bus_f;
float high_period_ns;
static constexpr float period_ns(const float f) {
return 1e9 / f;
}
static constexpr float period_ns(const float f) {
return 1e9 / f;
}
constexpr uint32_t i2c_period_count() const {
return period_ns(bus_f) / period_ns(clock_source_f) + 0.5f;
}
constexpr uint32_t i2c_period_count() const {
return period_ns(bus_f) / period_ns(clock_source_f) + 0.5f;
}
constexpr uint32_t i2c_high_count() const {
return high_period_ns / period_ns(clock_source_f) + 0.5f;
}
constexpr uint32_t i2c_high_count() const {
return high_period_ns / period_ns(clock_source_f) + 0.5f;
}
constexpr uint32_t i2c_low_count() const {
return i2c_period_count() - i2c_high_count();
}
constexpr uint32_t i2c_low_count() const {
return i2c_period_count() - i2c_high_count();
}
};
class I2C {
public:
using address_t = uint8_t;
public:
using address_t = uint8_t;
constexpr I2C(I2CDriver* const driver) :
_driver(driver) {
}
constexpr I2C(I2CDriver* const driver)
: _driver(driver) {
}
void start(const I2CConfig& config);
void stop();
void start(const I2CConfig& config);
void stop();
bool receive(
const address_t slave_address,
uint8_t* const data, const size_t count,
const systime_t timeout = TIME_INFINITE
);
bool receive(
const address_t slave_address,
uint8_t* const data,
const size_t count,
const systime_t timeout = TIME_INFINITE);
bool transmit(
const address_t slave_address,
const uint8_t* const data, const size_t count,
const systime_t timeout = TIME_INFINITE
);
bool transmit(
const address_t slave_address,
const uint8_t* const data,
const size_t count,
const systime_t timeout = TIME_INFINITE);
private:
I2CDriver* const _driver;
private:
I2CDriver* const _driver;
bool transfer(
const address_t slave_address,
const uint8_t* const data_tx, const size_t count_tx,
uint8_t* const data_rx, const size_t count_rx,
const systime_t timeout
);
bool transfer(
const address_t slave_address,
const uint8_t* const data_tx,
const size_t count_tx,
uint8_t* const data_rx,
const size_t count_rx,
const systime_t timeout);
};
#endif/*__I2C_PP_H__*/
#endif /*__I2C_PP_H__*/

View File

@@ -30,242 +30,213 @@ namespace lpc43xx {
namespace i2s {
enum class WordWidth {
Bits8 = 0x0,
Bits16 = 0x1,
Bits32 = 0x3,
Bits8 = 0x0,
Bits16 = 0x1,
Bits32 = 0x3,
};
enum class ClockSelect {
FractionalDivider = 0x0,
BaseAudioClkOrExternalMCLK = 0x01,
OtherMCLK = 0x2,
FractionalDivider = 0x0,
BaseAudioClkOrExternalMCLK = 0x01,
OtherMCLK = 0x2,
};
struct DAO {
WordWidth wordwidth;
uint32_t mono;
uint32_t stop;
uint32_t reset;
uint32_t ws_sel;
uint32_t ws_halfperiod;
uint32_t mute;
WordWidth wordwidth;
uint32_t mono;
uint32_t stop;
uint32_t reset;
uint32_t ws_sel;
uint32_t ws_halfperiod;
uint32_t mute;
constexpr operator uint32_t() const {
return
((toUType(wordwidth) & 3) << 0)
| ((mono & 1) << 2)
| ((stop & 1) << 3)
| ((reset & 1) << 4)
| ((ws_sel & 1) << 5)
| ((ws_halfperiod & 0x1ff) << 6)
| ((mute & 1) << 15)
;
}
constexpr operator uint32_t() const {
return ((toUType(wordwidth) & 3) << 0) | ((mono & 1) << 2) | ((stop & 1) << 3) | ((reset & 1) << 4) | ((ws_sel & 1) << 5) | ((ws_halfperiod & 0x1ff) << 6) | ((mute & 1) << 15);
}
};
struct DAI {
WordWidth wordwidth;
uint32_t mono;
uint32_t stop;
uint32_t reset;
uint32_t ws_sel;
uint32_t ws_halfperiod;
WordWidth wordwidth;
uint32_t mono;
uint32_t stop;
uint32_t reset;
uint32_t ws_sel;
uint32_t ws_halfperiod;
constexpr operator uint32_t() const {
return
((toUType(wordwidth) & 3) << 0)
| ((mono & 1) << 2)
| ((stop & 1) << 3)
| ((reset & 1) << 4)
| ((ws_sel & 1) << 5)
| ((ws_halfperiod & 0x1ff) << 6)
;
}
constexpr operator uint32_t() const {
return ((toUType(wordwidth) & 3) << 0) | ((mono & 1) << 2) | ((stop & 1) << 3) | ((reset & 1) << 4) | ((ws_sel & 1) << 5) | ((ws_halfperiod & 0x1ff) << 6);
}
};
struct MCLKRate {
uint32_t x_divider;
uint32_t y_divider;
uint32_t x_divider;
uint32_t y_divider;
constexpr operator uint32_t() const {
return
((y_divider & 0xff) << 0)
| ((x_divider & 0xff) << 8)
;
}
constexpr operator uint32_t() const {
return ((y_divider & 0xff) << 0) | ((x_divider & 0xff) << 8);
}
};
struct BitRate {
uint32_t bitrate;
uint32_t bitrate;
constexpr operator uint32_t() const {
return ((bitrate & 0x3f) << 0);
}
constexpr operator uint32_t() const {
return ((bitrate & 0x3f) << 0);
}
};
struct Mode {
ClockSelect clksel;
uint32_t four_pin;
uint32_t mclk_out_en;
ClockSelect clksel;
uint32_t four_pin;
uint32_t mclk_out_en;
constexpr operator uint32_t() const {
return
((toUType(clksel) & 3) << 0)
| ((four_pin & 1) << 2)
| ((mclk_out_en & 1) << 3)
;
}
constexpr operator uint32_t() const {
return ((toUType(clksel) & 3) << 0) | ((four_pin & 1) << 2) | ((mclk_out_en & 1) << 3);
}
};
struct DMA {
uint32_t rx_enable;
uint32_t tx_enable;
size_t rx_depth;
size_t tx_depth;
uint32_t rx_enable;
uint32_t tx_enable;
size_t rx_depth;
size_t tx_depth;
constexpr operator uint32_t() const {
return
((rx_enable & 1) << 0)
| ((tx_enable & 1) << 1)
| ((rx_depth & 0xf) << 8)
| ((tx_depth & 0xf) << 16)
;
}
constexpr operator uint32_t() const {
return ((rx_enable & 1) << 0) | ((tx_enable & 1) << 1) | ((rx_depth & 0xf) << 8) | ((tx_depth & 0xf) << 16);
}
};
struct ConfigTX {
uint32_t dao;
uint32_t txrate;
uint32_t txbitrate;
uint32_t txmode;
uint32_t sck_in_sel;
uint32_t dao;
uint32_t txrate;
uint32_t txbitrate;
uint32_t txmode;
uint32_t sck_in_sel;
};
struct ConfigRX {
uint32_t dai;
uint32_t rxrate;
uint32_t rxbitrate;
uint32_t rxmode;
uint32_t sck_in_sel;
uint32_t dai;
uint32_t rxrate;
uint32_t rxbitrate;
uint32_t rxmode;
uint32_t sck_in_sel;
};
struct ConfigDMA {
uint32_t dma1;
uint32_t dma2;
uint32_t dma1;
uint32_t dma2;
};
static const audio_clock_resources_t audio_clock_resources = {
.base = { .clk = &LPC_CGU->BASE_AUDIO_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = 0 },
.branch = { .cfg = &LPC_CCU2->CLK_AUDIO_CFG, .stat = &LPC_CCU2->CLK_AUDIO_STAT },
.base = {.clk = &LPC_CGU->BASE_AUDIO_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = 0},
.branch = {.cfg = &LPC_CCU2->CLK_AUDIO_CFG, .stat = &LPC_CCU2->CLK_AUDIO_STAT},
};
static const i2s_resources_t i2s_resources = {
.base = { .clk = &LPC_CGU->BASE_APB1_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 1) },
.branch = { .cfg = &LPC_CCU1->CLK_APB1_I2S_CFG, .stat = &LPC_CCU1->CLK_APB1_I2S_STAT },
.reset = { { .output_index = 52 }, { .output_index = 53 } },
.base = {.clk = &LPC_CGU->BASE_APB1_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 1)},
.branch = {.cfg = &LPC_CCU1->CLK_APB1_I2S_CFG, .stat = &LPC_CCU1->CLK_APB1_I2S_STAT},
.reset = {{.output_index = 52}, {.output_index = 53}},
};
template<uint32_t BaseAddress>
template <uint32_t BaseAddress>
class I2S {
public:
static void configure(
const ConfigTX& config_tx,
const ConfigRX& config_rx
) {
base_clock_enable(&i2s_resources.base);
branch_clock_enable(&i2s_resources.branch);
public:
static void configure(
const ConfigTX& config_tx,
const ConfigRX& config_rx) {
base_clock_enable(&i2s_resources.base);
branch_clock_enable(&i2s_resources.branch);
base_clock_enable(&audio_clock_resources.base);
branch_clock_enable(&audio_clock_resources.branch);
base_clock_enable(&audio_clock_resources.base);
branch_clock_enable(&audio_clock_resources.branch);
if( &p() == LPC_I2S0 ) {
peripheral_reset(&i2s_resources.reset[0]);
}
if( &p() == LPC_I2S1 ) {
peripheral_reset(&i2s_resources.reset[1]);
}
if (&p() == LPC_I2S0) {
peripheral_reset(&i2s_resources.reset[0]);
}
if (&p() == LPC_I2S1) {
peripheral_reset(&i2s_resources.reset[1]);
}
reset();
reset();
if( &p() == LPC_I2S0 ) {
LPC_CREG->CREG6.I2S0_TX_SCK_IN_SEL = config_tx.sck_in_sel;
LPC_CREG->CREG6.I2S0_RX_SCK_IN_SEL = config_rx.sck_in_sel;
}
if( &p() == LPC_I2S1 ) {
LPC_CREG->CREG6.I2S1_TX_SCK_IN_SEL = config_tx.sck_in_sel;
LPC_CREG->CREG6.I2S1_RX_SCK_IN_SEL = config_rx.sck_in_sel;
}
if (&p() == LPC_I2S0) {
LPC_CREG->CREG6.I2S0_TX_SCK_IN_SEL = config_tx.sck_in_sel;
LPC_CREG->CREG6.I2S0_RX_SCK_IN_SEL = config_rx.sck_in_sel;
}
if (&p() == LPC_I2S1) {
LPC_CREG->CREG6.I2S1_TX_SCK_IN_SEL = config_tx.sck_in_sel;
LPC_CREG->CREG6.I2S1_RX_SCK_IN_SEL = config_rx.sck_in_sel;
}
p().DAO = config_tx.dao;
p().TXRATE = config_tx.txrate;
p().TXBITRATE = config_tx.txbitrate;
p().TXMODE = config_tx.txmode;
p().DAO = config_tx.dao;
p().TXRATE = config_tx.txrate;
p().TXBITRATE = config_tx.txbitrate;
p().TXMODE = config_tx.txmode;
p().DAI = config_rx.dai;
p().RXRATE = config_rx.rxrate;
p().RXBITRATE = config_rx.rxbitrate;
p().RXMODE = config_rx.rxmode;
}
p().DAI = config_rx.dai;
p().RXRATE = config_rx.rxrate;
p().RXBITRATE = config_rx.rxbitrate;
p().RXMODE = config_rx.rxmode;
}
static void configure(
const ConfigTX& config_tx,
const ConfigRX& config_rx,
const ConfigDMA& config_dma
) {
configure(config_tx, config_rx);
static void configure(
const ConfigTX& config_tx,
const ConfigRX& config_rx,
const ConfigDMA& config_dma) {
configure(config_tx, config_rx);
p().DMA1 = config_dma.dma1;
p().DMA2 = config_dma.dma2;
}
p().DMA1 = config_dma.dma1;
p().DMA2 = config_dma.dma2;
}
static void shutdown() {
if( &p() == LPC_I2S0 ) {
peripheral_reset(&i2s_resources.reset[0]);
}
if( &p() == LPC_I2S1 ) {
peripheral_reset(&i2s_resources.reset[1]);
}
static void shutdown() {
if (&p() == LPC_I2S0) {
peripheral_reset(&i2s_resources.reset[0]);
}
if (&p() == LPC_I2S1) {
peripheral_reset(&i2s_resources.reset[1]);
}
branch_clock_disable(&audio_clock_resources.branch);
base_clock_disable(&audio_clock_resources.base);
branch_clock_disable(&audio_clock_resources.branch);
base_clock_disable(&audio_clock_resources.base);
branch_clock_disable(&i2s_resources.branch);
base_clock_disable(&i2s_resources.base);
}
branch_clock_disable(&i2s_resources.branch);
base_clock_disable(&i2s_resources.base);
}
static void rx_start() {
p().DAI &= ~(1U << 3);
}
static void rx_start() {
p().DAI &= ~(1U << 3);
}
static void rx_stop() {
p().DAI |= (1U << 3);
}
static void rx_stop() {
p().DAI |= (1U << 3);
}
static void tx_start() {
p().DAO &= ~(1U << 3);
}
static void tx_start() {
p().DAO &= ~(1U << 3);
}
static void tx_stop() {
p().DAO |= (1U << 3);
}
static void tx_stop() {
p().DAO |= (1U << 3);
}
static void tx_mute() {
p().DAO |= (1U << 15);
}
static void tx_mute() {
p().DAO |= (1U << 15);
}
static void tx_unmute() {
p().DAO &= ~(1U << 15);
}
static void tx_unmute() {
p().DAO &= ~(1U << 15);
}
private:
static void reset() {
p().DAO |= (1U << 4);
p().DAI |= (1U << 4);
}
private:
static void reset() {
p().DAO |= (1U << 4);
p().DAI |= (1U << 4);
}
static LPC_I2S_Type& p() {
return *reinterpret_cast<LPC_I2S_Type*>(BaseAddress);
}
static LPC_I2S_Type& p() {
return *reinterpret_cast<LPC_I2S_Type*>(BaseAddress);
}
};
using i2s0 = I2S<LPC_I2S0_BASE>;
@@ -274,4 +245,4 @@ using i2s1 = I2S<LPC_I2S1_BASE>;
} /* namespace i2s */
} /* namespace lpc43xx */
#endif/*__I2S_H__*/
#endif /*__I2S_H__*/

View File

@@ -29,17 +29,17 @@
namespace jammer {
typedef struct jammer_range {
bool enabled;
int64_t min;
int64_t max;
bool enabled;
int64_t min;
int64_t max;
} jammer_range_t;
enum JammerType : uint32_t {
TYPE_FSK = 0,
TYPE_TONE = 1,
TYPE_SWEEP = 2
TYPE_FSK = 0,
TYPE_TONE = 1,
TYPE_SWEEP = 2
};
} /* namespace jammer */
#endif/*__JAMMER_H__*/
#endif /*__JAMMER_H__*/

View File

@@ -27,15 +27,14 @@
namespace jtag {
uint32_t JTAG::shift(const size_t count, uint32_t value) {
for(size_t i=0; i<count; i++) {
const auto tdo = target.clock(
(i == (count - 1)) ? 1 : 0,
value & 1
);
value >>= 1;
value |= tdo << (count - 1);
}
return value;
for (size_t i = 0; i < count; i++) {
const auto tdo = target.clock(
(i == (count - 1)) ? 1 : 0,
value & 1);
value >>= 1;
value |= tdo << (count - 1);
}
return value;
}
} /* namespace jtag */

View File

@@ -32,70 +32,69 @@
namespace jtag {
class JTAG {
public:
constexpr JTAG(
Target& target
) : target(target)
{
}
public:
constexpr JTAG(
Target& target)
: target(target) {
}
void reset() {
/* ??? -> Test-Logic-Reset */
for(size_t i=0; i<8; i++) {
target.clock(1, 0);
}
}
void reset() {
/* ??? -> Test-Logic-Reset */
for (size_t i = 0; i < 8; i++) {
target.clock(1, 0);
}
}
void run_test_idle() {
/* Test-Logic-Reset -> Run-Test/Idle */
target.clock(0, 0);
}
void run_test_idle() {
/* Test-Logic-Reset -> Run-Test/Idle */
target.clock(0, 0);
}
void runtest_tck(const size_t count) {
target.delay(count);
}
void runtest_tck(const size_t count) {
target.delay(count);
}
uint32_t shift_ir(const size_t count, const uint32_t value) {
/* Run-Test/Idle -> Select-DR-Scan -> Select-IR-Scan */
target.clock(1, 0);
target.clock(1, 0);
/* Scan -> Capture -> Shift */
target.clock(0, 0);
target.clock(0, 0);
uint32_t shift_ir(const size_t count, const uint32_t value) {
/* Run-Test/Idle -> Select-DR-Scan -> Select-IR-Scan */
target.clock(1, 0);
target.clock(1, 0);
/* Scan -> Capture -> Shift */
target.clock(0, 0);
target.clock(0, 0);
const auto result = shift(count, value);
const auto result = shift(count, value);
/* Exit1 -> Update */
target.clock(1, 0);
/* Update -> Run-Test/Idle */
target.clock(0, 0);
/* Exit1 -> Update */
target.clock(1, 0);
/* Update -> Run-Test/Idle */
target.clock(0, 0);
return result;
}
return result;
}
uint32_t shift_dr(const size_t count, const uint32_t value) {
/* Run-Test/Idle -> Select-DR-Scan */
target.clock(1, 0);
/* Scan -> Capture -> Shift */
target.clock(0, 0);
target.clock(0, 0);
uint32_t shift_dr(const size_t count, const uint32_t value) {
/* Run-Test/Idle -> Select-DR-Scan */
target.clock(1, 0);
/* Scan -> Capture -> Shift */
target.clock(0, 0);
target.clock(0, 0);
const auto result = shift(count, value);
const auto result = shift(count, value);
/* Exit1 -> Update */
target.clock(1, 0);
/* Update -> Run-Test/Idle */
target.clock(0, 0);
/* Exit1 -> Update */
target.clock(1, 0);
/* Update -> Run-Test/Idle */
target.clock(0, 0);
return result;
}
return result;
}
private:
Target& target;
private:
Target& target;
uint32_t shift(const size_t count, uint32_t value);
uint32_t shift(const size_t count, uint32_t value);
};
} /* namespace jtag */
#endif/*__JTAG_H__*/
#endif /*__JTAG_H__*/

View File

@@ -29,44 +29,44 @@ namespace jtag {
namespace tap {
size_t bits_t::length() const {
return count;
return count;
}
bits_t::operator bool() const {
return (count > 0);
return (count > 0);
}
bool bits_t::operator[](const size_t index) const {
if( p && (index < count) ) {
const auto n = bytes() * 8 - index - 1;
const auto byte = n >> 3;
const auto bit = (n ^ 7) & 7;
return (p[byte] >> bit) & 1;
} else {
return default_value;
}
if (p && (index < count)) {
const auto n = bytes() * 8 - index - 1;
const auto byte = n >> 3;
const auto bit = (n ^ 7) & 7;
return (p[byte] >> bit) & 1;
} else {
return default_value;
}
}
size_t bits_t::bytes() const {
return (count + 7) >> 3;
return (count + 7) >> 3;
}
#if JTAG_TAP_DEBUG
static char nibble_to_hex_char(const uint8_t v) {
if( v < 0xa ) {
return 0x30 + v;
} else {
return 0x57 + v;
}
if (v < 0xa) {
return 0x30 + v;
} else {
return 0x57 + v;
}
}
std::string to_string(const bits_t& bits) {
std::string s { std::to_string(bits.length()) + "/0x" };
for(size_t i=0; i<bytes(); i++) {
s += nibble_to_hex_char((bits.p[i] >> 4) & 0xf);
s += nibble_to_hex_char((bits.p[i] >> 0) & 0xf);
}
return s;
std::string s{std::to_string(bits.length()) + "/0x"};
for (size_t i = 0; i < bytes(); i++) {
s += nibble_to_hex_char((bits.p[i] >> 4) & 0xf);
s += nibble_to_hex_char((bits.p[i] >> 0) & 0xf);
}
return s;
}
#endif
@@ -75,191 +75,191 @@ namespace {
using route_t = uint16_t;
struct entry_t {
state_t tms[2];
route_t route;
state_t tms[2];
route_t route;
};
static_assert(sizeof(entry_t) == 4, "Unexpected size of entry_t");
using table_t = std::array<entry_t, 16>;
static_assert(sizeof(table_t) == (16 * 4), "Unexpected size of table_t");
const table_t table { {
{ state_t::run_test_idle, state_t::test_logic_reset, 0b0000000000000001 }, // test_logic_reset test_logic_reset => 1, others => 0
{ state_t::run_test_idle, state_t::select_dr_scan, 0b1111111111111101 }, // run_test_idle run_test_idle => 0, others => 1
{ state_t::capture_dr, state_t::select_ir_scan, 0b1111111000000001 }, // select_dr_scan run_test_idle..update_dr => 0, others => 1
{ state_t::shift_dr, state_t::exit1_dr, 0b1111111111101111 }, // capture_dr shift_dr => 0, others => 1
{ state_t::shift_dr, state_t::exit1_dr, 0b1111111111101111 }, // shift_dr shift_dr => 0, others => 1
{ state_t::pause_dr, state_t::update_dr, 0b1111111100111111 }, // exit1_dr pause_dr, exit2_dr => 0, others => 1
{ state_t::pause_dr, state_t::exit2_dr, 0b1111111110111111 }, // pause_dr pause_dr => 0, others => 1
{ state_t::shift_dr, state_t::update_dr, 0b1111111111101111 }, // exit2_dr shift_dr => 0, others => 1
{ state_t::run_test_idle, state_t::select_dr_scan, 0b1111111111111101 }, // update_dr run_test_idle => 0, others => 1
{ state_t::capture_ir, state_t::test_logic_reset, 0b0000000000000001 }, // select_ir_scan test_logic_reset => 1, others => 0
{ state_t::shift_ir, state_t::exit1_ir, 0b1111011111111111 }, // capture_ir shift_ir => 0, others => 1
{ state_t::shift_ir, state_t::exit1_ir, 0b1111011111111111 }, // shift_ir shift_ir => 0, others => 1
{ state_t::pause_ir, state_t::update_ir, 0b1001111111111111 }, // exit1_ir pause_ir, exit2_ir => 0, others => 1
{ state_t::pause_ir, state_t::exit2_ir, 0b1101111111111111 }, // pause_ir pause_ir => 0, others => 1
{ state_t::shift_ir, state_t::update_ir, 0b1111011111111111 }, // exit2_ir shift_ir => 0, others => 1
{ state_t::run_test_idle, state_t::select_dr_scan, 0b1111111111111101 }, // update_ir run_test_idle => 0, others => 1
} };
const table_t table{{
{state_t::run_test_idle, state_t::test_logic_reset, 0b0000000000000001}, // test_logic_reset test_logic_reset => 1, others => 0
{state_t::run_test_idle, state_t::select_dr_scan, 0b1111111111111101}, // run_test_idle run_test_idle => 0, others => 1
{state_t::capture_dr, state_t::select_ir_scan, 0b1111111000000001}, // select_dr_scan run_test_idle..update_dr => 0, others => 1
{state_t::shift_dr, state_t::exit1_dr, 0b1111111111101111}, // capture_dr shift_dr => 0, others => 1
{state_t::shift_dr, state_t::exit1_dr, 0b1111111111101111}, // shift_dr shift_dr => 0, others => 1
{state_t::pause_dr, state_t::update_dr, 0b1111111100111111}, // exit1_dr pause_dr, exit2_dr => 0, others => 1
{state_t::pause_dr, state_t::exit2_dr, 0b1111111110111111}, // pause_dr pause_dr => 0, others => 1
{state_t::shift_dr, state_t::update_dr, 0b1111111111101111}, // exit2_dr shift_dr => 0, others => 1
{state_t::run_test_idle, state_t::select_dr_scan, 0b1111111111111101}, // update_dr run_test_idle => 0, others => 1
{state_t::capture_ir, state_t::test_logic_reset, 0b0000000000000001}, // select_ir_scan test_logic_reset => 1, others => 0
{state_t::shift_ir, state_t::exit1_ir, 0b1111011111111111}, // capture_ir shift_ir => 0, others => 1
{state_t::shift_ir, state_t::exit1_ir, 0b1111011111111111}, // shift_ir shift_ir => 0, others => 1
{state_t::pause_ir, state_t::update_ir, 0b1001111111111111}, // exit1_ir pause_ir, exit2_ir => 0, others => 1
{state_t::pause_ir, state_t::exit2_ir, 0b1101111111111111}, // pause_ir pause_ir => 0, others => 1
{state_t::shift_ir, state_t::update_ir, 0b1111011111111111}, // exit2_ir shift_ir => 0, others => 1
{state_t::run_test_idle, state_t::select_dr_scan, 0b1111111111111101}, // update_ir run_test_idle => 0, others => 1
}};
const std::array<const char*, 16> state_name { {
"test_logic_reset",
"run_test_idle",
"select_dr_scan",
"capture_dr",
"shift_dr",
"exit1_dr",
"pause_dr",
"exit2_dr",
"update_dr",
"select_ir_scan",
"capture_ir",
"shift_ir",
"exit1_ir",
"pause_ir",
"exit2_ir",
"update_ir",
} };
const std::array<const char*, 16> state_name{{
"test_logic_reset",
"run_test_idle",
"select_dr_scan",
"capture_dr",
"shift_dr",
"exit1_dr",
"pause_dr",
"exit2_dr",
"update_dr",
"select_ir_scan",
"capture_ir",
"shift_ir",
"exit1_ir",
"pause_ir",
"exit2_ir",
"update_ir",
}};
const std::array<const char*, 16> state_long_name { {
"Test-Logic-Reset",
"Run-Test/Idle",
"Select-DR-Scan",
"Capture-DR",
"Shift-DR",
"Exit1-DR",
"Pause-DR",
"Exit2-DR",
"Update-DR",
"Select-IR-Scan",
"Capture-IR",
"Shift-IR",
"Exit1-IR",
"Pause-IR",
"Exit2-IR",
"Update-IR",
} };
const std::array<const char*, 16> state_long_name{{
"Test-Logic-Reset",
"Run-Test/Idle",
"Select-DR-Scan",
"Capture-DR",
"Shift-DR",
"Exit1-DR",
"Pause-DR",
"Exit2-DR",
"Update-DR",
"Select-IR-Scan",
"Capture-IR",
"Shift-IR",
"Exit1-IR",
"Pause-IR",
"Exit2-IR",
"Update-IR",
}};
const entry_t& entry(const state_t state) {
return table[toUType(state)];
return table[toUType(state)];
}
} /* namespace */
const char* c_str(const state_t state) {
return state_name[toUType(state)];
return state_name[toUType(state)];
}
/* TAPState **************************************************************/
state_t TAPState::state() const {
return _state;
return _state;
}
void TAPState::advance(const bool tms) {
_state = entry(_state).tms[tms];
_state = entry(_state).tms[tms];
}
bool TAPState::advance_toward(const state_t desired_state) const {
return (entry(_state).route >> toUType(desired_state)) & 1;
return (entry(_state).route >> toUType(desired_state)) & 1;
}
/* TAPMachine ************************************************************/
void TAPMachine::set_run_test(const uint32_t value) {
_run_test = value;
_run_test = value;
}
void TAPMachine::set_repeat(const uint8_t value) {
_repeat = value;
_repeat = value;
}
void TAPMachine::set_end_ir(const state_t state) {
_end_ir = state;
_end_ir = state;
}
void TAPMachine::set_end_dr(const state_t state) {
_end_dr = state;
_end_dr = state;
}
bool TAPMachine::shift_ir(const bits_t& tdi_value, const bits_t& tdo_expected, const bits_t& tdo_mask) {
return shift_data(tdi_value, tdo_expected, tdo_mask, state_t::shift_ir, _end_ir, _run_test);
return shift_data(tdi_value, tdo_expected, tdo_mask, state_t::shift_ir, _end_ir, _run_test);
}
bool TAPMachine::shift_dr(const bits_t& tdi_value, const bits_t& tdo_expected, const bits_t& tdo_mask) {
return shift_data(tdi_value, tdo_expected, tdo_mask, state_t::shift_dr, _end_dr, _run_test);
return shift_data(tdi_value, tdo_expected, tdo_mask, state_t::shift_dr, _end_dr, _run_test);
}
void TAPMachine::state(const state_t state) {
if( state == state_t::test_logic_reset ) {
for(int i=0; i<5; i++) {
clock(1);
}
} else {
advance_to_state(state);
}
if (state == state_t::test_logic_reset) {
for (int i = 0; i < 5; i++) {
clock(1);
}
} else {
advance_to_state(state);
}
}
void TAPMachine::wait(const state_t wait_state, const state_t end_state, const uint32_t wait_time) {
advance_to_state(wait_state);
delay_us(wait_time);
advance_to_state(end_state);
advance_to_state(wait_state);
delay_us(wait_time);
advance_to_state(end_state);
}
bool TAPMachine::clock(const bool tms, const bool tdi) {
tap.advance(tms);
return target.clock(tms, tdi);
tap.advance(tms);
return target.clock(tms, tdi);
}
void TAPMachine::advance_to_state(const state_t desired_state) {
while( tap.state() != desired_state ) {
const auto tms = tap.advance_toward(desired_state);
clock(tms);
}
while (tap.state() != desired_state) {
const auto tms = tap.advance_toward(desired_state);
clock(tms);
}
}
void TAPMachine::delay_us(const uint32_t microseconds) {
target.delay(microseconds);
target.delay(microseconds);
}
void TAPMachine::shift_start(const state_t state) {
advance_to_state(state);
advance_to_state(state);
}
bool TAPMachine::shift(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const bool end_tms) {
if( tdo_expected.length() != tdo_mask.length() ) {
return false;
}
if( tdo_expected && (tdi.length() != tdo_expected.length()) ) {
return false;
}
if (tdo_expected.length() != tdo_mask.length()) {
return false;
}
if (tdo_expected && (tdi.length() != tdo_expected.length())) {
return false;
}
auto tdo_error = false;
for(uint32_t i=0; i<tdi.length(); i++) {
const auto tms = end_tms & (i == (tdi.length() - 1));
const auto tdo = clock(tms, tdi[i]);
if( tdo_expected && tdo_mask ) {
tdo_error |= (tdo & tdo_mask[i]) != (tdo_expected[i] & tdo_mask[i]);
}
}
auto tdo_error = false;
for (uint32_t i = 0; i < tdi.length(); i++) {
const auto tms = end_tms & (i == (tdi.length() - 1));
const auto tdo = clock(tms, tdi[i]);
if (tdo_expected && tdo_mask) {
tdo_error |= (tdo & tdo_mask[i]) != (tdo_expected[i] & tdo_mask[i]);
}
}
return tdo_error;
return tdo_error;
}
void TAPMachine::shift_end(const state_t end_state, const uint32_t end_delay) {
if( end_delay ) {
advance_to_state(state_t::run_test_idle);
delay_us(end_delay);
} else {
advance_to_state(end_state);
}
if (end_delay) {
advance_to_state(state_t::run_test_idle);
delay_us(end_delay);
} else {
advance_to_state(end_state);
}
}
bool TAPMachine::shift_data(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const state_t state, const state_t end_state, const uint32_t end_delay) {
shift_start(state);
const auto result = shift(tdi, tdo_expected, tdo_mask, true);
shift_end(end_state, end_delay);
return result;
shift_start(state);
const auto result = shift(tdi, tdo_expected, tdo_mask, true);
shift_end(end_state, end_delay);
return result;
}
} /* namespace tap */

View File

@@ -31,125 +31,120 @@ namespace jtag {
namespace tap {
class bits_t {
public:
constexpr bits_t(
) : p { nullptr },
count { 0 }
{
}
public:
constexpr bits_t()
: p{nullptr},
count{0} {
}
constexpr bits_t(
const size_t count,
const bool default_value = true
) : p { nullptr },
count { count },
default_value { default_value }
{
}
constexpr bits_t(
const size_t count,
const bool default_value = true)
: p{nullptr},
count{count},
default_value{default_value} {
}
constexpr bits_t(
const uint8_t* const p,
const size_t count
) : p { p },
count { count }
{
}
constexpr bits_t(
const uint8_t* const p,
const size_t count)
: p{p},
count{count} {
}
size_t length() const;
size_t length() const;
explicit operator bool() const;
explicit operator bool() const;
bool operator[](const size_t index) const;
bool operator[](const size_t index) const;
private:
const uint8_t* p { nullptr };
size_t count { 0 };
bool default_value { false };
private:
const uint8_t* p{nullptr};
size_t count{0};
bool default_value{false};
size_t bytes() const;
size_t bytes() const;
};
enum class state_t : uint8_t {
/* Ordinal values are important for "routes" values, and to match XSVF definitions. */
test_logic_reset = 0,
run_test_idle = 1,
select_dr_scan = 2,
capture_dr = 3,
shift_dr = 4,
exit1_dr = 5,
pause_dr = 6,
exit2_dr = 7,
update_dr = 8,
select_ir_scan = 9,
capture_ir = 10,
shift_ir = 11,
exit1_ir = 12,
pause_ir = 13,
exit2_ir = 14,
update_ir = 15,
/* Ordinal values are important for "routes" values, and to match XSVF definitions. */
test_logic_reset = 0,
run_test_idle = 1,
select_dr_scan = 2,
capture_dr = 3,
shift_dr = 4,
exit1_dr = 5,
pause_dr = 6,
exit2_dr = 7,
update_dr = 8,
select_ir_scan = 9,
capture_ir = 10,
shift_ir = 11,
exit1_ir = 12,
pause_ir = 13,
exit2_ir = 14,
update_ir = 15,
};
class TAPState {
public:
constexpr TAPState(
) : _state { state_t::test_logic_reset }
{
}
public:
constexpr TAPState()
: _state{state_t::test_logic_reset} {
}
state_t state() const;
void advance(const bool tms);
bool advance_toward(const state_t desired_state) const;
state_t state() const;
void advance(const bool tms);
bool advance_toward(const state_t desired_state) const;
private:
state_t _state;
private:
state_t _state;
};
class TAPMachine {
public:
constexpr TAPMachine(
jtag::Target& target
) : target { target }
{
}
public:
constexpr TAPMachine(
jtag::Target& target)
: target{target} {
}
void set_run_test(const uint32_t value);
void set_repeat(const uint8_t value);
void set_end_ir(const state_t state);
void set_end_dr(const state_t state);
void set_run_test(const uint32_t value);
void set_repeat(const uint8_t value);
void set_end_ir(const state_t state);
void set_end_dr(const state_t state);
bool shift(const bits_t& tdi, const bool end_tms) {
return shift(tdi, {}, {}, end_tms);
}
bool shift(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const bool end_tms);
bool shift(const bits_t& tdi, const bool end_tms) {
return shift(tdi, {}, {}, end_tms);
}
bool shift_ir(const bits_t& tdi_value, const bits_t& tdo_expected = {}, const bits_t& tdo_mask = {});
bool shift_dr(const bits_t& tdi_value, const bits_t& tdo_expected = {}, const bits_t& tdo_mask = {});
bool shift(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const bool end_tms);
void state(const state_t state);
void wait(const state_t wait_state, const state_t end_state, const uint32_t wait_time);
bool shift_ir(const bits_t& tdi_value, const bits_t& tdo_expected = {}, const bits_t& tdo_mask = {});
bool shift_dr(const bits_t& tdi_value, const bits_t& tdo_expected = {}, const bits_t& tdo_mask = {});
private:
jtag::Target& target;
TAPState tap { };
void state(const state_t state);
uint32_t _run_test { 0 };
uint8_t _repeat { 0 };
state_t _end_ir { };
state_t _end_dr { };
void wait(const state_t wait_state, const state_t end_state, const uint32_t wait_time);
bool clock(const bool tms, const bool tdi=false);
void advance_to_state(const state_t desired_state);
void delay_us(const uint32_t microseconds);
private:
jtag::Target& target;
TAPState tap{};
void shift_start(const state_t state);
void shift_end(const state_t end_state, const uint32_t end_delay);
uint32_t _run_test{0};
uint8_t _repeat{0};
state_t _end_ir{};
state_t _end_dr{};
bool shift_data(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const state_t state, const state_t end_state, const uint32_t end_delay);
bool clock(const bool tms, const bool tdi = false);
void advance_to_state(const state_t desired_state);
void delay_us(const uint32_t microseconds);
void shift_start(const state_t state);
void shift_end(const state_t end_state, const uint32_t end_delay);
bool shift_data(const bits_t& tdi, const bits_t& tdo_expected, const bits_t& tdo_mask, const state_t state, const state_t end_state, const uint32_t end_delay);
};
} /* namespace tap */
} /* namespace jtag */
#endif/*__JTAG_TAP_H__*/
#endif /*__JTAG_TAP_H__*/

View File

@@ -28,19 +28,18 @@
namespace jtag {
class Target {
public:
using bit_t = uint_fast8_t;
public:
using bit_t = uint_fast8_t;
virtual ~Target() {
}
virtual ~Target() {
}
virtual void delay(const size_t n) = 0;
virtual bit_t clock(
const bit_t tms_value,
const bit_t tdi_value
) = 0;
virtual void delay(const size_t n) = 0;
virtual bit_t clock(
const bit_t tms_value,
const bit_t tdi_value) = 0;
};
} /* namespace jtag */
#endif/*__JTAG_TARGET_H__*/
#endif /*__JTAG_TARGET_H__*/

View File

@@ -31,110 +31,108 @@
namespace jtag {
class GPIOTarget : public Target {
public:
// Tightly control how this object can be constructor or copied, since
// it initializes GPIOs in the constructor. I don't want it re-
// initializing a bunch as the object gets passed around. So don't let
// it get passed around...
/*
GPIOTarget() = delete;
GPIOTarget(const GPIOTarget&) = delete;
GPIOTarget(GPIOTarget&&) = delete;
GPIOTarget& operator=(const GPIOTarget&) = delete;
GPIOTarget& operator=(GPIOTarget&&) = delete;
*/
GPIOTarget(
GPIO gpio_tck,
GPIO gpio_tms,
GPIO gpio_tdi,
GPIO gpio_tdo
) : gpio_tck { gpio_tck },
gpio_tms { gpio_tms },
gpio_tdi { gpio_tdi },
gpio_tdo { gpio_tdo }
{
gpio_tdi.write(1);
gpio_tdi.output();
gpio_tdi.configure();
public:
// Tightly control how this object can be constructor or copied, since
// it initializes GPIOs in the constructor. I don't want it re-
// initializing a bunch as the object gets passed around. So don't let
// it get passed around...
/*
GPIOTarget() = delete;
GPIOTarget(const GPIOTarget&) = delete;
GPIOTarget(GPIOTarget&&) = delete;
GPIOTarget& operator=(const GPIOTarget&) = delete;
GPIOTarget& operator=(GPIOTarget&&) = delete;
*/
GPIOTarget(
GPIO gpio_tck,
GPIO gpio_tms,
GPIO gpio_tdi,
GPIO gpio_tdo)
: gpio_tck{gpio_tck},
gpio_tms{gpio_tms},
gpio_tdi{gpio_tdi},
gpio_tdo{gpio_tdo} {
gpio_tdi.write(1);
gpio_tdi.output();
gpio_tdi.configure();
gpio_tms.write(1);
gpio_tms.output();
gpio_tms.configure();
gpio_tms.write(1);
gpio_tms.output();
gpio_tms.configure();
gpio_tck.write(0);
gpio_tck.output();
gpio_tck.configure();
gpio_tck.write(0);
gpio_tck.output();
gpio_tck.configure();
gpio_tdo.input();
gpio_tdo.configure();
}
gpio_tdo.input();
gpio_tdo.configure();
}
~GPIOTarget() {
gpio_tdi.input();
gpio_tms.input();
gpio_tck.input();
}
~GPIOTarget() {
gpio_tdi.input();
gpio_tms.input();
gpio_tck.input();
}
void delay(const size_t clocks) override {
/* TODO: Use more precise timing mechanism, using the frequency
* specified by SVF file.
*/
void delay(const size_t clocks) override {
/* TODO: Use more precise timing mechanism, using the frequency
* specified by SVF file.
*/
halPolledDelay(clocks * systicks_per_tck);
}
}
Target::bit_t clock(
const Target::bit_t tms_value,
const Target::bit_t tdi_value
) override {
/* TODO: Use more precise timing mechanism, using the frequency
* specified by SVF file.
*/
const auto result = tdo();
tms(tms_value);
tdi(tdi_value);
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
tck(1);
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
tck(0);
return result;
}
Target::bit_t clock(
const Target::bit_t tms_value,
const Target::bit_t tdi_value) override {
/* TODO: Use more precise timing mechanism, using the frequency
* specified by SVF file.
*/
const auto result = tdo();
tms(tms_value);
tdi(tdi_value);
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
tck(1);
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
tck(0);
return result;
}
private:
/* At 200MHz, one 18MHz cycle is 11 systicks. */
static constexpr size_t systicks_per_tck = 11;
private:
/* At 200MHz, one 18MHz cycle is 11 systicks. */
static constexpr size_t systicks_per_tck = 11;
GPIO gpio_tck;
GPIO gpio_tms;
GPIO gpio_tdi;
GPIO gpio_tdo;
GPIO gpio_tck;
GPIO gpio_tms;
GPIO gpio_tdi;
GPIO gpio_tdo;
void tck(const Target::bit_t value) {
gpio_tck.write(value);
}
void tck(const Target::bit_t value) {
gpio_tck.write(value);
}
void tdi(const Target::bit_t value) {
gpio_tdi.write(value);
}
void tdi(const Target::bit_t value) {
gpio_tdi.write(value);
}
void tms(const bit_t value) {
gpio_tms.write(value);
}
void tms(const bit_t value) {
gpio_tms.write(value);
}
Target::bit_t tdo() {
return gpio_tdo.read();
}
Target::bit_t tdo() {
return gpio_tdo.read();
}
};
} /* namespace jtag */
#endif/*__JTAG_TARGET_GPIO_H__*/
#endif /*__JTAG_TARGET_GPIO_H__*/

File diff suppressed because it is too large Load Diff

View File

@@ -32,93 +32,87 @@
namespace lcd {
class ILI9341 {
public:
constexpr ILI9341(
) : scroll_state { 0, 0, height(), 0 }
{
}
public:
constexpr ILI9341()
: scroll_state{0, 0, height(), 0} {
}
ILI9341(const ILI9341&) = delete;
ILI9341(ILI9341&&) = delete;
void operator=(const ILI9341&) = delete;
ILI9341(const ILI9341&) = delete;
ILI9341(ILI9341&&) = delete;
void operator=(const ILI9341&) = delete;
void init();
void shutdown();
void init();
void shutdown();
void sleep();
void wake();
void sleep();
void wake();
void fill_rectangle(ui::Rect r, const ui::Color c);
void fill_rectangle_unrolled8(ui::Rect r, const ui::Color c);
void draw_line(const ui::Point start, const ui::Point end, const ui::Color color);
void fill_circle(
const ui::Point center,
const ui::Dim radius,
const ui::Color foreground,
const ui::Color background
);
void fill_rectangle(ui::Rect r, const ui::Color c);
void fill_rectangle_unrolled8(ui::Rect r, const ui::Color c);
void draw_line(const ui::Point start, const ui::Point end, const ui::Color color);
void fill_circle(
const ui::Point center,
const ui::Dim radius,
const ui::Color foreground,
const ui::Color background);
void draw_pixel(const ui::Point p, const ui::Color color);
void drawBMP(const ui::Point p, const uint8_t * bitmap, const bool transparency);
bool drawBMP2(const ui::Point p, const std::string file);
void render_line(const ui::Point p, const uint8_t count, const ui::Color* line_buffer);
void render_box(const ui::Point p, const ui::Size s, const ui::Color* line_buffer);
template<size_t N>
void draw_pixels(
const ui::Rect r,
const std::array<ui::Color, N>& colors
) {
draw_pixels(r, colors.data(), colors.size());
}
void draw_pixel(const ui::Point p, const ui::Color color);
void drawBMP(const ui::Point p, const uint8_t* bitmap, const bool transparency);
bool drawBMP2(const ui::Point p, const std::string file);
void render_line(const ui::Point p, const uint8_t count, const ui::Color* line_buffer);
void render_box(const ui::Point p, const ui::Size s, const ui::Color* line_buffer);
template<size_t N>
void read_pixels(
const ui::Rect r,
std::array<ui::ColorRGB888, N>& colors
) {
read_pixels(r, colors.data(), colors.size());
}
template <size_t N>
void draw_pixels(
const ui::Rect r,
const std::array<ui::Color, N>& colors) {
draw_pixels(r, colors.data(), colors.size());
}
void draw_bitmap(
const ui::Point p,
const ui::Size size,
const uint8_t* const data,
const ui::Color foreground,
const ui::Color background
);
template <size_t N>
void read_pixels(
const ui::Rect r,
std::array<ui::ColorRGB888, N>& colors) {
read_pixels(r, colors.data(), colors.size());
}
void draw_glyph(
const ui::Point p,
const ui::Glyph& glyph,
const ui::Color foreground,
const ui::Color background
);
void draw_bitmap(
const ui::Point p,
const ui::Size size,
const uint8_t* const data,
const ui::Color foreground,
const ui::Color background);
void scroll_set_area(const ui::Coord top_y, const ui::Coord bottom_y);
ui::Coord scroll_set_position(const ui::Coord position);
ui::Coord scroll(const int32_t delta);
ui::Coord scroll_area_y(const ui::Coord y) const;
void scroll_disable();
void draw_glyph(
const ui::Point p,
const ui::Glyph& glyph,
const ui::Color foreground,
const ui::Color background);
constexpr ui::Dim width() const { return 240; }
constexpr ui::Dim height() const { return 320; }
constexpr ui::Rect screen_rect() const { return { 0, 0, width(), height() }; }
void scroll_set_area(const ui::Coord top_y, const ui::Coord bottom_y);
ui::Coord scroll_set_position(const ui::Coord position);
ui::Coord scroll(const int32_t delta);
ui::Coord scroll_area_y(const ui::Coord y) const;
void scroll_disable();
private:
struct scroll_t {
ui::Coord top_area;
ui::Coord bottom_area;
ui::Dim height;
ui::Coord current_position;
};
scroll_t scroll_state;
constexpr ui::Dim width() const { return 240; }
constexpr ui::Dim height() const { return 320; }
constexpr ui::Rect screen_rect() const { return {0, 0, width(), height()}; }
void draw_pixels(const ui::Rect r, const ui::Color* const colors, const size_t count);
void read_pixels(const ui::Rect r, ui::ColorRGB888* const colors, const size_t count);
private:
struct scroll_t {
ui::Coord top_area;
ui::Coord bottom_area;
ui::Dim height;
ui::Coord current_position;
};
scroll_t scroll_state;
void draw_pixels(const ui::Rect r, const ui::Color* const colors, const size_t count);
void read_pixels(const ui::Rect r, ui::ColorRGB888* const colors, const size_t count);
};
} /* namespace lcd */
#endif/*__LCD_ILI9341_H__*/
#endif /*__LCD_ILI9341_H__*/

View File

@@ -25,34 +25,34 @@
#include "gpio.hpp"
struct LED {
constexpr LED(const GPIO gpio) :
_gpio { gpio } {
}
constexpr LED(const GPIO gpio)
: _gpio{gpio} {
}
void setup() const {
_gpio.clear();
_gpio.output();
_gpio.configure();
}
void setup() const {
_gpio.clear();
_gpio.output();
_gpio.configure();
}
void on() const {
_gpio.set();
}
void on() const {
_gpio.set();
}
void off() const {
_gpio.clear();
}
void off() const {
_gpio.clear();
}
void toggle() const {
_gpio.toggle();
}
void toggle() const {
_gpio.toggle();
}
void write(const bool value) const {
_gpio.write(value);
}
void write(const bool value) const {
_gpio.write(value);
}
private:
const GPIO _gpio;
private:
const GPIO _gpio;
};
#endif/*__LED_H__*/
#endif /*__LED_H__*/

View File

@@ -21,86 +21,67 @@
#include "lfsr_random.hpp"
static void lfsr_iterate_internal(lfsr_word_t& v)
{
/*
Generated with lfsr-generator:
http://lfsr-generator.sourceforge.net
=============================================
config : fibonacci
length : 31
taps : (31, 18)
shift-amounts : (12, 12, 8)
shift-direction : left
*/
enum {
length = 31,
tap_0 = 31,
tap_1 = 18,
shift_amount_0 = 12,
shift_amount_1 = 12,
shift_amount_2 = 8
};
static void lfsr_iterate_internal(lfsr_word_t& v) {
/*
Generated with lfsr-generator:
http://lfsr-generator.sourceforge.net
=============================================
config : fibonacci
length : 31
taps : (31, 18)
shift-amounts : (12, 12, 8)
shift-direction : left
*/
enum {
length = 31,
tap_0 = 31,
tap_1 = 18,
shift_amount_0 = 12,
shift_amount_1 = 12,
shift_amount_2 = 8
};
const lfsr_word_t zero = 0;
v = (
(
v << shift_amount_0
) | (
(
(v >> (tap_0 - shift_amount_0)) ^
(v >> (tap_1 - shift_amount_0))
) & (
~(~zero << shift_amount_0)
)
)
);
v = (
(
v << shift_amount_1
) | (
(
(v >> (tap_0 - shift_amount_1)) ^
(v >> (tap_1 - shift_amount_1))
) & (
~(~zero << shift_amount_1)
)
)
);
v = (
(
v << shift_amount_2
) | (
(
(v >> (tap_0 - shift_amount_2)) ^
(v >> (tap_1 - shift_amount_2))
) & (
~(~zero << shift_amount_2)
)
)
);
const lfsr_word_t zero = 0;
v = ((
v << shift_amount_0) |
((
(v >> (tap_0 - shift_amount_0)) ^
(v >> (tap_1 - shift_amount_0))) &
(~(~zero << shift_amount_0))));
v = ((
v << shift_amount_1) |
((
(v >> (tap_0 - shift_amount_1)) ^
(v >> (tap_1 - shift_amount_1))) &
(~(~zero << shift_amount_1))));
v = ((
v << shift_amount_2) |
((
(v >> (tap_0 - shift_amount_2)) ^
(v >> (tap_1 - shift_amount_2))) &
(~(~zero << shift_amount_2))));
}
lfsr_word_t lfsr_iterate(lfsr_word_t v) {
lfsr_iterate_internal(v);
return v;
lfsr_iterate_internal(v);
return v;
}
void lfsr_fill(lfsr_word_t& v, lfsr_word_t* buffer, size_t word_count) {
while( word_count != 0 ) {
lfsr_iterate_internal(v);
*(buffer++) = v;
word_count--;
}
while (word_count != 0) {
lfsr_iterate_internal(v);
*(buffer++) = v;
word_count--;
}
}
bool lfsr_compare(lfsr_word_t& v, const lfsr_word_t* buffer, size_t word_count) {
while( word_count != 0 ) {
lfsr_iterate_internal(v);
if( *(buffer++) != v ) {
return false;
}
word_count--;
}
return true;
while (word_count != 0) {
lfsr_iterate_internal(v);
if (*(buffer++) != v) {
return false;
}
word_count--;
}
return true;
}

View File

@@ -31,4 +31,4 @@ lfsr_word_t lfsr_iterate(lfsr_word_t v);
void lfsr_fill(lfsr_word_t& v, lfsr_word_t* buffer, size_t word_count);
bool lfsr_compare(lfsr_word_t& v, const lfsr_word_t* buffer, size_t word_count);
#endif/*__LFSR_RANDOM_HPP__*/
#endif /*__LFSR_RANDOM_HPP__*/

View File

@@ -34,12 +34,14 @@ namespace lpc43xx {
namespace m4 {
static inline bool flag_saturation() {
return __get_APSR() & (1U << 27);
return __get_APSR() & (1U << 27);
}
static inline void clear_flag_saturation() {
uint32_t flags = 1;
__asm volatile ("MSR APSR_nzcvqg, %0" : : "r" (flags));
uint32_t flags = 1;
__asm volatile("MSR APSR_nzcvqg, %0"
:
: "r"(flags));
}
} /* namespace m4 */
@@ -60,22 +62,22 @@ namespace m4txevent {
#if defined(LPC43XX_M0)
inline void enable() {
nvicEnableVector(M4CORE_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_M4TXEVENT_IRQ_PRIORITY));
nvicEnableVector(M4CORE_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_M4TXEVENT_IRQ_PRIORITY));
}
inline void disable() {
nvicDisableVector(M4CORE_IRQn);
nvicDisableVector(M4CORE_IRQn);
}
#endif
#if defined(LPC43XX_M4)
inline void assert_event() {
__SEV();
__SEV();
}
#endif
inline void clear() {
LPC_CREG->M4TXEVENT = 0;
LPC_CREG->M4TXEVENT = 0;
}
} /* namespace m4txevent */
@@ -84,157 +86,137 @@ namespace m0apptxevent {
#if defined(LPC43XX_M4)
inline void enable() {
nvicEnableVector(M0CORE_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_M0APPTXEVENT_IRQ_PRIORITY));
nvicEnableVector(M0CORE_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_M0APPTXEVENT_IRQ_PRIORITY));
}
inline void disable() {
nvicDisableVector(M0CORE_IRQn);
nvicDisableVector(M0CORE_IRQn);
}
#endif
#if defined(LPC43XX_M0)
inline void assert_event() {
__SEV();
__SEV();
}
#endif
inline void clear() {
LPC_CREG->M0APPTXEVENT = 0;
LPC_CREG->M0APPTXEVENT = 0;
}
} /* namespace */
} // namespace m0apptxevent
} /* namespace creg */
namespace cgu {
enum class CLK_SEL : uint8_t {
RTC_32KHZ = 0x00,
IRC = 0x01,
ENET_RX_CLK = 0x02,
ENET_TX_CLK = 0x03,
GP_CLKIN = 0x04,
XTAL = 0x06,
PLL0USB = 0x07,
PLL0AUDIO = 0x08,
PLL1 = 0x09,
IDIVA = 0x0c,
IDIVB = 0x0d,
IDIVC = 0x0e,
IDIVD = 0x0f,
IDIVE = 0x10,
RTC_32KHZ = 0x00,
IRC = 0x01,
ENET_RX_CLK = 0x02,
ENET_TX_CLK = 0x03,
GP_CLKIN = 0x04,
XTAL = 0x06,
PLL0USB = 0x07,
PLL0AUDIO = 0x08,
PLL1 = 0x09,
IDIVA = 0x0c,
IDIVB = 0x0d,
IDIVC = 0x0e,
IDIVD = 0x0f,
IDIVE = 0x10,
};
struct IDIV_CTRL {
uint32_t pd;
uint32_t idiv;
uint32_t autoblock;
CLK_SEL clk_sel;
uint32_t pd;
uint32_t idiv;
uint32_t autoblock;
CLK_SEL clk_sel;
constexpr operator uint32_t() const {
return
((pd & 1) << 0)
| ((idiv & 255) << 2)
| ((autoblock & 1) << 11)
| ((toUType(clk_sel) & 0x1f) << 24)
;
}
constexpr operator uint32_t() const {
return ((pd & 1) << 0) | ((idiv & 255) << 2) | ((autoblock & 1) << 11) | ((toUType(clk_sel) & 0x1f) << 24);
}
};
namespace pll0audio {
struct CTRL {
uint32_t pd;
uint32_t bypass;
uint32_t directi;
uint32_t directo;
uint32_t clken;
uint32_t frm;
uint32_t autoblock;
uint32_t pllfract_req;
uint32_t sel_ext;
uint32_t mod_pd;
CLK_SEL clk_sel;
uint32_t pd;
uint32_t bypass;
uint32_t directi;
uint32_t directo;
uint32_t clken;
uint32_t frm;
uint32_t autoblock;
uint32_t pllfract_req;
uint32_t sel_ext;
uint32_t mod_pd;
CLK_SEL clk_sel;
constexpr operator uint32_t() const {
return
((pd & 1) << 0)
| ((bypass & 1) << 1)
| ((directi & 1) << 2)
| ((directo & 1) << 3)
| ((clken & 1) << 4)
| ((frm & 1) << 6)
| ((autoblock & 1) << 11)
| ((pllfract_req & 1) << 12)
| ((sel_ext & 1) << 13)
| ((mod_pd & 1) << 14)
| ((toUType(clk_sel) & 0x1f) << 24)
;
}
constexpr operator uint32_t() const {
return ((pd & 1) << 0) | ((bypass & 1) << 1) | ((directi & 1) << 2) | ((directo & 1) << 3) | ((clken & 1) << 4) | ((frm & 1) << 6) | ((autoblock & 1) << 11) | ((pllfract_req & 1) << 12) | ((sel_ext & 1) << 13) | ((mod_pd & 1) << 14) | ((toUType(clk_sel) & 0x1f) << 24);
}
};
struct MDIV {
uint32_t mdec;
uint32_t mdec;
constexpr operator uint32_t() const {
return ((mdec & 0x1ffff) << 0);
}
constexpr operator uint32_t() const {
return ((mdec & 0x1ffff) << 0);
}
};
struct NP_DIV {
uint32_t pdec;
uint32_t ndec;
uint32_t pdec;
uint32_t ndec;
constexpr operator uint32_t() const {
return
((pdec & 0x7f) << 0)
| ((ndec & 0x3ff) << 12)
;
}
constexpr operator uint32_t() const {
return ((pdec & 0x7f) << 0) | ((ndec & 0x3ff) << 12);
}
};
struct FRAC {
uint32_t pllfract_ctrl;
uint32_t pllfract_ctrl;
constexpr operator uint32_t() const {
return ((pllfract_ctrl & 0x3fffff) << 0);
}
constexpr operator uint32_t() const {
return ((pllfract_ctrl & 0x3fffff) << 0);
}
};
inline void ctrl(const CTRL& value) {
LPC_CGU->PLL0AUDIO_CTRL = value;
LPC_CGU->PLL0AUDIO_CTRL = value;
}
inline void mdiv(const MDIV& value) {
LPC_CGU->PLL0AUDIO_MDIV = value;
LPC_CGU->PLL0AUDIO_MDIV = value;
}
inline void np_div(const NP_DIV& value) {
LPC_CGU->PLL0AUDIO_NP_DIV = value;
LPC_CGU->PLL0AUDIO_NP_DIV = value;
}
inline void frac(const FRAC& value) {
LPC_CGU->PLL0AUDIO_FRAC = value;
LPC_CGU->PLL0AUDIO_FRAC = value;
}
inline void power_up() {
LPC_CGU->PLL0AUDIO_CTRL &= ~(1U << 0);
LPC_CGU->PLL0AUDIO_CTRL &= ~(1U << 0);
}
inline void power_down() {
LPC_CGU->PLL0AUDIO_CTRL |= (1U << 0);
LPC_CGU->PLL0AUDIO_CTRL |= (1U << 0);
}
inline bool is_locked() {
return LPC_CGU->PLL0AUDIO_STAT & (1U << 0);
return LPC_CGU->PLL0AUDIO_STAT & (1U << 0);
}
inline void clock_enable() {
LPC_CGU->PLL0AUDIO_CTRL |= (1U << 4);
LPC_CGU->PLL0AUDIO_CTRL |= (1U << 4);
}
inline void clock_disable() {
LPC_CGU->PLL0AUDIO_CTRL &= ~(1U << 4);
LPC_CGU->PLL0AUDIO_CTRL &= ~(1U << 4);
}
} /* namespace pll0audio */
@@ -242,49 +224,39 @@ inline void clock_disable() {
namespace pll1 {
struct CTRL {
uint32_t pd;
uint32_t bypass;
uint32_t fbsel;
uint32_t direct;
uint32_t psel;
uint32_t autoblock;
uint32_t nsel;
uint32_t msel;
CLK_SEL clk_sel;
uint32_t pd;
uint32_t bypass;
uint32_t fbsel;
uint32_t direct;
uint32_t psel;
uint32_t autoblock;
uint32_t nsel;
uint32_t msel;
CLK_SEL clk_sel;
constexpr operator uint32_t() const {
return
((pd & 1) << 0)
| ((bypass & 1) << 1)
| ((fbsel & 1) << 6)
| ((direct & 1) << 7)
| ((psel & 3) << 8)
| ((autoblock & 1) << 11)
| ((nsel & 3) << 12)
| ((msel & 0xff) << 16)
| ((toUType(clk_sel) & 0x1f) << 24)
;
}
constexpr operator uint32_t() const {
return ((pd & 1) << 0) | ((bypass & 1) << 1) | ((fbsel & 1) << 6) | ((direct & 1) << 7) | ((psel & 3) << 8) | ((autoblock & 1) << 11) | ((nsel & 3) << 12) | ((msel & 0xff) << 16) | ((toUType(clk_sel) & 0x1f) << 24);
}
};
inline void ctrl(const CTRL& value) {
LPC_CGU->PLL1_CTRL = value;
LPC_CGU->PLL1_CTRL = value;
}
inline void enable() {
LPC_CGU->PLL1_CTRL &= ~(1U << 0);
LPC_CGU->PLL1_CTRL &= ~(1U << 0);
}
inline void disable() {
LPC_CGU->PLL1_CTRL |= (1U << 0);
LPC_CGU->PLL1_CTRL |= (1U << 0);
}
inline void direct() {
LPC_CGU->PLL1_CTRL |= (1U << 7);
LPC_CGU->PLL1_CTRL |= (1U << 7);
}
inline bool is_locked() {
return LPC_CGU->PLL1_STAT & (1U << 0);
return LPC_CGU->PLL1_STAT & (1U << 0);
}
} /* namespace pll1 */
@@ -300,90 +272,89 @@ static_assert(offsetof(LPC_CCU1_Type, CLK_ADCHS_STAT) == 0xb04, "CLK_ADCHS_STAT
namespace rgu {
enum class Reset {
CORE = 0,
PERIPH = 1,
MASTER = 2,
WWDT = 4,
CREG = 5,
BUS = 8,
SCU = 9,
M0_SUB = 12,
M4_RST = 13,
LCD = 16,
USB0 = 17,
USB1 = 18,
DMA = 19,
SDIO = 20,
EMC = 21,
ETHERNET = 22,
FLASHA = 25,
EEPROM = 27,
GPIO = 28,
FLASHB = 29,
TIMER0 = 32,
TIMER1 = 33,
TIMER2 = 34,
TIMER3 = 35,
RITIMER = 36,
SCT = 37,
MOTOCONPWM = 38,
QEI = 39,
ADC0 = 40,
ADC1 = 41,
DAC = 42,
UART0 = 44,
UART1 = 45,
UART2 = 46,
UART3 = 47,
I2C0 = 48,
I2C1 = 49,
SSP0 = 50,
SSP1 = 51,
I2S = 52,
SPIFI = 53,
CAN1 = 54,
CAN0 = 55,
M0APP = 56,
SGPIO = 57,
SPI = 58,
ADCHS = 60,
CORE = 0,
PERIPH = 1,
MASTER = 2,
WWDT = 4,
CREG = 5,
BUS = 8,
SCU = 9,
M0_SUB = 12,
M4_RST = 13,
LCD = 16,
USB0 = 17,
USB1 = 18,
DMA = 19,
SDIO = 20,
EMC = 21,
ETHERNET = 22,
FLASHA = 25,
EEPROM = 27,
GPIO = 28,
FLASHB = 29,
TIMER0 = 32,
TIMER1 = 33,
TIMER2 = 34,
TIMER3 = 35,
RITIMER = 36,
SCT = 37,
MOTOCONPWM = 38,
QEI = 39,
ADC0 = 40,
ADC1 = 41,
DAC = 42,
UART0 = 44,
UART1 = 45,
UART2 = 46,
UART3 = 47,
I2C0 = 48,
I2C1 = 49,
SSP0 = 50,
SSP1 = 51,
I2S = 52,
SPIFI = 53,
CAN1 = 54,
CAN0 = 55,
M0APP = 56,
SGPIO = 57,
SPI = 58,
ADCHS = 60,
};
enum class Status {
NotActive = 0b00,
ActivatedByRGUInput = 0b01,
ActivatedBySoftware = 0b11,
NotActive = 0b00,
ActivatedByRGUInput = 0b01,
ActivatedBySoftware = 0b11,
};
inline void reset(const Reset reset) {
LPC_RGU->RESET_CTRL[toUType(reset) >> 5] = (1U << (toUType(reset) & 0x1f));
LPC_RGU->RESET_CTRL[toUType(reset) >> 5] = (1U << (toUType(reset) & 0x1f));
}
inline void reset_mask(const uint64_t mask) {
LPC_RGU->RESET_CTRL[0] = mask & 0xffffffffU;
LPC_RGU->RESET_CTRL[1] = mask >> 32;
LPC_RGU->RESET_CTRL[0] = mask & 0xffffffffU;
LPC_RGU->RESET_CTRL[1] = mask >> 32;
}
inline Status status(const Reset reset) {
return static_cast<Status>(
(LPC_RGU->RESET_STATUS[toUType(reset) >> 4] >> ((toUType(reset) & 0xf) * 2)) & 3
);
return static_cast<Status>(
(LPC_RGU->RESET_STATUS[toUType(reset) >> 4] >> ((toUType(reset) & 0xf) * 2)) & 3);
}
inline bool active(const Reset reset) {
return (LPC_RGU->RESET_ACTIVE_STATUS[toUType(reset) >> 5] >> (toUType(reset) & 0x1f)) & 1;
return (LPC_RGU->RESET_ACTIVE_STATUS[toUType(reset) >> 5] >> (toUType(reset) & 0x1f)) & 1;
}
inline uint32_t external_status(const Reset reset) {
return LPC_RGU->RESET_EXT_STAT[toUType(reset)];
return LPC_RGU->RESET_EXT_STAT[toUType(reset)];
}
inline uint64_t operator|(Reset r1, Reset r2) {
return (1ULL << toUType(r1)) | (1ULL << toUType(r2));
return (1ULL << toUType(r1)) | (1ULL << toUType(r2));
}
inline uint64_t operator|(uint64_t m, Reset r) {
return m | (1ULL << toUType(r));
return m | (1ULL << toUType(r));
}
static_assert(offsetof(LPC_RGU_Type, RESET_CTRL[0]) == 0x100, "RESET_CTRL[0] offset wrong");
@@ -397,23 +368,16 @@ static_assert(offsetof(LPC_RGU_Type, RESET_EXT_STAT[60]) == 0x4f0, "RESET_EXT_ST
namespace scu {
struct SFS {
uint32_t mode;
uint32_t epd;
uint32_t epun;
uint32_t ehs;
uint32_t ezi;
uint32_t zif;
uint32_t mode;
uint32_t epd;
uint32_t epun;
uint32_t ehs;
uint32_t ezi;
uint32_t zif;
constexpr operator uint32_t() const {
return
((mode & 7) << 0)
| ((epd & 1) << 3)
| ((epun & 1) << 4)
| ((ehs & 1) << 5)
| ((ezi & 1) << 6)
| ((zif & 1) << 7)
;
}
constexpr operator uint32_t() const {
return ((mode & 7) << 0) | ((epd & 1) << 3) | ((epun & 1) << 4) | ((ehs & 1) << 5) | ((ezi & 1) << 6) | ((zif & 1) << 7);
}
};
static_assert(offsetof(LPC_SCU_Type, PINTSEL0) == 0xe00, "PINTSEL0 offset wrong");
@@ -455,31 +419,20 @@ static_assert(offsetof(LPC_SDMMC_Type, DATA) == 0x100, "SDMMC DATA offset wrong"
namespace spifi {
struct CTRL {
uint32_t timeout;
uint32_t cshigh;
uint32_t d_prftch_dis;
uint32_t inten;
uint32_t mode3;
uint32_t prftch_dis;
uint32_t dual;
uint32_t rfclk;
uint32_t fbclk;
uint32_t dmaen;
uint32_t timeout;
uint32_t cshigh;
uint32_t d_prftch_dis;
uint32_t inten;
uint32_t mode3;
uint32_t prftch_dis;
uint32_t dual;
uint32_t rfclk;
uint32_t fbclk;
uint32_t dmaen;
constexpr operator uint32_t() const {
return
((timeout & 0xffff) << 0)
| ((cshigh & 1) << 16)
| ((d_prftch_dis & 1) << 21)
| ((inten & 1) << 22)
| ((mode3 & 1) << 23)
| ((prftch_dis & 1) << 27)
| ((dual & 1) << 28)
| ((rfclk & 1) << 29)
| ((fbclk & 1) << 30)
| ((dmaen & 1) << 31)
;
}
constexpr operator uint32_t() const {
return ((timeout & 0xffff) << 0) | ((cshigh & 1) << 16) | ((d_prftch_dis & 1) << 21) | ((inten & 1) << 22) | ((mode3 & 1) << 23) | ((prftch_dis & 1) << 27) | ((dual & 1) << 28) | ((rfclk & 1) << 29) | ((fbclk & 1) << 30) | ((dmaen & 1) << 31);
}
};
static_assert(offsetof(LPC_SPIFI_Type, STAT) == 0x01c, "SPIFI STAT offset wrong");
@@ -500,59 +453,56 @@ namespace rtc {
namespace interrupt {
inline void clear_all() {
LPC_RTC->ILR = (1U << 1) | (1U << 0);
LPC_RTC->ILR = (1U << 1) | (1U << 0);
}
inline void enable_second_inc() {
LPC_RTC->CIIR = (1U << 0);
LPC_RTC->CIIR = (1U << 0);
}
} /* namespace */
} // namespace interrupt
#if HAL_USE_RTC
struct RTC : public RTCTime {
constexpr RTC(
uint32_t year,
uint32_t month,
uint32_t day,
uint32_t hour,
uint32_t minute,
uint32_t second
) : RTCTime {
(year << 16) | (month << 8) | (day << 0),
(hour << 16) | (minute << 8) | (second << 0)
}
{
}
constexpr RTC(
uint32_t year,
uint32_t month,
uint32_t day,
uint32_t hour,
uint32_t minute,
uint32_t second)
: RTCTime{
(year << 16) | (month << 8) | (day << 0),
(hour << 16) | (minute << 8) | (second << 0)} {
}
constexpr RTC(
) : RTCTime { 0, 0 }
{
}
constexpr RTC()
: RTCTime{0, 0} {
}
uint16_t year() const {
return (tv_date >> 16) & 0xfff;
}
uint16_t year() const {
return (tv_date >> 16) & 0xfff;
}
uint8_t month() const {
return (tv_date >> 8) & 0x00f;
}
uint8_t month() const {
return (tv_date >> 8) & 0x00f;
}
uint8_t day() const {
return (tv_date >> 0) & 0x01f;
}
uint8_t day() const {
return (tv_date >> 0) & 0x01f;
}
uint8_t hour() const {
return (tv_time >> 16) & 0x01f;
}
uint8_t hour() const {
return (tv_time >> 16) & 0x01f;
}
uint8_t minute() const {
return (tv_time >> 8) & 0x03f;
}
uint8_t minute() const {
return (tv_time >> 8) & 0x03f;
}
uint8_t second() const {
return (tv_time >> 0) & 0x03f;
}
uint8_t second() const {
return (tv_time >> 0) & 0x03f;
}
};
#endif
@@ -563,4 +513,4 @@ static_assert(offsetof(LPC_RTC_Type, ASEC) == 0x060, "RTC ASEC offset wrong");
} /* namespace lpc43xx */
#endif/*__LPC43XX_CPP_H__*/
#endif /*__LPC43XX_CPP_H__*/

View File

@@ -24,73 +24,72 @@
#include "string_format.hpp"
size_t ManchesterBase::symbols_count() const {
return packet.size() / 2;
return packet.size() / 2;
}
DecodedSymbol ManchesterDecoder::operator[](const size_t index) const {
const size_t encoded_index = index * 2;
if( (encoded_index + 1) < packet.size() ) {
const auto value = packet[encoded_index + sense];
const auto error = packet[encoded_index + 0] == packet[encoded_index + 1];
return { value, error };
} else {
return { 0, 1 };
}
const size_t encoded_index = index * 2;
if ((encoded_index + 1) < packet.size()) {
const auto value = packet[encoded_index + sense];
const auto error = packet[encoded_index + 0] == packet[encoded_index + 1];
return {value, error};
} else {
return {0, 1};
}
}
DecodedSymbol BiphaseMDecoder::operator[](const size_t index) const {
const size_t encoded_index = index * 2;
if( (encoded_index + 1) < packet.size() ) {
const auto value = packet[encoded_index + 0] != packet[encoded_index + 1];
const uint_fast8_t error = encoded_index ? (packet[encoded_index - 1] == packet[encoded_index + 0]) : 0;
return { value, error };
} else {
return { 0, 1 };
}
const size_t encoded_index = index * 2;
if ((encoded_index + 1) < packet.size()) {
const auto value = packet[encoded_index + 0] != packet[encoded_index + 1];
const uint_fast8_t error = encoded_index ? (packet[encoded_index - 1] == packet[encoded_index + 0]) : 0;
return {value, error};
} else {
return {0, 1};
}
}
FormattedSymbols format_symbols(
const ManchesterBase& decoder
) {
const size_t payload_length_decoded = decoder.symbols_count();
const size_t payload_length_hex_characters = (payload_length_decoded + 3) / 4;
const size_t payload_length_symbols_rounded = payload_length_hex_characters * 4;
const ManchesterBase& decoder) {
const size_t payload_length_decoded = decoder.symbols_count();
const size_t payload_length_hex_characters = (payload_length_decoded + 3) / 4;
const size_t payload_length_symbols_rounded = payload_length_hex_characters * 4;
std::string hex_data;
std::string hex_error;
hex_data.reserve(payload_length_hex_characters);
hex_error.reserve(payload_length_hex_characters);
std::string hex_data;
std::string hex_error;
hex_data.reserve(payload_length_hex_characters);
hex_error.reserve(payload_length_hex_characters);
uint_fast8_t data = 0;
uint_fast8_t error = 0;
for(size_t i=0; i<payload_length_symbols_rounded; i++) {
const auto symbol = decoder[i];
uint_fast8_t data = 0;
uint_fast8_t error = 0;
for (size_t i = 0; i < payload_length_symbols_rounded; i++) {
const auto symbol = decoder[i];
data <<= 1;
data |= symbol.value;
data <<= 1;
data |= symbol.value;
error <<= 1;
error |= symbol.error;
error <<= 1;
error |= symbol.error;
if( (i & 3) == 3 ) {
hex_data += to_string_hex(data & 0xf, 1);
hex_error += to_string_hex(error & 0xf, 1);
}
}
if ((i & 3) == 3) {
hex_data += to_string_hex(data & 0xf, 1);
hex_error += to_string_hex(error & 0xf, 1);
}
}
return { hex_data, hex_error };
return {hex_data, hex_error};
}
void manchester_encode(uint8_t * dest, uint8_t * src, const size_t length, const size_t sense) {
uint8_t part = sense ? 0 : 0xFF;
for (size_t c = 0; c < length; c++) {
if ((src[c >> 3] << (c & 7)) & 0x80) {
*(dest++) = part;
*(dest++) = ~part;
} else {
*(dest++) = ~part;
*(dest++) = part;
}
}
void manchester_encode(uint8_t* dest, uint8_t* src, const size_t length, const size_t sense) {
uint8_t part = sense ? 0 : 0xFF;
for (size_t c = 0; c < length; c++) {
if ((src[c >> 3] << (c & 7)) & 0x80) {
*(dest++) = part;
*(dest++) = ~part;
} else {
*(dest++) = ~part;
*(dest++) = part;
}
}
}

View File

@@ -30,57 +30,55 @@
#include "baseband_packet.hpp"
struct DecodedSymbol {
uint_fast8_t value;
uint_fast8_t error;
uint_fast8_t value;
uint_fast8_t error;
};
class ManchesterBase {
public:
constexpr ManchesterBase(
const baseband::Packet& packet,
const size_t sense = 0
) : packet { packet },
sense { sense }
{
}
virtual DecodedSymbol operator[](const size_t index) const = 0;
public:
constexpr ManchesterBase(
const baseband::Packet& packet,
const size_t sense = 0)
: packet{packet},
sense{sense} {
}
virtual size_t symbols_count() const;
virtual ~ManchesterBase() { };
protected:
const baseband::Packet& packet;
const size_t sense;
virtual DecodedSymbol operator[](const size_t index) const = 0;
virtual size_t symbols_count() const;
virtual ~ManchesterBase(){};
protected:
const baseband::Packet& packet;
const size_t sense;
};
class ManchesterDecoder : public ManchesterBase {
public:
using ManchesterBase::ManchesterBase;
DecodedSymbol operator[](const size_t index) const;
public:
using ManchesterBase::ManchesterBase;
DecodedSymbol operator[](const size_t index) const;
};
class BiphaseMDecoder : public ManchesterBase {
public:
using ManchesterBase::ManchesterBase;
DecodedSymbol operator[](const size_t index) const;
public:
using ManchesterBase::ManchesterBase;
DecodedSymbol operator[](const size_t index) const;
};
template<typename T>
template <typename T>
T operator|(const T& l, const DecodedSymbol& r) {
return l | r.value;
return l | r.value;
}
struct FormattedSymbols {
const std::string data;
const std::string errors;
const std::string data;
const std::string errors;
};
FormattedSymbols format_symbols(
const ManchesterBase& decoder
);
const ManchesterBase& decoder);
void manchester_encode(uint8_t * dest, uint8_t * src, const size_t length, const size_t sense = 0);
void manchester_encode(uint8_t* dest, uint8_t* src, const size_t length, const size_t sense = 0);
#endif/*__MANCHESTER_H__*/
#endif /*__MANCHESTER_H__*/

View File

@@ -34,55 +34,54 @@ namespace portapack {
namespace memory {
struct region_t {
public:
constexpr region_t(
const uint32_t base,
const size_t size
) : base_ { base },
size_ { size } {
public:
constexpr region_t(
const uint32_t base,
const size_t size)
: base_{base},
size_{size} {
}
}
constexpr uint32_t base() const {
return base_;
}
constexpr uint32_t base() const {
return base_;
}
constexpr uint32_t end() const {
return base_ + size_;
}
constexpr uint32_t end() const {
return base_ + size_;
}
constexpr size_t size() const {
return size_;
}
constexpr size_t size() const {
return size_;
}
private:
const uint32_t base_;
const size_t size_;
private:
const uint32_t base_;
const size_t size_;
};
namespace map {
constexpr region_t local_sram_0 { 0x10000000, 96_KiB };
constexpr region_t local_sram_1 { 0x10080000, 40_KiB };
constexpr region_t local_sram_0{0x10000000, 96_KiB};
constexpr region_t local_sram_1{0x10080000, 40_KiB};
constexpr region_t ahb_ram_0 { 0x20000000, 32_KiB };
constexpr region_t ahb_ram_1 { 0x20008000, 16_KiB };
constexpr region_t ahb_ram_2 { 0x2000c000, 16_KiB };
constexpr region_t ahb_ram_0{0x20000000, 32_KiB};
constexpr region_t ahb_ram_1{0x20008000, 16_KiB};
constexpr region_t ahb_ram_2{0x2000c000, 16_KiB};
constexpr region_t backup_ram { LPC_BACKUP_REG_BASE, 256 };
constexpr region_t backup_ram{LPC_BACKUP_REG_BASE, 256};
constexpr region_t spifi_uncached { LPC_SPIFI_DATA_BASE, 1_MiB };
constexpr region_t spifi_cached { LPC_SPIFI_DATA_CACHED_BASE, spifi_uncached.size() };
constexpr region_t spifi_uncached{LPC_SPIFI_DATA_BASE, 1_MiB};
constexpr region_t spifi_cached{LPC_SPIFI_DATA_CACHED_BASE, spifi_uncached.size()};
/////////////////////////////////
constexpr region_t m4_code { local_sram_1.base(), 32_KiB };
constexpr region_t shared_memory { m4_code.end(), 8_KiB };
constexpr region_t m4_code{local_sram_1.base(), 32_KiB};
constexpr region_t shared_memory{m4_code.end(), 8_KiB};
constexpr region_t m4_code_hackrf = local_sram_0;
constexpr region_t m4_code_hackrf = local_sram_0;
} /* namespace map */
} /* namespace memory */
} /* namespace portapack */
#endif/*__MEMORY_MAP_H__*/
#endif /*__MEMORY_MAP_H__*/

File diff suppressed because it is too large Load Diff

View File

@@ -26,12 +26,12 @@ using namespace lpc43xx;
#if defined(LPC43XX_M0)
void MessageQueue::signal() {
creg::m0apptxevent::assert_event();
creg::m0apptxevent::assert_event();
}
#endif
#if defined(LPC43XX_M4)
void MessageQueue::signal() {
creg::m4txevent::assert_event();
creg::m4txevent::assert_event();
}
#endif

View File

@@ -30,89 +30,89 @@
#include <ch.h>
class MessageQueue {
public:
MessageQueue() = delete;
MessageQueue(const MessageQueue&) = delete;
MessageQueue(MessageQueue&&) = delete;
MessageQueue(
uint8_t* const data,
size_t k
) : fifo { data, k }
{
chMtxInit(&mutex_write);
}
public:
MessageQueue() = delete;
MessageQueue(const MessageQueue&) = delete;
MessageQueue(MessageQueue&&) = delete;
template<typename T>
bool push(const T& message) {
static_assert(sizeof(T) <= Message::MAX_SIZE, "Message::MAX_SIZE too small for message type");
static_assert(std::is_base_of<Message, T>::value, "type is not based on Message");
MessageQueue(
uint8_t* const data,
size_t k)
: fifo{data, k} {
chMtxInit(&mutex_write);
}
return push(&message, sizeof(message));
}
template <typename T>
bool push(const T& message) {
static_assert(sizeof(T) <= Message::MAX_SIZE, "Message::MAX_SIZE too small for message type");
static_assert(std::is_base_of<Message, T>::value, "type is not based on Message");
template<typename T>
bool push_and_wait(const T& message) {
const bool result = push(message);
if( result ) {
// TODO: More graceful method of waiting for empty? Maybe sleep for a bit?
while( !is_empty() );
}
return result;
}
return push(&message, sizeof(message));
}
template<typename HandlerFn>
void handle(HandlerFn handler) {
std::array<uint8_t, Message::MAX_SIZE> message_buffer;
while(Message* const message = peek(message_buffer)) {
handler(message);
skip();
}
}
template <typename T>
bool push_and_wait(const T& message) {
const bool result = push(message);
if (result) {
// TODO: More graceful method of waiting for empty? Maybe sleep for a bit?
while (!is_empty())
;
}
return result;
}
bool is_empty() const {
return fifo.is_empty();
}
template <typename HandlerFn>
void handle(HandlerFn handler) {
std::array<uint8_t, Message::MAX_SIZE> message_buffer;
while (Message* const message = peek(message_buffer)) {
handler(message);
skip();
}
}
void reset() {
fifo.reset();
}
private:
FIFO<uint8_t> fifo;
Mutex mutex_write { };
bool is_empty() const {
return fifo.is_empty();
}
Message* peek(std::array<uint8_t, Message::MAX_SIZE>& buf) {
Message* const p = reinterpret_cast<Message*>(buf.data());
return fifo.peek_r(buf.data(), buf.size()) ? p : nullptr;
}
void reset() {
fifo.reset();
}
bool skip() {
return fifo.skip();
}
private:
FIFO<uint8_t> fifo;
Mutex mutex_write{};
Message* pop(std::array<uint8_t, Message::MAX_SIZE>& buf) {
Message* const p = reinterpret_cast<Message*>(buf.data());
return fifo.out_r(buf.data(), buf.size()) ? p : nullptr;
}
Message* peek(std::array<uint8_t, Message::MAX_SIZE>& buf) {
Message* const p = reinterpret_cast<Message*>(buf.data());
return fifo.peek_r(buf.data(), buf.size()) ? p : nullptr;
}
size_t len() const {
return fifo.len();
}
bool skip() {
return fifo.skip();
}
bool push(const void* const buf, const size_t len) {
chMtxLock(&mutex_write);
const auto result = fifo.in_r(buf, len);
chMtxUnlock();
Message* pop(std::array<uint8_t, Message::MAX_SIZE>& buf) {
Message* const p = reinterpret_cast<Message*>(buf.data());
return fifo.out_r(buf.data(), buf.size()) ? p : nullptr;
}
const bool success = (result == len);
if( success ) {
signal();
}
return success;
}
size_t len() const {
return fifo.len();
}
void signal();
bool push(const void* const buf, const size_t len) {
chMtxLock(&mutex_write);
const auto result = fifo.in_r(buf, len);
chMtxUnlock();
const bool success = (result == len);
if (success) {
signal();
}
return success;
}
void signal();
};
#endif/*__MESSAGE_QUEUE_H__*/
#endif /*__MESSAGE_QUEUE_H__*/

View File

@@ -1,2 +1,36 @@
const char md5_baseband[16] = {0xb8,0x9e,0x9b,0x08,0x44,0x34,0x04,0x20,0x0b,0xbc,0x60,0x7e,0x67,0x88,0x53,0xf7,};
const char md5_baseband_tx[16] = {0xd5,0xaf,0x76,0xd5,0xa3,0x32,0x5d,0x9a,0x9d,0x83,0x46,0x37,0x02,0x2d,0xd0,0x57,};
const char md5_baseband[16] = {
0xb8,
0x9e,
0x9b,
0x08,
0x44,
0x34,
0x04,
0x20,
0x0b,
0xbc,
0x60,
0x7e,
0x67,
0x88,
0x53,
0xf7,
};
const char md5_baseband_tx[16] = {
0xd5,
0xaf,
0x76,
0xd5,
0xa3,
0x32,
0x5d,
0x9a,
0x9d,
0x83,
0x46,
0x37,
0x02,
0x2d,
0xd0,
0x57,
};

View File

@@ -31,61 +31,59 @@ using namespace portapack;
namespace morse {
// Returns 0 if message is too long
size_t morse_encode(std::string& message, const uint32_t time_unit_ms,
const uint32_t tone, uint32_t * const time_units) {
size_t i, c;
uint16_t code, code_size;
uint8_t morse_message[256];
uint32_t delta;
*time_units = 0;
i = 0;
for (char& ch : message) {
if (i > 256) return 0; // Message too long
if ((ch >= 'a') && (ch <= 'z')) // Make uppercase
ch -= 32;
if ((ch >= '!') && (ch <= '_')) {
code = morse_ITU[ch - '!'];
} else {
code = 0; // Default to space char
}
if (!code) {
if (i)
morse_message[i - 1] = 4; // Word space
} else {
code_size = code & 7;
for (c = 0; c < code_size; c++) {
morse_message[i++] = ((code << c) & 0x8000) ? 1 : 0; // Dot/dash
morse_message[i++] = 2; // Symbol space
}
morse_message[i - 1] = 3; // Letter space
}
}
// Count time units
for (c = 0; c < i; c++) {
*time_units += morse_symbols[morse_message[c]];
}
memcpy(shared_memory.bb_data.tones_data.message, morse_message, i);
// Setup tone "symbols"
for (c = 0; c < 5; c++) {
if (c < 2)
delta = TONES_F2D(tone, TONES_SAMPLERATE); // Dot and dash
else
delta = 0; // Pause
baseband::set_tone(c, delta, (TONES_SAMPLERATE * morse_symbols[c] * time_unit_ms) / 1000);
}
return i;
size_t morse_encode(std::string& message, const uint32_t time_unit_ms, const uint32_t tone, uint32_t* const time_units) {
size_t i, c;
uint16_t code, code_size;
uint8_t morse_message[256];
uint32_t delta;
*time_units = 0;
i = 0;
for (char& ch : message) {
if (i > 256) return 0; // Message too long
if ((ch >= 'a') && (ch <= 'z')) // Make uppercase
ch -= 32;
if ((ch >= '!') && (ch <= '_')) {
code = morse_ITU[ch - '!'];
} else {
code = 0; // Default to space char
}
if (!code) {
if (i)
morse_message[i - 1] = 4; // Word space
} else {
code_size = code & 7;
for (c = 0; c < code_size; c++) {
morse_message[i++] = ((code << c) & 0x8000) ? 1 : 0; // Dot/dash
morse_message[i++] = 2; // Symbol space
}
morse_message[i - 1] = 3; // Letter space
}
}
// Count time units
for (c = 0; c < i; c++) {
*time_units += morse_symbols[morse_message[c]];
}
memcpy(shared_memory.bb_data.tones_data.message, morse_message, i);
// Setup tone "symbols"
for (c = 0; c < 5; c++) {
if (c < 2)
delta = TONES_F2D(tone, TONES_SAMPLERATE); // Dot and dash
else
delta = 0; // Pause
baseband::set_tone(c, delta, (TONES_SAMPLERATE * morse_symbols[c] * time_unit_ms) / 1000);
}
return i;
}
} /* namespace morse */

View File

@@ -33,116 +33,114 @@
#define MORSE_WORD_SPACE 7
namespace morse {
const uint32_t morse_symbols[5] = {
MORSE_DOT,
MORSE_DASH,
MORSE_SYMBOL_SPACE,
MORSE_LETTER_SPACE,
MORSE_WORD_SPACE
};
size_t morse_encode(std::string& message, const uint32_t time_unit_ms,
const uint32_t tone, uint32_t * const time_units);
const uint32_t morse_symbols[5] = {
MORSE_DOT,
MORSE_DASH,
MORSE_SYMBOL_SPACE,
MORSE_LETTER_SPACE,
MORSE_WORD_SPACE};
size_t morse_encode(std::string& message, const uint32_t time_unit_ms, const uint32_t tone, uint32_t* const time_units);
constexpr char foxhunt_codes[11][4] = {
{ "MOE" }, // -----.
{ "MOI" }, // -----..
{ "MOS" }, // -----...
{ "MOH" }, // -----....
{ "MO5" }, // -----.....
{ "MON" }, // ------.
{ "MOD" }, // ------..
{ "MOB" }, // ------...
{ "MO6" }, // ------....
{ "MO" }, // -----
{ "S" } // ...
{"MOE"}, // -----.
{"MOI"}, // -----..
{"MOS"}, // -----...
{"MOH"}, // -----....
{"MO5"}, // -----.....
{"MON"}, // ------.
{"MOD"}, // ------..
{"MOB"}, // ------...
{"MO6"}, // ------....
{"MO"}, // -----
{"S"} // ...
};
// 0=dot 1=dash
constexpr uint16_t morse_ITU[63] = {
// Code Size
0b1010110000000110, // !: 101011- 110
0b0100100000000110, // ": 010010- 110
0, // #
0b0001001000000111, // $: 0001001 111
0, // %
0b0100000000000101, // &: 01000-- 101
0b0111100000000110, // ': 011110- 110
0b1011000000000101, // (: 10110-- 101
0b1011010000000110, // ): 101101- 110
0, // *
0b0101000000000101, // +: 01010-- 101
0b1100110000000110, // ,: 110011- 110
0b1000010000000110, // -: 100001- 110
0b0101010000000110, // .: 010101- 110
0b1001000000000101, // /: 10010-- 101
0b1111100000000101, // 0: 11111-- 101
0b0111100000000101, // 1: 01111-- 101
0b0011100000000101, // 2: 00111-- 101
0b0001100000000101, // 3: 00011-- 101
0b0000100000000101, // 4: 00001-- 101
0b0000000000000101, // 5: 00000-- 101
0b1000000000000101, // 6: 10000-- 101
0b1100000000000101, // 7: 11000-- 101
0b1110000000000101, // 8: 11100-- 101
0b1111000000000101, // 9: 11110-- 101
0b1110000000000110, // :: 111000- 110
0b1010100000000110, // ;: 101010- 110
0, // <
0b1000100000000101, // =: 10001-- 101
0, // >
0b0011000000000110, // ?: 001100- 110
0b0110100000000110, // @: 011010- 110
0b0100000000000010, // A: 01----- 010
0b1000000000000100, // B: 1000--- 100
0b1010000000000100, // C: 1010--- 100
0b1000000000000011, // D: 100---- 011
0b0000000000000001, // E: 0------ 001
0b0010000000000100, // F: 0010--- 100
0b1100000000000011, // G: 110---- 011
0b0000000000000100, // H: 0000--- 100
0b0000000000000010, // I: 00----- 010
0b0111000000000100, // J: 0111--- 100
0b1010000000000011, // K: 101---- 011
0b0100000000000100, // L: 0100--- 100
0b1100000000000010, // M: 11----- 010
0b1000000000000010, // N: 10----- 010
0b1110000000000011, // O: 111---- 011
0b0110000000000100, // P: 0110--- 100 .#-###-###.# ##.#-### ##.#-###.# ##.#.# ##.#.#.# = 48 units
0b1101000000000100, // Q: 1101--- 100
0b0100000000000011, // R: 010---- 011
0b0000000000000011, // S: 000---- 011
0b1000000000000001, // T: 1------ 001
0b0010000000000011, // U: 001---- 011
0b0001000000000100, // V: 0001--- 100
0b0110000000000011, // W: 011---- 011
0b1001000000000100, // X: 1001--- 100
0b1011000000000100, // Y: 1011--- 100
0b1100000000000100, // Z: 1100--- 100
0, // [
0, // Back-slash
0, // ]
0, // ^
0b0011010000000110 // _: 001101- 110
// Code Size
0b1010110000000110, // !: 101011- 110
0b0100100000000110, // ": 010010- 110
0, // #
0b0001001000000111, // $: 0001001 111
0, // %
0b0100000000000101, // &: 01000-- 101
0b0111100000000110, // ': 011110- 110
0b1011000000000101, // (: 10110-- 101
0b1011010000000110, // ): 101101- 110
0, // *
0b0101000000000101, // +: 01010-- 101
0b1100110000000110, // ,: 110011- 110
0b1000010000000110, // -: 100001- 110
0b0101010000000110, // .: 010101- 110
0b1001000000000101, // /: 10010-- 101
0b1111100000000101, // 0: 11111-- 101
0b0111100000000101, // 1: 01111-- 101
0b0011100000000101, // 2: 00111-- 101
0b0001100000000101, // 3: 00011-- 101
0b0000100000000101, // 4: 00001-- 101
0b0000000000000101, // 5: 00000-- 101
0b1000000000000101, // 6: 10000-- 101
0b1100000000000101, // 7: 11000-- 101
0b1110000000000101, // 8: 11100-- 101
0b1111000000000101, // 9: 11110-- 101
0b1110000000000110, // :: 111000- 110
0b1010100000000110, // ;: 101010- 110
0, // <
0b1000100000000101, // =: 10001-- 101
0, // >
0b0011000000000110, // ?: 001100- 110
0b0110100000000110, // @: 011010- 110
0b0100000000000010, // A: 01----- 010
0b1000000000000100, // B: 1000--- 100
0b1010000000000100, // C: 1010--- 100
0b1000000000000011, // D: 100---- 011
0b0000000000000001, // E: 0------ 001
0b0010000000000100, // F: 0010--- 100
0b1100000000000011, // G: 110---- 011
0b0000000000000100, // H: 0000--- 100
0b0000000000000010, // I: 00----- 010
0b0111000000000100, // J: 0111--- 100
0b1010000000000011, // K: 101---- 011
0b0100000000000100, // L: 0100--- 100
0b1100000000000010, // M: 11----- 010
0b1000000000000010, // N: 10----- 010
0b1110000000000011, // O: 111---- 011
0b0110000000000100, // P: 0110--- 100 .#-###-###.# ##.#-### ##.#-###.# ##.#.# ##.#.#.# = 48 units
0b1101000000000100, // Q: 1101--- 100
0b0100000000000011, // R: 010---- 011
0b0000000000000011, // S: 000---- 011
0b1000000000000001, // T: 1------ 001
0b0010000000000011, // U: 001---- 011
0b0001000000000100, // V: 0001--- 100
0b0110000000000011, // W: 011---- 011
0b1001000000000100, // X: 1001--- 100
0b1011000000000100, // Y: 1011--- 100
0b1100000000000100, // Z: 1100--- 100
0, // [
0, // Back-slash
0, // ]
0, // ^
0b0011010000000110 // _: 001101- 110
};
constexpr uint16_t prosigns[12] = {
// Code Size
0b0001110000001001, // <SOS>: 000111000 1001
0b0101000000000100, // <AA>: 0101----- 0100
0b0101000000000101, // <AR>: 01010---- 0101
0b0100000000000101, // <AS>: 01000---- 0101
0b1000100000000101, // <BT>: 10001---- 0101
0b1010100000000101, // <CT>: 10101---- 0101
0b0000000000001000, // <HH>: 00000000- 1000
0b1010000000000011, // <K>: 101------ 0011
0b1011000000000101, // <KN>: 10110---- 0101
0b1001110000000110, // <NJ>: 100111--- 0110
0b0001010000000110, // <SK>: 000101--- 0110
0b0001100000000101, // <SN>: 00010---- 0101
// Code Size
0b0001110000001001, // <SOS>: 000111000 1001
0b0101000000000100, // <AA>: 0101----- 0100
0b0101000000000101, // <AR>: 01010---- 0101
0b0100000000000101, // <AS>: 01000---- 0101
0b1000100000000101, // <BT>: 10001---- 0101
0b1010100000000101, // <CT>: 10101---- 0101
0b0000000000001000, // <HH>: 00000000- 1000
0b1010000000000011, // <K>: 101------ 0011
0b1011000000000101, // <KN>: 10110---- 0101
0b1001110000000110, // <NJ>: 100111--- 0110
0b0001010000000110, // <SK>: 000101--- 0110
0b0001100000000101, // <SN>: 00010---- 0101
};
} /* namespace morse */
#endif/*__MORSE_H__*/
#endif /*__MORSE_H__*/

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
@@ -22,320 +22,317 @@
#include "msgpack.hpp"
bool MsgPack::get_bool(const void * buffer, const bool inc, bool * value) {
uint8_t v;
if (seek_ptr >= buffer_size) return false; // End of buffer
v = ((uint8_t*)buffer)[seek_ptr];
if (v == MSGPACK_FALSE)
*value = false;
else if (v == MSGPACK_TRUE)
*value = true;
else
return false; // Not a bool
if (inc) seek_ptr++;
return true;
bool MsgPack::get_bool(const void* buffer, const bool inc, bool* value) {
uint8_t v;
if (seek_ptr >= buffer_size) return false; // End of buffer
v = ((uint8_t*)buffer)[seek_ptr];
if (v == MSGPACK_FALSE)
*value = false;
else if (v == MSGPACK_TRUE)
*value = true;
else
return false; // Not a bool
if (inc) seek_ptr++;
return true;
}
bool MsgPack::get_raw_byte(const void * buffer, const bool inc, uint8_t * byte) {
if (seek_ptr >= buffer_size) return false; // End of buffer
*byte = ((uint8_t*)buffer)[seek_ptr];
if (inc) seek_ptr++;
return true;
bool MsgPack::get_raw_byte(const void* buffer, const bool inc, uint8_t* byte) {
if (seek_ptr >= buffer_size) return false; // End of buffer
*byte = ((uint8_t*)buffer)[seek_ptr];
if (inc) seek_ptr++;
return true;
}
bool MsgPack::get_raw_word(const void * buffer, const bool inc, uint16_t * word) {
if ((seek_ptr + 1) >= buffer_size) return false; // End of buffer
*word = (((uint8_t*)buffer)[seek_ptr] << 8) | ((uint8_t*)buffer)[seek_ptr + 1];
if (inc) seek_ptr += 2;
return true;
bool MsgPack::get_raw_word(const void* buffer, const bool inc, uint16_t* word) {
if ((seek_ptr + 1) >= buffer_size) return false; // End of buffer
*word = (((uint8_t*)buffer)[seek_ptr] << 8) | ((uint8_t*)buffer)[seek_ptr + 1];
if (inc) seek_ptr += 2;
return true;
}
bool MsgPack::get_u8(const void * buffer, const bool inc, uint8_t * value) {
uint8_t v;
if (seek_ptr >= buffer_size) return false; // End of buffer
v = ((uint8_t*)buffer)[seek_ptr];
bool MsgPack::get_u8(const void* buffer, const bool inc, uint8_t* value) {
uint8_t v;
if (!(v & 0x80))
*value = ((uint8_t*)buffer)[seek_ptr]; // Fixnum
else if (v == MSGPACK_TYPE_U8)
*value = ((uint8_t*)buffer)[seek_ptr + 1]; // u8
else
return false; // Value isn't a u8 or fixnum
if (inc) seek_ptr++;
return true;
if (seek_ptr >= buffer_size) return false; // End of buffer
v = ((uint8_t*)buffer)[seek_ptr];
if (!(v & 0x80))
*value = ((uint8_t*)buffer)[seek_ptr]; // Fixnum
else if (v == MSGPACK_TYPE_U8)
*value = ((uint8_t*)buffer)[seek_ptr + 1]; // u8
else
return false; // Value isn't a u8 or fixnum
if (inc) seek_ptr++;
return true;
}
// TODO: Typecheck function
bool MsgPack::get_u16(const void * buffer, const bool inc, uint16_t * value) {
uint8_t byte;
if ((seek_ptr + 1) >= buffer_size) return false; // End of buffer
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_U16)) return false; // Value isn't a u16
*value = (((uint8_t*)buffer)[seek_ptr] << 8) | ((uint8_t*)buffer)[seek_ptr + 1];
if (inc) seek_ptr += 2;
return true;
bool MsgPack::get_u16(const void* buffer, const bool inc, uint16_t* value) {
uint8_t byte;
if ((seek_ptr + 1) >= buffer_size) return false; // End of buffer
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_U16)) return false; // Value isn't a u16
*value = (((uint8_t*)buffer)[seek_ptr] << 8) | ((uint8_t*)buffer)[seek_ptr + 1];
if (inc) seek_ptr += 2;
return true;
}
bool MsgPack::get_s32(const void * buffer, const bool inc, int32_t * value) {
uint8_t byte;
if ((seek_ptr + 3) >= buffer_size) return false; // End of buffer
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_S32)) return false; // Value isn't a s32
*value = (((uint8_t*)buffer)[seek_ptr] << 24) | (((uint8_t*)buffer)[seek_ptr + 1] << 16) |
(((uint8_t*)buffer)[seek_ptr + 2] << 8) | ((uint8_t*)buffer)[seek_ptr + 3];
if (inc) seek_ptr += 4;
return true;
bool MsgPack::get_s32(const void* buffer, const bool inc, int32_t* value) {
uint8_t byte;
if ((seek_ptr + 3) >= buffer_size) return false; // End of buffer
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_S32)) return false; // Value isn't a s32
*value = (((uint8_t*)buffer)[seek_ptr] << 24) | (((uint8_t*)buffer)[seek_ptr + 1] << 16) |
(((uint8_t*)buffer)[seek_ptr + 2] << 8) | ((uint8_t*)buffer)[seek_ptr + 3];
if (inc) seek_ptr += 4;
return true;
}
bool MsgPack::get_string(const void * buffer, const bool inc, std::string& value) {
size_t length;
uint8_t byte;
// Todo: Set max length !
if ((seek_ptr + 3) >= buffer_size) return false; // End of buffer
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_STR8)
&& (byte != MSGPACK_TYPE_STR16)) return false; // Value isn't a str8 or str16
bool MsgPack::get_string(const void* buffer, const bool inc, std::string& value) {
size_t length;
uint8_t byte;
if (byte == MSGPACK_TYPE_STR8) {
if (!get_raw_byte(buffer, true, (uint8_t*)&length)) return false; // Couldn't get str8 length
} else if (byte == MSGPACK_TYPE_STR16) {
if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false; // Couldn't get str16 length
}
memcpy(&value[0], ((uint8_t*)buffer), length); //std::string(
// Todo: Set max length !
if ((seek_ptr + 3) >= buffer_size) return false; // End of buffer
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_STR8) && (byte != MSGPACK_TYPE_STR16)) return false; // Value isn't a str8 or str16
if (inc) seek_ptr += length;
return true;
if (byte == MSGPACK_TYPE_STR8) {
if (!get_raw_byte(buffer, true, (uint8_t*)&length)) return false; // Couldn't get str8 length
} else if (byte == MSGPACK_TYPE_STR16) {
if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false; // Couldn't get str16 length
}
memcpy(&value[0], ((uint8_t*)buffer), length); // std::string(
if (inc) seek_ptr += length;
return true;
}
bool MsgPack::init_search(const void * buffer, const size_t size) {
uint8_t byte;
uint16_t map_size;
if (!size) return false;
buffer_size = size;
seek_ptr = 0;
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_MAP16)) return false; // First record isn't a map16
if (!get_raw_word(buffer, true, &map_size)) return false; // Couldn't get map16 size
if (!map_size) return false;
return true;
bool MsgPack::init_search(const void* buffer, const size_t size) {
uint8_t byte;
uint16_t map_size;
if (!size) return false;
buffer_size = size;
seek_ptr = 0;
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_MAP16)) return false; // First record isn't a map16
if (!get_raw_word(buffer, true, &map_size)) return false; // Couldn't get map16 size
if (!map_size) return false;
return true;
}
bool MsgPack::skip(const void * buffer) {
uint8_t byte, c;
size_t length;
if (!get_raw_byte(buffer, true, &byte)) return false; // Couldn't get type
if (!(byte & 0x80)) return true; // Positive fixnum, already skipped by get_raw_byte
if ((byte & 0xE0) == 0xE0) return true; // Negative fixnum, already skipped by get_raw_byte
if ((byte & 0xE0) == 0xA0) { // Fixstr
seek_ptr += (byte & 0x1F);
return true;
}
if ((byte & 0xF0) == 0x80) { // Fixmap
length = (byte & 0x0F) * 2;
for (c = 0; c < length; c++)
skip(buffer);
return true;
}
if ((byte & 0xF0) == 0x90) { // Fixarray
length = byte & 0x0F;
for (c = 0; c < length; c++)
skip(buffer);
return true;
}
switch (byte) {
case MSGPACK_NIL:
case MSGPACK_FALSE:
case MSGPACK_TRUE: // Already skipped by get_raw_byte
break;
case MSGPACK_TYPE_U8:
case MSGPACK_TYPE_S8:
seek_ptr++;
break;
case MSGPACK_TYPE_U16:
case MSGPACK_TYPE_S16:
seek_ptr += 2;
break;
case MSGPACK_TYPE_U32:
case MSGPACK_TYPE_S32:
seek_ptr += 4;
break;
case MSGPACK_TYPE_U64:
case MSGPACK_TYPE_S64:
seek_ptr += 8;
break;
case MSGPACK_TYPE_STR8:
if (!get_raw_byte(buffer, true, (uint8_t*)&length)) return false; // Couldn't get str8 length
seek_ptr += length;
break;
case MSGPACK_TYPE_STR16:
if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false; // Couldn't get str16 length
seek_ptr += length;
break;
case MSGPACK_TYPE_ARR16:
if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false; // Couldn't get arr16 length
for (c = 0; c < length; c++)
skip(buffer);
break;
case MSGPACK_TYPE_MAP16:
if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false; // Couldn't get map16 length
for (c = 0; c < (length * 2); c++)
skip(buffer);
break;
default:
return false; // Type unsupported
}
return true;
bool MsgPack::skip(const void* buffer) {
uint8_t byte, c;
size_t length;
if (!get_raw_byte(buffer, true, &byte)) return false; // Couldn't get type
if (!(byte & 0x80)) return true; // Positive fixnum, already skipped by get_raw_byte
if ((byte & 0xE0) == 0xE0) return true; // Negative fixnum, already skipped by get_raw_byte
if ((byte & 0xE0) == 0xA0) { // Fixstr
seek_ptr += (byte & 0x1F);
return true;
}
if ((byte & 0xF0) == 0x80) { // Fixmap
length = (byte & 0x0F) * 2;
for (c = 0; c < length; c++)
skip(buffer);
return true;
}
if ((byte & 0xF0) == 0x90) { // Fixarray
length = byte & 0x0F;
for (c = 0; c < length; c++)
skip(buffer);
return true;
}
switch (byte) {
case MSGPACK_NIL:
case MSGPACK_FALSE:
case MSGPACK_TRUE: // Already skipped by get_raw_byte
break;
case MSGPACK_TYPE_U8:
case MSGPACK_TYPE_S8:
seek_ptr++;
break;
case MSGPACK_TYPE_U16:
case MSGPACK_TYPE_S16:
seek_ptr += 2;
break;
case MSGPACK_TYPE_U32:
case MSGPACK_TYPE_S32:
seek_ptr += 4;
break;
case MSGPACK_TYPE_U64:
case MSGPACK_TYPE_S64:
seek_ptr += 8;
break;
case MSGPACK_TYPE_STR8:
if (!get_raw_byte(buffer, true, (uint8_t*)&length)) return false; // Couldn't get str8 length
seek_ptr += length;
break;
case MSGPACK_TYPE_STR16:
if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false; // Couldn't get str16 length
seek_ptr += length;
break;
case MSGPACK_TYPE_ARR16:
if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false; // Couldn't get arr16 length
for (c = 0; c < length; c++)
skip(buffer);
break;
case MSGPACK_TYPE_MAP16:
if (!get_raw_word(buffer, true, (uint16_t*)&length)) return false; // Couldn't get map16 length
for (c = 0; c < (length * 2); c++)
skip(buffer);
break;
default:
return false; // Type unsupported
}
return true;
}
bool MsgPack::search_key(const void * buffer, const MsgPack::RecID record_id) {
uint8_t byte;
uint16_t key;
while (get_raw_byte(buffer, false, &byte)) {
if (!get_u16(buffer, true, &key)) return false; // Couldn't get key
if (key == record_id) return true; // Found record
if (!skip(buffer)) return false; // Can't skip to next key
};
return false;
bool MsgPack::search_key(const void* buffer, const MsgPack::RecID record_id) {
uint8_t byte;
uint16_t key;
while (get_raw_byte(buffer, false, &byte)) {
if (!get_u16(buffer, true, &key)) return false; // Couldn't get key
if (key == record_id) return true; // Found record
if (!skip(buffer)) return false; // Can't skip to next key
};
return false;
}
bool MsgPack::msgpack_get(const void * buffer, const size_t size, const RecID record_id, bool * value) {
init_search(buffer, size);
if (!search_key(buffer, record_id)) return false; // Record not found
if (!get_bool(buffer, false, value)) return false; // Value isn't a bool
return true;
bool MsgPack::msgpack_get(const void* buffer, const size_t size, const RecID record_id, bool* value) {
init_search(buffer, size);
if (!search_key(buffer, record_id)) return false; // Record not found
if (!get_bool(buffer, false, value)) return false; // Value isn't a bool
return true;
}
bool MsgPack::msgpack_get(const void * buffer, const size_t size, const RecID record_id, uint8_t * value) {
if (!init_search(buffer, size)) return false;
if (!search_key(buffer, record_id)) return false; // Record not found
if (!get_u8(buffer, false, value)) return false; // Value isn't a u8
return true;
bool MsgPack::msgpack_get(const void* buffer, const size_t size, const RecID record_id, uint8_t* value) {
if (!init_search(buffer, size)) return false;
if (!search_key(buffer, record_id)) return false; // Record not found
if (!get_u8(buffer, false, value)) return false; // Value isn't a u8
return true;
}
bool MsgPack::msgpack_get(const void * buffer, const size_t size, const RecID record_id, int64_t * value) {
uint8_t byte;
init_search(buffer, size);
if (!search_key(buffer, record_id)) return false; // Record not found
if ((seek_ptr + 3) >= buffer_size) return false; // End of buffer
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_S64)) return false; // Value isn't a s64
*value = ((int64_t)((uint8_t*)buffer)[seek_ptr] << 56) | ((int64_t)((uint8_t*)buffer)[seek_ptr + 1] << 48) |
((int64_t)((uint8_t*)buffer)[seek_ptr + 2] << 40) | ((int64_t)((uint8_t*)buffer)[seek_ptr + 3] << 32) |
(((uint8_t*)buffer)[seek_ptr + 4] << 24) | (((uint8_t*)buffer)[seek_ptr + 5] << 16) |
(((uint8_t*)buffer)[seek_ptr + 6] << 8) | ((uint8_t*)buffer)[seek_ptr + 7];
return true;
bool MsgPack::msgpack_get(const void* buffer, const size_t size, const RecID record_id, int64_t* value) {
uint8_t byte;
init_search(buffer, size);
if (!search_key(buffer, record_id)) return false; // Record not found
if ((seek_ptr + 3) >= buffer_size) return false; // End of buffer
if ((get_raw_byte(buffer, true, &byte)) && (byte != MSGPACK_TYPE_S64)) return false; // Value isn't a s64
*value = ((int64_t)((uint8_t*)buffer)[seek_ptr] << 56) | ((int64_t)((uint8_t*)buffer)[seek_ptr + 1] << 48) |
((int64_t)((uint8_t*)buffer)[seek_ptr + 2] << 40) | ((int64_t)((uint8_t*)buffer)[seek_ptr + 3] << 32) |
(((uint8_t*)buffer)[seek_ptr + 4] << 24) | (((uint8_t*)buffer)[seek_ptr + 5] << 16) |
(((uint8_t*)buffer)[seek_ptr + 6] << 8) | ((uint8_t*)buffer)[seek_ptr + 7];
return true;
}
bool MsgPack::msgpack_get(const void * buffer, const size_t size, const RecID record_id, std::string& value) {
init_search(buffer, size);
if (!search_key(buffer, record_id)) return false; // Record not found
if (!get_string(buffer, false, value)) return false; // Value isn't a char array
return true;
bool MsgPack::msgpack_get(const void* buffer, const size_t size, const RecID record_id, std::string& value) {
init_search(buffer, size);
if (!search_key(buffer, record_id)) return false; // Record not found
if (!get_string(buffer, false, value)) return false; // Value isn't a char array
return true;
}
void MsgPack::msgpack_init(const void* buffer, size_t* ptr) {
((uint8_t*)buffer)[0] = MSGPACK_TYPE_MAP16;
((uint8_t*)buffer)[1] = 0;
((uint8_t*)buffer)[2] = 0;
void MsgPack::msgpack_init(const void * buffer, size_t * ptr) {
((uint8_t*)buffer)[0] = MSGPACK_TYPE_MAP16;
((uint8_t*)buffer)[1] = 0;
((uint8_t*)buffer)[2] = 0;
*ptr = 3;
*ptr = 3;
}
void MsgPack::add_key(const void * buffer, size_t * ptr, const RecID record_id) {
uint16_t key;
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_U16;
((uint8_t*)buffer)[(*ptr)++] = record_id >> 8;
((uint8_t*)buffer)[(*ptr)++] = record_id & 0xFF;
// Auto-inc MAP16 size which should be at the beginning of the buffer
key = (((uint8_t*)buffer)[1] << 8) | ((uint8_t*)buffer)[2];
key++;
((uint8_t*)buffer)[1] = key >> 8;
((uint8_t*)buffer)[2] = key & 0xFF;
void MsgPack::add_key(const void* buffer, size_t* ptr, const RecID record_id) {
uint16_t key;
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_U16;
((uint8_t*)buffer)[(*ptr)++] = record_id >> 8;
((uint8_t*)buffer)[(*ptr)++] = record_id & 0xFF;
// Auto-inc MAP16 size which should be at the beginning of the buffer
key = (((uint8_t*)buffer)[1] << 8) | ((uint8_t*)buffer)[2];
key++;
((uint8_t*)buffer)[1] = key >> 8;
((uint8_t*)buffer)[2] = key & 0xFF;
}
void MsgPack::msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, bool value) {
add_key(buffer, ptr, record_id);
if (value)
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TRUE;
else
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_FALSE;
void MsgPack::msgpack_add(const void* buffer, size_t* ptr, const RecID record_id, bool value) {
add_key(buffer, ptr, record_id);
if (value)
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TRUE;
else
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_FALSE;
}
void MsgPack::msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, uint8_t value) {
add_key(buffer, ptr, record_id);
if (value < 128) {
((uint8_t*)buffer)[(*ptr)++] = value;
} else {
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_U8;
((uint8_t*)buffer)[(*ptr)++] = value;
}
void MsgPack::msgpack_add(const void* buffer, size_t* ptr, const RecID record_id, uint8_t value) {
add_key(buffer, ptr, record_id);
if (value < 128) {
((uint8_t*)buffer)[(*ptr)++] = value;
} else {
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_U8;
((uint8_t*)buffer)[(*ptr)++] = value;
}
}
void MsgPack::msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, int64_t value) {
uint8_t c;
add_key(buffer, ptr, record_id);
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_S64;
for (c = 0; c < 8; c++)
((uint8_t*)buffer)[(*ptr)++] = (value >> (8 * (7 - c))) & 0xFF;
void MsgPack::msgpack_add(const void* buffer, size_t* ptr, const RecID record_id, int64_t value) {
uint8_t c;
add_key(buffer, ptr, record_id);
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_S64;
for (c = 0; c < 8; c++)
((uint8_t*)buffer)[(*ptr)++] = (value >> (8 * (7 - c))) & 0xFF;
}
bool MsgPack::msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, std::string value) {
uint8_t c;
size_t length;
add_key(buffer, ptr, record_id);
length = value.size();
if (length < 32) {
((uint8_t*)buffer)[(*ptr)++] = length | 0xA0; // Fixstr
} else if ((length >= 32) && (length < 256)) {
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_STR8;
((uint8_t*)buffer)[(*ptr)++] = length;
} else if ((length >= 256) && (length < 65536)) {
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_STR16;
((uint8_t*)buffer)[(*ptr)++] = length >> 8;
((uint8_t*)buffer)[(*ptr)++] = length & 0xFF;
} else {
return false;
}
for (c = 0; c < length; c++)
((uint8_t*)buffer)[(*ptr)++] = value[c];
return true;
bool MsgPack::msgpack_add(const void* buffer, size_t* ptr, const RecID record_id, std::string value) {
uint8_t c;
size_t length;
add_key(buffer, ptr, record_id);
length = value.size();
if (length < 32) {
((uint8_t*)buffer)[(*ptr)++] = length | 0xA0; // Fixstr
} else if ((length >= 32) && (length < 256)) {
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_STR8;
((uint8_t*)buffer)[(*ptr)++] = length;
} else if ((length >= 256) && (length < 65536)) {
((uint8_t*)buffer)[(*ptr)++] = MSGPACK_TYPE_STR16;
((uint8_t*)buffer)[(*ptr)++] = length >> 8;
((uint8_t*)buffer)[(*ptr)++] = length & 0xFF;
} else {
return false;
}
for (c = 0; c < length; c++)
((uint8_t*)buffer)[(*ptr)++] = value[c];
return true;
}

View File

@@ -1,7 +1,7 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2016 Furrtek
*
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
@@ -27,75 +27,74 @@
#include <memory>
#include <cstring>
#define MSGPACK_NIL 0xC0
#define MSGPACK_NIL 0xC0
#define MSGPACK_FALSE 0xC2
#define MSGPACK_TRUE 0xC3
#define MSGPACK_FALSE 0xC2
#define MSGPACK_TRUE 0xC3
#define MSGPACK_TYPE_F32 0xCA
#define MSGPACK_TYPE_F64 0xCB
#define MSGPACK_TYPE_F32 0xCA
#define MSGPACK_TYPE_F64 0xCB
#define MSGPACK_TYPE_U8 0xCC
#define MSGPACK_TYPE_U16 0xCD
#define MSGPACK_TYPE_U32 0xCE
#define MSGPACK_TYPE_U64 0xCF
#define MSGPACK_TYPE_U8 0xCC
#define MSGPACK_TYPE_U16 0xCD
#define MSGPACK_TYPE_U32 0xCE
#define MSGPACK_TYPE_U64 0xCF
#define MSGPACK_TYPE_S8 0xD0
#define MSGPACK_TYPE_S16 0xD1
#define MSGPACK_TYPE_S32 0xD2
#define MSGPACK_TYPE_S64 0xD3
#define MSGPACK_TYPE_S8 0xD0
#define MSGPACK_TYPE_S16 0xD1
#define MSGPACK_TYPE_S32 0xD2
#define MSGPACK_TYPE_S64 0xD3
#define MSGPACK_TYPE_STR8 0xD9
#define MSGPACK_TYPE_STR16 0xDA
#define MSGPACK_TYPE_STR32 0xDB
#define MSGPACK_TYPE_STR8 0xD9
#define MSGPACK_TYPE_STR16 0xDA
#define MSGPACK_TYPE_STR32 0xDB
#define MSGPACK_TYPE_ARR16 0xDC
#define MSGPACK_TYPE_ARR32 0xDD
#define MSGPACK_TYPE_ARR16 0xDC
#define MSGPACK_TYPE_ARR32 0xDD
#define MSGPACK_TYPE_MAP16 0xDE
#define MSGPACK_TYPE_MAP32 0xDF
#define MSGPACK_TYPE_MAP16 0xDE
#define MSGPACK_TYPE_MAP32 0xDF
class MsgPack {
public:
public:
enum RecID {
TestListA = 0,
TestListB = 1,
TestListC = 2,
TestListD = 3,
TestListE = 4
};
enum RecID {
TestListA = 0,
TestListB = 1,
TestListC = 2,
TestListD = 3,
TestListE = 4
};
// Read
bool msgpack_get(const void* buffer, const size_t size, const RecID record_id, bool* value);
bool msgpack_get(const void* buffer, const size_t size, const RecID record_id, uint8_t* value);
bool msgpack_get(const void* buffer, const size_t size, const RecID record_id, int64_t* value);
bool msgpack_get(const void* buffer, const size_t size, const RecID record_id, std::string& value);
// Read
bool msgpack_get(const void * buffer, const size_t size, const RecID record_id, bool * value);
bool msgpack_get(const void * buffer, const size_t size, const RecID record_id, uint8_t * value);
bool msgpack_get(const void * buffer, const size_t size, const RecID record_id, int64_t * value);
bool msgpack_get(const void * buffer, const size_t size, const RecID record_id, std::string& value);
// Write
void msgpack_init(const void * buffer, size_t * ptr);
void msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, bool value);
void msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, uint8_t value);
void msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, int64_t value);
bool msgpack_add(const void * buffer, size_t * ptr, const RecID record_id, std::string value);
// Write
void msgpack_init(const void* buffer, size_t* ptr);
void msgpack_add(const void* buffer, size_t* ptr, const RecID record_id, bool value);
void msgpack_add(const void* buffer, size_t* ptr, const RecID record_id, uint8_t value);
void msgpack_add(const void* buffer, size_t* ptr, const RecID record_id, int64_t value);
bool msgpack_add(const void* buffer, size_t* ptr, const RecID record_id, std::string value);
private:
bool get_raw_byte(const void * buffer, const bool inc, uint8_t * byte);
bool get_raw_word(const void * buffer, const bool inc, uint16_t * word);
bool get_bool(const void * buffer, const bool inc, bool * value);
bool get_u8(const void * buffer, const bool inc, uint8_t * value);
bool get_u16(const void * buffer, const bool inc, uint16_t * value);
bool get_s32(const void * buffer, const bool inc, int32_t * value);
bool get_string(const void * buffer, const bool inc, std::string& value);
void add_key(const void * buffer, size_t * ptr, const RecID record_id);
bool init_search(const void * buffer, const size_t size);
bool search_key(const void * buffer, const RecID record_id);
bool skip(const void * buffer);
size_t seek_ptr = 0;
size_t buffer_size;
private:
bool get_raw_byte(const void* buffer, const bool inc, uint8_t* byte);
bool get_raw_word(const void* buffer, const bool inc, uint16_t* word);
bool get_bool(const void* buffer, const bool inc, bool* value);
bool get_u8(const void* buffer, const bool inc, uint8_t* value);
bool get_u16(const void* buffer, const bool inc, uint16_t* value);
bool get_s32(const void* buffer, const bool inc, int32_t* value);
bool get_string(const void* buffer, const bool inc, std::string& value);
void add_key(const void* buffer, size_t* ptr, const RecID record_id);
bool init_search(const void* buffer, const size_t size);
bool search_key(const void* buffer, const RecID record_id);
bool skip(const void* buffer);
size_t seek_ptr = 0;
size_t buffer_size;
};
#endif

View File

@@ -24,19 +24,22 @@
#include <utility>
template<typename T>
template <typename T>
class Optional {
public:
constexpr Optional() : value_ { }, valid_ { false } { };
constexpr Optional(const T& value) : value_ { value }, valid_ { true } { };
constexpr Optional(T&& value) : value_ { std::move(value) }, valid_ { true } { };
public:
constexpr Optional()
: value_{}, valid_{false} {};
constexpr Optional(const T& value)
: value_{value}, valid_{true} {};
constexpr Optional(T&& value)
: value_{std::move(value)}, valid_{true} {};
bool is_valid() const { return valid_; };
T value() const { return value_; };
bool is_valid() const { return valid_; };
T value() const { return value_; };
private:
T value_;
bool valid_;
private:
T value_;
bool valid_;
};
#endif/*__OPTIONAL_H__*/
#endif /*__OPTIONAL_H__*/

View File

@@ -23,35 +23,35 @@
#include "ch.h"
uint8_t get_cpu_utilisation_in_percent() {
static systime_t last_time = 0;
static systime_t last_idle_ticks = 0;
static systime_t last_time = 0;
static systime_t last_idle_ticks = 0;
auto now = chTimeNow();
auto idle_ticks = chThdGetTicks(chSysGetIdleThread());
auto now = chTimeNow();
auto idle_ticks = chThdGetTicks(chSysGetIdleThread());
if (last_time == 0) {
last_time = now;
last_idle_ticks = idle_ticks;
if (last_time == 0) {
last_time = now;
last_idle_ticks = idle_ticks;
return 0;
}
return 0;
}
int32_t time_elapsed = now - last_time;
int32_t idle_elapsed = idle_ticks - last_idle_ticks;
int32_t time_elapsed = now - last_time;
int32_t idle_elapsed = idle_ticks - last_idle_ticks;
int32_t working_ticks = time_elapsed - idle_elapsed;
int32_t working_ticks = time_elapsed - idle_elapsed;
if (working_ticks < 0)
working_ticks = 0;
if (working_ticks < 0)
working_ticks = 0;
auto utilisation = working_ticks * 100 / time_elapsed;
auto utilisation = working_ticks * 100 / time_elapsed;
last_time = now;
last_idle_ticks = idle_ticks;
last_time = now;
last_idle_ticks = idle_ticks;
if (utilisation > 100) {
return 100;
}
if (utilisation > 100) {
return 100;
}
return (uint8_t) utilisation;
return (uint8_t)utilisation;
}

View File

@@ -27,207 +27,353 @@
namespace lpc43xx {
enum Pins {
P0_0, P0_1,
P1_0, P1_1, P1_2, P1_3, P1_4, P1_5, P1_6, P1_7, P1_8, P1_9, P1_10, P1_11, P1_12, P1_13, P1_14, P1_15, P1_16, P1_17, P1_18, P1_19, P1_20,
P2_0, P2_1, P2_2, P2_3, P2_4, P2_5, P2_6, P2_7, P2_8, P2_9, P2_10, P2_11, P2_12, P2_13,
P3_0, P3_1, P3_2,
P4_0, P4_1, P4_2, P4_3, P4_4, P4_5, P4_6, P4_7, P4_8, P4_9, P4_10,
P5_0, P5_1, P5_2, P5_3, P5_4, P5_5, P5_6, P5_7,
P6_0, P6_1, P6_2, P6_3, P6_4, P6_5, P6_6, P6_7, P6_8, P6_9, P6_10, P6_11, P6_12,
P7_0, P7_1, P7_2, P7_3, P7_4, P7_5, P7_6, P7_7,
P9_5, P9_6,
PF_4,
CLK0, CLK2,
P0_0,
P0_1,
P1_0,
P1_1,
P1_2,
P1_3,
P1_4,
P1_5,
P1_6,
P1_7,
P1_8,
P1_9,
P1_10,
P1_11,
P1_12,
P1_13,
P1_14,
P1_15,
P1_16,
P1_17,
P1_18,
P1_19,
P1_20,
P2_0,
P2_1,
P2_2,
P2_3,
P2_4,
P2_5,
P2_6,
P2_7,
P2_8,
P2_9,
P2_10,
P2_11,
P2_12,
P2_13,
P3_0,
P3_1,
P3_2,
P4_0,
P4_1,
P4_2,
P4_3,
P4_4,
P4_5,
P4_6,
P4_7,
P4_8,
P4_9,
P4_10,
P5_0,
P5_1,
P5_2,
P5_3,
P5_4,
P5_5,
P5_6,
P5_7,
P6_0,
P6_1,
P6_2,
P6_3,
P6_4,
P6_5,
P6_6,
P6_7,
P6_8,
P6_9,
P6_10,
P6_11,
P6_12,
P7_0,
P7_1,
P7_2,
P7_3,
P7_4,
P7_5,
P7_6,
P7_7,
P9_5,
P9_6,
PF_4,
CLK0,
CLK2,
};
constexpr Pin pins[] {
[P0_0] = { 0, 0},
[P0_1] = { 0, 1},
[P1_0] = { 1, 0},
[P1_1] = { 1, 1},
[P1_2] = { 1, 2},
[P1_3] = { 1, 3},
[P1_4] = { 1, 4},
[P1_5] = { 1, 5},
[P1_6] = { 1, 6},
[P1_7] = { 1, 7},
[P1_8] = { 1, 8},
[P1_9] = { 1, 9},
[P1_10] = { 1, 10},
[P1_11] = { 1, 11},
[P1_12] = { 1, 12},
[P1_13] = { 1, 13},
[P1_14] = { 1, 14},
[P1_15] = { 1, 15},
[P1_16] = { 1, 16},
[P1_17] = { 1, 17},
[P1_18] = { 1, 18},
[P1_19] = { 1, 19},
[P1_20] = { 1, 20},
[P2_0] = { 2, 0},
[P2_1] = { 2, 1},
[P2_2] = { 2, 2},
[P2_3] = { 2, 3},
[P2_4] = { 2, 4},
[P2_5] = { 2, 5},
[P2_6] = { 2, 6},
[P2_7] = { 2, 7},
[P2_8] = { 2, 8},
[P2_9] = { 2, 9},
[P2_10] = { 2, 10},
[P2_11] = { 2, 11},
[P2_12] = { 2, 12},
[P2_13] = { 2, 13},
[P3_0] = { 3, 0},
[P3_1] = { 3, 1},
[P3_2] = { 3, 2},
[P4_0] = { 4, 0},
[P4_1] = { 4, 1},
[P4_2] = { 4, 2},
[P4_3] = { 4, 3},
[P4_4] = { 4, 4},
[P4_5] = { 4, 5},
[P4_6] = { 4, 6},
[P4_7] = { 4, 7},
[P4_8] = { 4, 8},
[P4_9] = { 4, 9},
[P4_10] = { 4, 10},
[P5_0] = { 5, 0},
[P5_1] = { 5, 1},
[P5_2] = { 5, 2},
[P5_3] = { 5, 3},
[P5_4] = { 5, 4},
[P5_5] = { 5, 5},
[P5_6] = { 5, 6},
[P5_7] = { 5, 7},
[P6_0] = { 6, 0},
[P6_1] = { 6, 1},
[P6_2] = { 6, 2},
[P6_3] = { 6, 3},
[P6_4] = { 6, 4},
[P6_5] = { 6, 5},
[P6_6] = { 6, 6},
[P6_7] = { 6, 7},
[P6_8] = { 6, 8},
[P6_9] = { 6, 9},
[P6_10] = { 6, 10},
[P6_11] = { 6, 11},
[P6_12] = { 6, 12},
[P7_0] = { 7, 0},
[P7_1] = { 7, 1},
[P7_2] = { 7, 2},
[P7_3] = { 7, 3},
[P7_4] = { 7, 4},
[P7_5] = { 7, 5},
[P7_6] = { 7, 6},
[P7_7] = { 7, 7},
[P9_5] = { 9, 5},
[P9_6] = { 9, 6},
[PF_4] = { 15, 4},
[CLK0] = { 24, 0},
[CLK2] = { 24, 2},
constexpr Pin pins[]{
[P0_0] = {0, 0},
[P0_1] = {0, 1},
[P1_0] = {1, 0},
[P1_1] = {1, 1},
[P1_2] = {1, 2},
[P1_3] = {1, 3},
[P1_4] = {1, 4},
[P1_5] = {1, 5},
[P1_6] = {1, 6},
[P1_7] = {1, 7},
[P1_8] = {1, 8},
[P1_9] = {1, 9},
[P1_10] = {1, 10},
[P1_11] = {1, 11},
[P1_12] = {1, 12},
[P1_13] = {1, 13},
[P1_14] = {1, 14},
[P1_15] = {1, 15},
[P1_16] = {1, 16},
[P1_17] = {1, 17},
[P1_18] = {1, 18},
[P1_19] = {1, 19},
[P1_20] = {1, 20},
[P2_0] = {2, 0},
[P2_1] = {2, 1},
[P2_2] = {2, 2},
[P2_3] = {2, 3},
[P2_4] = {2, 4},
[P2_5] = {2, 5},
[P2_6] = {2, 6},
[P2_7] = {2, 7},
[P2_8] = {2, 8},
[P2_9] = {2, 9},
[P2_10] = {2, 10},
[P2_11] = {2, 11},
[P2_12] = {2, 12},
[P2_13] = {2, 13},
[P3_0] = {3, 0},
[P3_1] = {3, 1},
[P3_2] = {3, 2},
[P4_0] = {4, 0},
[P4_1] = {4, 1},
[P4_2] = {4, 2},
[P4_3] = {4, 3},
[P4_4] = {4, 4},
[P4_5] = {4, 5},
[P4_6] = {4, 6},
[P4_7] = {4, 7},
[P4_8] = {4, 8},
[P4_9] = {4, 9},
[P4_10] = {4, 10},
[P5_0] = {5, 0},
[P5_1] = {5, 1},
[P5_2] = {5, 2},
[P5_3] = {5, 3},
[P5_4] = {5, 4},
[P5_5] = {5, 5},
[P5_6] = {5, 6},
[P5_7] = {5, 7},
[P6_0] = {6, 0},
[P6_1] = {6, 1},
[P6_2] = {6, 2},
[P6_3] = {6, 3},
[P6_4] = {6, 4},
[P6_5] = {6, 5},
[P6_6] = {6, 6},
[P6_7] = {6, 7},
[P6_8] = {6, 8},
[P6_9] = {6, 9},
[P6_10] = {6, 10},
[P6_11] = {6, 11},
[P6_12] = {6, 12},
[P7_0] = {7, 0},
[P7_1] = {7, 1},
[P7_2] = {7, 2},
[P7_3] = {7, 3},
[P7_4] = {7, 4},
[P7_5] = {7, 5},
[P7_6] = {7, 6},
[P7_7] = {7, 7},
[P9_5] = {9, 5},
[P9_6] = {9, 6},
[PF_4] = {15, 4},
[CLK0] = {24, 0},
[CLK2] = {24, 2},
};
enum GPIOs {
GPIO0_0, GPIO0_1, GPIO0_2, GPIO0_3, GPIO0_4, GPIO0_5, /*GPIO0_6,*/ GPIO0_7, GPIO0_8, GPIO0_9, GPIO0_10, GPIO0_11, GPIO0_12, GPIO0_13, GPIO0_14, GPIO0_15,
GPIO1_0, GPIO1_1, GPIO1_2, GPIO1_3, GPIO1_4, GPIO1_5, GPIO1_6, GPIO1_7, GPIO1_8, GPIO1_9, GPIO1_10, GPIO1_11, GPIO1_12, GPIO1_13, /*GPIO1_14, GPIO1_15,*/
GPIO2_0, GPIO2_1, GPIO2_2, GPIO2_3, GPIO2_4, GPIO2_5, GPIO2_6, GPIO2_7, GPIO2_8, GPIO2_9, GPIO2_10, GPIO2_11, GPIO2_12, GPIO2_13, GPIO2_14, GPIO2_15,
GPIO3_0, GPIO3_1, GPIO3_2, GPIO3_3, GPIO3_4, GPIO3_5, GPIO3_6, GPIO3_7, GPIO3_8, GPIO3_9, GPIO3_10, GPIO3_11, GPIO3_12, GPIO3_13, GPIO3_14, GPIO3_15,
GPIO4_11,
GPIO5_0, GPIO5_1, GPIO5_2, GPIO5_3, GPIO5_4, GPIO5_5, GPIO5_6, GPIO5_7, GPIO5_8, GPIO5_9, /*GPIO5_10, GPIO5_11,*/ GPIO5_12, GPIO5_13, GPIO5_14, GPIO5_15, GPIO5_16, GPIO5_18,
GPIO0_0,
GPIO0_1,
GPIO0_2,
GPIO0_3,
GPIO0_4,
GPIO0_5,
/*GPIO0_6,*/ GPIO0_7,
GPIO0_8,
GPIO0_9,
GPIO0_10,
GPIO0_11,
GPIO0_12,
GPIO0_13,
GPIO0_14,
GPIO0_15,
GPIO1_0,
GPIO1_1,
GPIO1_2,
GPIO1_3,
GPIO1_4,
GPIO1_5,
GPIO1_6,
GPIO1_7,
GPIO1_8,
GPIO1_9,
GPIO1_10,
GPIO1_11,
GPIO1_12,
GPIO1_13, /*GPIO1_14, GPIO1_15,*/
GPIO2_0,
GPIO2_1,
GPIO2_2,
GPIO2_3,
GPIO2_4,
GPIO2_5,
GPIO2_6,
GPIO2_7,
GPIO2_8,
GPIO2_9,
GPIO2_10,
GPIO2_11,
GPIO2_12,
GPIO2_13,
GPIO2_14,
GPIO2_15,
GPIO3_0,
GPIO3_1,
GPIO3_2,
GPIO3_3,
GPIO3_4,
GPIO3_5,
GPIO3_6,
GPIO3_7,
GPIO3_8,
GPIO3_9,
GPIO3_10,
GPIO3_11,
GPIO3_12,
GPIO3_13,
GPIO3_14,
GPIO3_15,
GPIO4_11,
GPIO5_0,
GPIO5_1,
GPIO5_2,
GPIO5_3,
GPIO5_4,
GPIO5_5,
GPIO5_6,
GPIO5_7,
GPIO5_8,
GPIO5_9,
/*GPIO5_10, GPIO5_11,*/ GPIO5_12,
GPIO5_13,
GPIO5_14,
GPIO5_15,
GPIO5_16,
GPIO5_18,
};
constexpr GPIO gpio[] = {
[GPIO0_0] = { pins[P0_0], 0, 0, 0 },
[GPIO0_1] = { pins[P0_1], 0, 1, 0 },
[GPIO0_2] = { pins[P1_15], 0, 2, 0 },
[GPIO0_3] = { pins[P1_16], 0, 3, 0 },
[GPIO0_4] = { pins[P1_0], 0, 4, 0 },
[GPIO0_5] = { pins[P6_6], 0, 5, 0 },
//[GPIO0_6] = { pins[P3_6], 0, 6, 0 },
[GPIO0_7] = { pins[P2_7], 0, 7, 0 },
[GPIO0_8] = { pins[P1_1], 0, 8, 0 },
[GPIO0_9] = { pins[P1_2], 0, 9, 0 },
[GPIO0_10] = { pins[P1_3], 0, 10, 0 },
[GPIO0_11] = { pins[P1_4], 0, 11, 0 },
[GPIO0_12] = { pins[P1_17], 0, 12, 0 },
[GPIO0_13] = { pins[P1_18], 0, 13, 0 },
[GPIO0_14] = { pins[P2_10], 0, 14, 0 },
[GPIO0_15] = { pins[P1_20], 0, 15, 0 },
[GPIO0_0] = {pins[P0_0], 0, 0, 0},
[GPIO0_1] = {pins[P0_1], 0, 1, 0},
[GPIO0_2] = {pins[P1_15], 0, 2, 0},
[GPIO0_3] = {pins[P1_16], 0, 3, 0},
[GPIO0_4] = {pins[P1_0], 0, 4, 0},
[GPIO0_5] = {pins[P6_6], 0, 5, 0},
//[GPIO0_6] = { pins[P3_6], 0, 6, 0 },
[GPIO0_7] = {pins[P2_7], 0, 7, 0},
[GPIO0_8] = {pins[P1_1], 0, 8, 0},
[GPIO0_9] = {pins[P1_2], 0, 9, 0},
[GPIO0_10] = {pins[P1_3], 0, 10, 0},
[GPIO0_11] = {pins[P1_4], 0, 11, 0},
[GPIO0_12] = {pins[P1_17], 0, 12, 0},
[GPIO0_13] = {pins[P1_18], 0, 13, 0},
[GPIO0_14] = {pins[P2_10], 0, 14, 0},
[GPIO0_15] = {pins[P1_20], 0, 15, 0},
[GPIO1_0] = { pins[P1_7], 1, 0, 0 },
[GPIO1_1] = { pins[P1_8], 1, 1, 0 },
[GPIO1_2] = { pins[P1_9], 1, 2, 0 },
[GPIO1_3] = { pins[P1_10], 1, 3, 0 },
[GPIO1_4] = { pins[P1_11], 1, 4, 0 },
[GPIO1_5] = { pins[P1_12], 1, 5, 0 },
[GPIO1_6] = { pins[P1_13], 1, 6, 0 },
[GPIO1_7] = { pins[P1_14], 1, 7, 0 },
[GPIO1_8] = { pins[P1_5], 1, 8, 0 },
[GPIO1_9] = { pins[P1_6], 1, 9, 0 },
[GPIO1_10] = { pins[P2_9], 1, 10, 0 },
[GPIO1_11] = { pins[P2_11], 1, 11, 0 },
[GPIO1_12] = { pins[P2_12], 1, 12, 0 },
[GPIO1_13] = { pins[P2_13], 1, 13, 0 },
//[GPIO1_14] = { pins[P3_4], 1, 14, 0 },
//[GPIO1_15] = { pins[P3_5], 1, 15, 0 },
[GPIO1_0] = {pins[P1_7], 1, 0, 0},
[GPIO1_1] = {pins[P1_8], 1, 1, 0},
[GPIO1_2] = {pins[P1_9], 1, 2, 0},
[GPIO1_3] = {pins[P1_10], 1, 3, 0},
[GPIO1_4] = {pins[P1_11], 1, 4, 0},
[GPIO1_5] = {pins[P1_12], 1, 5, 0},
[GPIO1_6] = {pins[P1_13], 1, 6, 0},
[GPIO1_7] = {pins[P1_14], 1, 7, 0},
[GPIO1_8] = {pins[P1_5], 1, 8, 0},
[GPIO1_9] = {pins[P1_6], 1, 9, 0},
[GPIO1_10] = {pins[P2_9], 1, 10, 0},
[GPIO1_11] = {pins[P2_11], 1, 11, 0},
[GPIO1_12] = {pins[P2_12], 1, 12, 0},
[GPIO1_13] = {pins[P2_13], 1, 13, 0},
//[GPIO1_14] = { pins[P3_4], 1, 14, 0 },
//[GPIO1_15] = { pins[P3_5], 1, 15, 0 },
[GPIO2_0] = { pins[P4_0], 2, 0, 0 },
[GPIO2_1] = { pins[P4_1], 2, 1, 0 },
[GPIO2_2] = { pins[P4_2], 2, 2, 0 },
[GPIO2_3] = { pins[P4_3], 2, 3, 0 },
[GPIO2_4] = { pins[P4_4], 2, 4, 0 },
[GPIO2_5] = { pins[P4_5], 2, 5, 0 },
[GPIO2_6] = { pins[P4_6], 2, 6, 0 },
[GPIO2_7] = { pins[P5_7], 2, 7, 0 },
[GPIO2_8] = { pins[P6_12], 2, 8, 0 },
[GPIO2_9] = { pins[P5_0], 2, 9, 0 },
[GPIO2_10] = { pins[P5_1], 2, 10, 0 },
[GPIO2_11] = { pins[P5_2], 2, 11, 0 },
[GPIO2_12] = { pins[P5_3], 2, 12, 0 },
[GPIO2_13] = { pins[P5_4], 2, 13, 0 },
[GPIO2_14] = { pins[P5_5], 2, 14, 0 },
[GPIO2_15] = { pins[P5_6], 2, 15, 0 },
[GPIO2_0] = {pins[P4_0], 2, 0, 0},
[GPIO2_1] = {pins[P4_1], 2, 1, 0},
[GPIO2_2] = {pins[P4_2], 2, 2, 0},
[GPIO2_3] = {pins[P4_3], 2, 3, 0},
[GPIO2_4] = {pins[P4_4], 2, 4, 0},
[GPIO2_5] = {pins[P4_5], 2, 5, 0},
[GPIO2_6] = {pins[P4_6], 2, 6, 0},
[GPIO2_7] = {pins[P5_7], 2, 7, 0},
[GPIO2_8] = {pins[P6_12], 2, 8, 0},
[GPIO2_9] = {pins[P5_0], 2, 9, 0},
[GPIO2_10] = {pins[P5_1], 2, 10, 0},
[GPIO2_11] = {pins[P5_2], 2, 11, 0},
[GPIO2_12] = {pins[P5_3], 2, 12, 0},
[GPIO2_13] = {pins[P5_4], 2, 13, 0},
[GPIO2_14] = {pins[P5_5], 2, 14, 0},
[GPIO2_15] = {pins[P5_6], 2, 15, 0},
[GPIO3_0] = { pins[P6_1], 3, 0, 0 },
[GPIO3_1] = { pins[P6_2], 3, 1, 0 },
[GPIO3_2] = { pins[P6_3], 3, 2, 0 },
[GPIO3_3] = { pins[P6_4], 3, 3, 0 },
[GPIO3_4] = { pins[P6_5], 3, 4, 0 },
[GPIO3_5] = { pins[P6_9], 3, 5, 0 },
[GPIO3_6] = { pins[P6_10], 3, 6, 0 },
[GPIO3_7] = { pins[P6_11], 3, 7, 0 },
[GPIO3_8] = { pins[P7_0], 3, 8, 0 },
[GPIO3_9] = { pins[P7_1], 3, 9, 0 },
[GPIO3_10] = { pins[P7_2], 3, 10, 0 },
[GPIO3_11] = { pins[P7_3], 3, 11, 0 },
[GPIO3_12] = { pins[P7_4], 3, 12, 0 },
[GPIO3_13] = { pins[P7_5], 3, 13, 0 },
[GPIO3_14] = { pins[P7_6], 3, 14, 0 },
[GPIO3_15] = { pins[P7_7], 3, 15, 0 },
[GPIO3_0] = {pins[P6_1], 3, 0, 0},
[GPIO3_1] = {pins[P6_2], 3, 1, 0},
[GPIO3_2] = {pins[P6_3], 3, 2, 0},
[GPIO3_3] = {pins[P6_4], 3, 3, 0},
[GPIO3_4] = {pins[P6_5], 3, 4, 0},
[GPIO3_5] = {pins[P6_9], 3, 5, 0},
[GPIO3_6] = {pins[P6_10], 3, 6, 0},
[GPIO3_7] = {pins[P6_11], 3, 7, 0},
[GPIO3_8] = {pins[P7_0], 3, 8, 0},
[GPIO3_9] = {pins[P7_1], 3, 9, 0},
[GPIO3_10] = {pins[P7_2], 3, 10, 0},
[GPIO3_11] = {pins[P7_3], 3, 11, 0},
[GPIO3_12] = {pins[P7_4], 3, 12, 0},
[GPIO3_13] = {pins[P7_5], 3, 13, 0},
[GPIO3_14] = {pins[P7_6], 3, 14, 0},
[GPIO3_15] = {pins[P7_7], 3, 15, 0},
[GPIO4_11] = { pins[P9_6], 4, 11, 0 },
[GPIO4_11] = {pins[P9_6], 4, 11, 0},
[GPIO5_0] = { pins[P2_0], 5, 0, 4 },
[GPIO5_1] = { pins[P2_1], 5, 1, 4 },
[GPIO5_2] = { pins[P2_2], 5, 2, 4 },
[GPIO5_3] = { pins[P2_3], 5, 3, 4 },
[GPIO5_4] = { pins[P2_4], 5, 4, 4 },
[GPIO5_5] = { pins[P2_5], 5, 5, 4 },
[GPIO5_6] = { pins[P2_6], 5, 6, 4 },
[GPIO5_7] = { pins[P2_8], 5, 7, 4 },
[GPIO5_8] = { pins[P3_1], 5, 8, 4 },
[GPIO5_9] = { pins[P3_2], 5, 9, 4 },
//[GPIO5_10] = { pins[P3_7], 5, 10, 4 },
//[GPIO5_11] = { pins[P3_8], 5, 11, 4 },
[GPIO5_12] = { pins[P4_8], 5, 12, 4 },
[GPIO5_13] = { pins[P4_9], 5, 13, 4 },
[GPIO5_14] = { pins[P4_10], 5, 14, 4 },
[GPIO5_15] = { pins[P6_7], 5, 15, 4 },
[GPIO5_16] = { pins[P6_8], 5, 16, 4 },
[GPIO5_18] = { pins[P9_5], 5, 18, 4 },
[GPIO5_0] = {pins[P2_0], 5, 0, 4},
[GPIO5_1] = {pins[P2_1], 5, 1, 4},
[GPIO5_2] = {pins[P2_2], 5, 2, 4},
[GPIO5_3] = {pins[P2_3], 5, 3, 4},
[GPIO5_4] = {pins[P2_4], 5, 4, 4},
[GPIO5_5] = {pins[P2_5], 5, 5, 4},
[GPIO5_6] = {pins[P2_6], 5, 6, 4},
[GPIO5_7] = {pins[P2_8], 5, 7, 4},
[GPIO5_8] = {pins[P3_1], 5, 8, 4},
[GPIO5_9] = {pins[P3_2], 5, 9, 4},
//[GPIO5_10] = { pins[P3_7], 5, 10, 4 },
//[GPIO5_11] = { pins[P3_8], 5, 11, 4 },
[GPIO5_12] = {pins[P4_8], 5, 12, 4},
[GPIO5_13] = {pins[P4_9], 5, 13, 4},
[GPIO5_14] = {pins[P4_10], 5, 14, 4},
[GPIO5_15] = {pins[P6_7], 5, 15, 4},
[GPIO5_16] = {pins[P6_8], 5, 16, 4},
[GPIO5_18] = {pins[P9_5], 5, 18, 4},
};
}
} // namespace lpc43xx
#endif/*__PINS_H__*/
#endif /*__PINS_H__*/

View File

@@ -21,112 +21,115 @@
#include "png_writer.hpp"
static constexpr std::array<uint8_t, 8> png_file_header { {
0x89, 0x50, 0x4e, 0x47,
0x0d, 0x0a, 0x1a, 0x0a,
} };
static constexpr std::array<uint8_t, 8> png_file_header{{
0x89,
0x50,
0x4e,
0x47,
0x0d,
0x0a,
0x1a,
0x0a,
}};
static constexpr std::array<uint8_t, 25> png_ihdr_screen_capture { {
0x00, 0x00, 0x00, 0x0d, // IHDR length
0x49, 0x48, 0x44, 0x52, // IHDR type
0x00, 0x00, 0x00, 0xf0, // width = 240
0x00, 0x00, 0x01, 0x40, // height = 320
0x08, // bit_depth = 8
0x02, // color_type = 2
0x00, // compression_method = 0
0x00, // filter_method = 0
0x00, // interlace_method = 0
0x0d, 0x8a, 0x66, 0x04, // CRC
} };
static constexpr std::array<uint8_t, 25> png_ihdr_screen_capture{{
0x00, 0x00, 0x00, 0x0d, // IHDR length
0x49, 0x48, 0x44, 0x52, // IHDR type
0x00, 0x00, 0x00, 0xf0, // width = 240
0x00, 0x00, 0x01, 0x40, // height = 320
0x08, // bit_depth = 8
0x02, // color_type = 2
0x00, // compression_method = 0
0x00, // filter_method = 0
0x00, // interlace_method = 0
0x0d, 0x8a, 0x66, 0x04, // CRC
}};
static constexpr std::array<uint8_t, 4> png_idat_chunk_type { {
0x49, 0x44, 0x41, 0x54, // IDAT type
} };
static constexpr std::array<uint8_t, 4> png_idat_chunk_type{{
0x49, 0x44, 0x41, 0x54, // IDAT type
}};
static constexpr std::array<uint8_t, 12> png_iend { {
0x00, 0x00, 0x00, 0x00, // IEND length
0x49, 0x45, 0x4e, 0x44, // IEND type
0xae, 0x42, 0x60, 0x82, // CRC
} };
static constexpr std::array<uint8_t, 12> png_iend{{
0x00, 0x00, 0x00, 0x00, // IEND length
0x49, 0x45, 0x4e, 0x44, // IEND type
0xae, 0x42, 0x60, 0x82, // CRC
}};
Optional<File::Error> PNGWriter::create(
const std::filesystem::path& filename
) {
const auto create_error = file.create(filename);
if( create_error.is_valid() ) {
return create_error;
}
const std::filesystem::path& filename) {
const auto create_error = file.create(filename);
if (create_error.is_valid()) {
return create_error;
}
file.write(png_file_header);
file.write(png_ihdr_screen_capture);
write_chunk_header(
2 + height * (5 + 1 + width * 3) + 4,
png_idat_chunk_type
);
file.write(png_file_header);
file.write(png_ihdr_screen_capture);
constexpr std::array<uint8_t, 2> zlib_header { 0x78, 0x01 }; // Zlib CM, CINFO, FLG.
write_chunk_content(zlib_header);
write_chunk_header(
2 + height * (5 + 1 + width * 3) + 4,
png_idat_chunk_type);
return { };
constexpr std::array<uint8_t, 2> zlib_header{0x78, 0x01}; // Zlib CM, CINFO, FLG.
write_chunk_content(zlib_header);
return {};
}
PNGWriter::~PNGWriter() {
write_chunk_content(adler_32.bytes());
write_chunk_crc();
write_chunk_content(adler_32.bytes());
write_chunk_crc();
file.write(png_iend);
file.write(png_iend);
}
void PNGWriter::write_scanline(const std::array<ui::ColorRGB888, 240>& scanline) {
constexpr uint8_t scanline_filter_type = 0;
constexpr uint32_t deflate_block_length = 1 + sizeof(scanline);
constexpr uint8_t scanline_filter_type = 0;
constexpr uint32_t deflate_block_length = 1 + sizeof(scanline);
const std::array<uint8_t, 6> deflate_and_scanline_header {
static_cast<uint8_t>((scanline_count == (height - 1)) ? 0x01 : 0x00), // DEFLATE header bits, bfinal=0, btype=00
static_cast<uint8_t>((deflate_block_length >> 0) & 0xff), // Length LSB
static_cast<uint8_t>((deflate_block_length >> 8) & 0xff), // Length MSB
static_cast<uint8_t>((deflate_block_length >> 0) & 0xff) ^ 0xff, // ~Length LSB
static_cast<uint8_t>((deflate_block_length >> 8) & 0xff) ^ 0xff, // ~Length MSB
scanline_filter_type,
};
write_chunk_content(deflate_and_scanline_header);
const std::array<uint8_t, 6> deflate_and_scanline_header{
static_cast<uint8_t>((scanline_count == (height - 1)) ? 0x01 : 0x00), // DEFLATE header bits, bfinal=0, btype=00
static_cast<uint8_t>((deflate_block_length >> 0) & 0xff), // Length LSB
static_cast<uint8_t>((deflate_block_length >> 8) & 0xff), // Length MSB
static_cast<uint8_t>((deflate_block_length >> 0) & 0xff) ^ 0xff, // ~Length LSB
static_cast<uint8_t>((deflate_block_length >> 8) & 0xff) ^ 0xff, // ~Length MSB
scanline_filter_type,
};
write_chunk_content(deflate_and_scanline_header);
adler_32.feed(scanline_filter_type);
adler_32.feed(scanline);
adler_32.feed(scanline_filter_type);
adler_32.feed(scanline);
// Small writes to avoid some sort of large-transfer plus block
// boundary FatFs or SDC driver bug?
write_chunk_content(&scanline[ 0], 80 * sizeof(ui::ColorRGB888));
write_chunk_content(&scanline[ 80], 80 * sizeof(ui::ColorRGB888));
write_chunk_content(&scanline[160], 80 * sizeof(ui::ColorRGB888));
// Small writes to avoid some sort of large-transfer plus block
// boundary FatFs or SDC driver bug?
write_chunk_content(&scanline[0], 80 * sizeof(ui::ColorRGB888));
write_chunk_content(&scanline[80], 80 * sizeof(ui::ColorRGB888));
write_chunk_content(&scanline[160], 80 * sizeof(ui::ColorRGB888));
scanline_count++;
scanline_count++;
}
void PNGWriter::write_chunk_header(
const size_t length,
const std::array<uint8_t, 4>& type
) {
write_uint32_be(length);
crc.reset();
write_chunk_content(type);
const size_t length,
const std::array<uint8_t, 4>& type) {
write_uint32_be(length);
crc.reset();
write_chunk_content(type);
}
void PNGWriter::write_chunk_content(const void* const p, const size_t count) {
file.write(p, count);
crc.process_bytes(p, count);
file.write(p, count);
crc.process_bytes(p, count);
}
void PNGWriter::write_chunk_crc() {
write_uint32_be(crc.checksum());
write_uint32_be(crc.checksum());
}
void PNGWriter::write_uint32_be(const uint32_t v) {
file.write(std::array<uint8_t, 4> { {
static_cast<uint8_t>((v >> 24) & 0xff),
static_cast<uint8_t>((v >> 16) & 0xff),
static_cast<uint8_t>((v >> 8) & 0xff),
static_cast<uint8_t>((v >> 0) & 0xff),
} });
file.write(std::array<uint8_t, 4>{{
static_cast<uint8_t>((v >> 24) & 0xff),
static_cast<uint8_t>((v >> 16) & 0xff),
static_cast<uint8_t>((v >> 8) & 0xff),
static_cast<uint8_t>((v >> 0) & 0xff),
}});
}

View File

@@ -32,33 +32,33 @@
#include "crc.hpp"
class PNGWriter {
public:
~PNGWriter();
public:
~PNGWriter();
Optional<File::Error> create(const std::filesystem::path& filename);
void write_scanline(const std::array<ui::ColorRGB888, 240>& scanline);
Optional<File::Error> create(const std::filesystem::path& filename);
private:
// TODO: These constants are baked in a few places, do not change blithely.
static constexpr int width { 240 };
static constexpr int height { 320 };
void write_scanline(const std::array<ui::ColorRGB888, 240>& scanline);
File file { };
int scanline_count { 0 };
CRC<32, true, true> crc { 0x04c11db7, 0xffffffff, 0xffffffff };
Adler32 adler_32 { };
private:
// TODO: These constants are baked in a few places, do not change blithely.
static constexpr int width{240};
static constexpr int height{320};
void write_chunk_header(const size_t length, const std::array<uint8_t, 4>& type);
void write_chunk_content(const void* const p, const size_t count);
File file{};
int scanline_count{0};
CRC<32, true, true> crc{0x04c11db7, 0xffffffff, 0xffffffff};
Adler32 adler_32{};
template<size_t N>
void write_chunk_content(const std::array<uint8_t, N>& data) {
write_chunk_content(data.data(), sizeof(data));
}
void write_chunk_header(const size_t length, const std::array<uint8_t, 4>& type);
void write_chunk_content(const void* const p, const size_t count);
void write_chunk_crc();
void write_uint32_be(const uint32_t v);
template <size_t N>
void write_chunk_content(const std::array<uint8_t, N>& data) {
write_chunk_content(data.data(), sizeof(data));
}
void write_chunk_crc();
void write_uint32_be(const uint32_t v);
};
#endif/*__PNG_WRITER_H__*/
#endif /*__PNG_WRITER_H__*/

View File

@@ -32,437 +32,423 @@ using namespace portapack;
namespace pocsag {
std::string bitrate_str(BitRate bitrate) {
switch (bitrate) {
case BitRate::FSK512: return "512bps ";
case BitRate::FSK1200: return "1200bps";
case BitRate::FSK2400: return "2400bps";
case BitRate::FSK3200: return "3200bps";
default: return "????";
}
switch (bitrate) {
case BitRate::FSK512:
return "512bps ";
case BitRate::FSK1200:
return "1200bps";
case BitRate::FSK2400:
return "2400bps";
case BitRate::FSK3200:
return "3200bps";
default:
return "????";
}
}
std::string flag_str(PacketFlag packetflag) {
switch (packetflag) {
case PacketFlag::NORMAL: return "OK";
case PacketFlag::TIMED_OUT: return "TIMED OUT";
default: return "";
}
switch (packetflag) {
case PacketFlag::NORMAL:
return "OK";
case PacketFlag::TIMED_OUT:
return "TIMED OUT";
default:
return "";
}
}
void insert_BCH(BCHCode& BCH_code, uint32_t * codeword) {
uint32_t parity = 0;
int data[21];
int bit;
int * bb;
size_t c;
for (c = 0; c < 21; c++) {
bit = (((*codeword) << c) & 0x80000000U) ? 1 : 0;
if (bit) parity++;
data[c] = bit;
}
bb = BCH_code.encode(data);
// Make sure ECC bits are cleared
(*codeword) &= 0xFFFFF801;
for (c = 0; c < 10; c++) {
bit = bb[c];
(*codeword) |= (bit << (10 - c));
if (bit) parity++;
}
// Even parity
(*codeword) |= (parity & 1);
void insert_BCH(BCHCode& BCH_code, uint32_t* codeword) {
uint32_t parity = 0;
int data[21];
int bit;
int* bb;
size_t c;
for (c = 0; c < 21; c++) {
bit = (((*codeword) << c) & 0x80000000U) ? 1 : 0;
if (bit) parity++;
data[c] = bit;
}
bb = BCH_code.encode(data);
// Make sure ECC bits are cleared
(*codeword) &= 0xFFFFF801;
for (c = 0; c < 10; c++) {
bit = bb[c];
(*codeword) |= (bit << (10 - c));
if (bit) parity++;
}
// Even parity
(*codeword) |= (parity & 1);
}
uint32_t get_digit_code(char code) {
if ((code >= '0') && (code <= '9')) {
code -= '0';
} else {
if (code == 'S')
code = 10;
else if (code == 'U')
code = 11;
else if (code == ' ')
code = 12;
else if (code == '-')
code = 13;
else if (code == ']')
code = 14;
else if (code == '[')
code = 15;
else
code = 12;
}
code = ((code & 0x0C) >> 2) | ((code & 0x03) << 2); // ----3210 -> ----1032
code = ((code & 0x0A) >> 1) | ((code & 0x05) << 1); // ----1032 -> ----0123
return code;
}
void pocsag_encode(const MessageType type, BCHCode& BCH_code, const uint32_t function, const std::string message, const uint32_t address,
std::vector<uint32_t>& codewords) {
size_t b, c, address_slot;
size_t bit_idx, char_idx = 0;
uint32_t codeword, digit_code;
char ascii_char = 0;
size_t message_size = message.size();
// Preamble
for (b = 0; b < (POCSAG_PREAMBLE_LENGTH / 32); b++) {
codewords.push_back(0xAAAAAAAA);
}
// Address
codeword = (address & 0x1FFFF8U) << 10;
address_slot = (address & 7) * 2;
// Function
codeword |= (function << 11);
insert_BCH(BCH_code, &codeword);
// Address batch
codewords.push_back(POCSAG_SYNCWORD);
for (c = 0; c < 16; c++) {
if (c == address_slot) {
codewords.push_back(codeword);
if (type != MessageType::ADDRESS_ONLY) break;
} else
codewords.push_back(POCSAG_IDLEWORD);
}
if (type == MessageType::ADDRESS_ONLY) return; // Done.
c++;
codeword = 0;
bit_idx = 20 + 11;
// Messages batch(es)
do {
if (c == 0) codewords.push_back(POCSAG_SYNCWORD);
for ( ; c < 16; c++) {
// Fill up 20 bits
if (type == MessageType::ALPHANUMERIC) {
if ((char_idx < message_size) || (ascii_char)) {
do {
bit_idx -= 7;
if (char_idx < message_size)
ascii_char = message[char_idx] & 0x7F;
else
ascii_char = 0; // Codeword padding
// Bottom's up
ascii_char = (ascii_char & 0xF0) >> 4 | (ascii_char & 0x0F) << 4; // *6543210 -> 3210*654
ascii_char = (ascii_char & 0xCC) >> 2 | (ascii_char & 0x33) << 2; // 3210*654 -> 103254*6
ascii_char = (ascii_char & 0xAA) >> 2 | (ascii_char & 0x55); // 103254*6 -> *0123456
codeword |= (ascii_char << bit_idx);
char_idx++;
} while (bit_idx > 11);
codeword &= 0x7FFFF800; // Trim data
codeword |= 0x80000000; // Message type
insert_BCH(BCH_code, &codeword);
codewords.push_back(codeword);
if (bit_idx != 11) {
bit_idx = 20 + bit_idx;
codeword = ascii_char << bit_idx;
} else {
bit_idx = 20 + 11;
codeword = 0;
}
} else {
codewords.push_back(POCSAG_IDLEWORD); // Batch padding
}
} else if (type == MessageType::NUMERIC_ONLY) {
if (char_idx < message_size) {
do {
bit_idx -= 4;
if (char_idx < message_size)
digit_code = get_digit_code(message[char_idx]);
else
digit_code = 3; // Space (codeword padding)
codeword |= (digit_code << bit_idx);
char_idx++;
} while (bit_idx > 11);
codeword |= 0x80000000; // Message type
insert_BCH(BCH_code, &codeword);
codewords.push_back(codeword);
bit_idx = 20 + 11;
codeword = 0;
} else {
codewords.push_back(POCSAG_IDLEWORD); // Batch padding
}
}
}
c = 0;
} while (char_idx < message_size);
if ((code >= '0') && (code <= '9')) {
code -= '0';
} else {
if (code == 'S')
code = 10;
else if (code == 'U')
code = 11;
else if (code == ' ')
code = 12;
else if (code == '-')
code = 13;
else if (code == ']')
code = 14;
else if (code == '[')
code = 15;
else
code = 12;
}
code = ((code & 0x0C) >> 2) | ((code & 0x03) << 2); // ----3210 -> ----1032
code = ((code & 0x0A) >> 1) | ((code & 0x05) << 1); // ----1032 -> ----0123
return code;
}
void pocsag_encode(const MessageType type, BCHCode& BCH_code, const uint32_t function, const std::string message, const uint32_t address, std::vector<uint32_t>& codewords) {
size_t b, c, address_slot;
size_t bit_idx, char_idx = 0;
uint32_t codeword, digit_code;
char ascii_char = 0;
// -------------------------------------------------------------------------------
// -------------------------------------------------------------------------------
inline int bitsDiff(unsigned long left, unsigned long right)
{
unsigned long xord = left ^ right;
int count = 0;
for (int i = 0; i<32; i++)
{
if ((xord & 0x01) != 0) ++count;
xord = xord >> 1;
}
return(count);
size_t message_size = message.size();
// Preamble
for (b = 0; b < (POCSAG_PREAMBLE_LENGTH / 32); b++) {
codewords.push_back(0xAAAAAAAA);
}
// Address
codeword = (address & 0x1FFFF8U) << 10;
address_slot = (address & 7) * 2;
// Function
codeword |= (function << 11);
insert_BCH(BCH_code, &codeword);
// Address batch
codewords.push_back(POCSAG_SYNCWORD);
for (c = 0; c < 16; c++) {
if (c == address_slot) {
codewords.push_back(codeword);
if (type != MessageType::ADDRESS_ONLY) break;
} else
codewords.push_back(POCSAG_IDLEWORD);
}
if (type == MessageType::ADDRESS_ONLY) return; // Done.
c++;
codeword = 0;
bit_idx = 20 + 11;
// Messages batch(es)
do {
if (c == 0) codewords.push_back(POCSAG_SYNCWORD);
for (; c < 16; c++) {
// Fill up 20 bits
if (type == MessageType::ALPHANUMERIC) {
if ((char_idx < message_size) || (ascii_char)) {
do {
bit_idx -= 7;
if (char_idx < message_size)
ascii_char = message[char_idx] & 0x7F;
else
ascii_char = 0; // Codeword padding
// Bottom's up
ascii_char = (ascii_char & 0xF0) >> 4 | (ascii_char & 0x0F) << 4; // *6543210 -> 3210*654
ascii_char = (ascii_char & 0xCC) >> 2 | (ascii_char & 0x33) << 2; // 3210*654 -> 103254*6
ascii_char = (ascii_char & 0xAA) >> 2 | (ascii_char & 0x55); // 103254*6 -> *0123456
codeword |= (ascii_char << bit_idx);
char_idx++;
} while (bit_idx > 11);
codeword &= 0x7FFFF800; // Trim data
codeword |= 0x80000000; // Message type
insert_BCH(BCH_code, &codeword);
codewords.push_back(codeword);
if (bit_idx != 11) {
bit_idx = 20 + bit_idx;
codeword = ascii_char << bit_idx;
} else {
bit_idx = 20 + 11;
codeword = 0;
}
} else {
codewords.push_back(POCSAG_IDLEWORD); // Batch padding
}
} else if (type == MessageType::NUMERIC_ONLY) {
if (char_idx < message_size) {
do {
bit_idx -= 4;
if (char_idx < message_size)
digit_code = get_digit_code(message[char_idx]);
else
digit_code = 3; // Space (codeword padding)
codeword |= (digit_code << bit_idx);
char_idx++;
} while (bit_idx > 11);
codeword |= 0x80000000; // Message type
insert_BCH(BCH_code, &codeword);
codewords.push_back(codeword);
bit_idx = 20 + 11;
codeword = 0;
} else {
codewords.push_back(POCSAG_IDLEWORD); // Batch padding
}
}
}
c = 0;
} while (char_idx < message_size);
}
// -------------------------------------------------------------------------------
// -------------------------------------------------------------------------------
static uint32_t ecs[32]; /* error correction sequence */
inline int bitsDiff(unsigned long left, unsigned long right) {
unsigned long xord = left ^ right;
int count = 0;
for (int i = 0; i < 32; i++) {
if ((xord & 0x01) != 0) ++count;
xord = xord >> 1;
}
return (count);
}
// -------------------------------------------------------------------------------
// -------------------------------------------------------------------------------
static uint32_t ecs[32]; /* error correction sequence */
static uint32_t bch[1025];
static int eccSetup = 0;
// -------------------------------------------------------------------------------
// -------------------------------------------------------------------------------
void setupecc()
{
unsigned int srr = 0x3b4;
unsigned int i, n, j, k;
void setupecc() {
unsigned int srr = 0x3b4;
unsigned int i, n, j, k;
/* calculate all information needed to implement error correction */
// Note : this is only for 31,21 code used in pocsag & flex
// one should probably also make use of 32nd parity bit
for (i = 0; i <= 20; i++)
{
ecs[i] = srr;
if ((srr & 0x01) != 0) srr = (srr >> 1) ^ 0x3B4; else srr = srr >> 1;
}
/* calculate all information needed to implement error correction */
// Note : this is only for 31,21 code used in pocsag & flex
// one should probably also make use of 32nd parity bit
for (i = 0; i <= 20; i++) {
ecs[i] = srr;
if ((srr & 0x01) != 0)
srr = (srr >> 1) ^ 0x3B4;
else
srr = srr >> 1;
}
/* bch holds a syndrome look-up table telling which bits to correct */
// first 5 bits hold location of first error; next 5 bits hold location
// of second error; bits 12 & 13 tell how many bits are bad
for (i = 0; i<1024; i++) bch[i] = 0;
/* bch holds a syndrome look-up table telling which bits to correct */
// first 5 bits hold location of first error; next 5 bits hold location
// of second error; bits 12 & 13 tell how many bits are bad
for (i = 0; i < 1024; i++) bch[i] = 0;
/* two errors in data */
for (n = 0; n <= 20; n++)
{
for (i = 0; i <= 20; i++)
{
j = (i << 5) + n;
k = ecs[n] ^ ecs[i];
bch[k] = j + 0x2000;
}
}
/* two errors in data */
for (n = 0; n <= 20; n++) {
for (i = 0; i <= 20; i++) {
j = (i << 5) + n;
k = ecs[n] ^ ecs[i];
bch[k] = j + 0x2000;
}
}
/* one error in data */
for (n = 0; n <= 20; n++)
{
k = ecs[n];
j = n + (0x1f << 5);
bch[k] = j + 0x1000;
}
/* one error in data */
for (n = 0; n <= 20; n++) {
k = ecs[n];
j = n + (0x1f << 5);
bch[k] = j + 0x1000;
}
/* one error in data and one error in ecc portion */
for (n = 0; n <= 20; n++)
{
for (i = 0; i<10; i++) /* ecc screwed up bit */
{
k = ecs[n] ^ (1 << i);
j = n + (0x1f << 5);
bch[k] = j + 0x2000;
}
}
/* one error in data and one error in ecc portion */
for (n = 0; n <= 20; n++) {
for (i = 0; i < 10; i++) /* ecc screwed up bit */
{
k = ecs[n] ^ (1 << i);
j = n + (0x1f << 5);
bch[k] = j + 0x2000;
}
}
/* one error in ecc */
for (n = 0; n<10; n++)
{
k = 1 << n;
bch[k] = 0x3ff + 0x1000;
}
/* one error in ecc */
for (n = 0; n < 10; n++) {
k = 1 << n;
bch[k] = 0x3ff + 0x1000;
}
/* two errors in ecc */
for (n = 0; n<10; n++)
{
for (i = 0; i<10; i++)
{
if (i != n)
{
k = (1 << n) ^ (1 << i);
bch[k] = 0x3ff + 0x2000;
}
}
}
/* two errors in ecc */
for (n = 0; n < 10; n++) {
for (i = 0; i < 10; i++) {
if (i != n) {
k = (1 << n) ^ (1 << i);
bch[k] = 0x3ff + 0x2000;
}
}
}
}
// -------------------------------------------------------------------------------
// -------------------------------------------------------------------------------
inline int errorCorrection(uint32_t * val)
{
// Set up the tables the first time
if (eccSetup == 0)
{
setupecc();
eccSetup = 1;
}
inline int errorCorrection(uint32_t* val) {
// Set up the tables the first time
if (eccSetup == 0) {
setupecc();
eccSetup = 1;
}
int i, synd, errl, acc, pari, ecc, b1, b2;
int i, synd, errl, acc, pari, ecc, b1, b2;
errl = 0;
pari = 0;
errl = 0;
pari = 0;
/* run through error detection and correction routine */
/* run through error detection and correction routine */
// for (i=0; i<=20; i++)
ecc = 0;
for (i = 31; i >= 11; --i)
{
if ((*val&(1 << i))) { ecc = ecc ^ ecs[31 - i]; pari = pari ^ 0x01; }
}
// for (i=0; i<=20; i++)
ecc = 0;
for (i = 31; i >= 11; --i) {
if ((*val & (1 << i))) {
ecc = ecc ^ ecs[31 - i];
pari = pari ^ 0x01;
}
}
// for (i=21; i<=30; i++)
acc = 0;
for (i = 10; i >= 1; --i)
{
acc = acc << 1;
if ((*val&(1 << i))) { acc = acc ^ 0x01; }
}
// for (i=21; i<=30; i++)
acc = 0;
for (i = 10; i >= 1; --i) {
acc = acc << 1;
if ((*val & (1 << i))) {
acc = acc ^ 0x01;
}
}
synd = ecc ^ acc;
synd = ecc ^ acc;
errl = 0;
errl = 0;
if (synd != 0) /* if nonzero syndrome we have error */
{
if (synd != 0) /* if nonzero syndrome we have error */
{
if (bch[synd] != 0) /* check for correctable error */
{
b1 = bch[synd] & 0x1f;
b2 = bch[synd] >> 5;
b2 = b2 & 0x1f;
if (bch[synd] != 0) /* check for correctable error */
{
b1 = bch[synd] & 0x1f;
b2 = bch[synd] >> 5;
b2 = b2 & 0x1f;
if (b2 != 0x1f) {
*val ^= 0x01 << (31 - b2);
ecc = ecc ^ ecs[b2];
}
if (b2 != 0x1f)
{
*val ^= 0x01 << (31 - b2);
ecc = ecc ^ ecs[b2];
}
if (b1 != 0x1f) {
*val ^= 0x01 << (31 - b1);
ecc = ecc ^ ecs[b1];
}
if (b1 != 0x1f)
{
*val ^= 0x01 << (31 - b1);
ecc = ecc ^ ecs[b1];
}
errl = bch[synd] >> 12;
} else {
errl = 3;
}
errl = bch[synd] >> 12;
}
else
{
errl = 3;
}
if (errl == 1) pari = pari ^ 0x01;
}
if (errl == 1) pari = pari ^ 0x01;
}
if (errl == 4) errl = 3;
if (errl == 4) errl = 3;
return errl;
return errl;
}
void pocsag_decode_batch(const POCSAGPacket& batch, POCSAGState* const state) {
int errors = 0;
uint32_t codeword;
char ascii_char;
std::string output_text = "";
void pocsag_decode_batch(const POCSAGPacket& batch, POCSAGState * const state) {
int errors = 0;
uint32_t codeword;
char ascii_char;
std::string output_text = "";
state->out_type = EMPTY;
// For each codeword...
for (size_t i = 0; i < 16; i++) {
codeword = batch[i];
errorCorrection(&codeword);
errors = errorCorrection(&codeword);
state->out_type = EMPTY;
if (!(codeword & 0x80000000U)) {
// Address codeword
if (state->mode == STATE_CLEAR) {
//if (codeword != POCSAG_IDLEWORD) {
if (! (bitsDiff(codeword, POCSAG_IDLEWORD) < 1)){
// For each codeword...
for (size_t i = 0; i < 16; i++) {
codeword = batch[i];
state->function = (codeword >> 11) & 3;
state->address = (codeword >> 10) & 0x1FFFF8U; // 18 MSBs are transmitted
state->mode = STATE_HAVE_ADDRESS;
state->out_type = ADDRESS;
state->errors = errors;
errorCorrection(&codeword);
errors = errorCorrection(&codeword);
state->ascii_idx = 0;
state->ascii_data = 0;
}
} else {
state->mode = STATE_CLEAR; // New address = new message
}
} else {
state->errors += errors;
// Message codeword
if (state->mode == STATE_HAVE_ADDRESS) {
// First message codeword: complete address
state->address |= (i >> 1); // Add in the 3 LSBs (frame #)
state->mode = STATE_GETTING_MSG;
}
state->out_type = MESSAGE;
state->ascii_data |= ((codeword >> 11) & 0xFFFFF); // Get 20 message bits
state->ascii_idx += 20;
// Raw 20 bits to 7 bit reversed ASCII
while (state->ascii_idx >= 7) {
state->ascii_idx -= 7;
ascii_char = ((state->ascii_data) >> (state->ascii_idx)) & 0x7F;
// Bottom's up
ascii_char = (ascii_char & 0xF0) >> 4 | (ascii_char & 0x0F) << 4; // 01234567 -> 45670123
ascii_char = (ascii_char & 0xCC) >> 2 | (ascii_char & 0x33) << 2; // 45670123 -> 67452301
ascii_char = (ascii_char & 0xAA) >> 2 | (ascii_char & 0x55); // 67452301 -> *7654321
// Translate non-printable chars
if ((ascii_char < 32) || (ascii_char > 126))
{
//output_text += "[" + to_string_dec_uint(ascii_char) + "]";
output_text += ".";
}
else
output_text += ascii_char;
}
state->ascii_data <<= 20; // Remaining bits are for next time...
}
}
state->output = output_text;
if (state->mode == STATE_HAVE_ADDRESS)
state->mode = STATE_CLEAR;
if (!(codeword & 0x80000000U)) {
// Address codeword
if (state->mode == STATE_CLEAR) {
// if (codeword != POCSAG_IDLEWORD) {
if (!(bitsDiff(codeword, POCSAG_IDLEWORD) < 1)) {
state->function = (codeword >> 11) & 3;
state->address = (codeword >> 10) & 0x1FFFF8U; // 18 MSBs are transmitted
state->mode = STATE_HAVE_ADDRESS;
state->out_type = ADDRESS;
state->errors = errors;
state->ascii_idx = 0;
state->ascii_data = 0;
}
} else {
state->mode = STATE_CLEAR; // New address = new message
}
} else {
state->errors += errors;
// Message codeword
if (state->mode == STATE_HAVE_ADDRESS) {
// First message codeword: complete address
state->address |= (i >> 1); // Add in the 3 LSBs (frame #)
state->mode = STATE_GETTING_MSG;
}
state->out_type = MESSAGE;
state->ascii_data |= ((codeword >> 11) & 0xFFFFF); // Get 20 message bits
state->ascii_idx += 20;
// Raw 20 bits to 7 bit reversed ASCII
while (state->ascii_idx >= 7) {
state->ascii_idx -= 7;
ascii_char = ((state->ascii_data) >> (state->ascii_idx)) & 0x7F;
// Bottom's up
ascii_char = (ascii_char & 0xF0) >> 4 | (ascii_char & 0x0F) << 4; // 01234567 -> 45670123
ascii_char = (ascii_char & 0xCC) >> 2 | (ascii_char & 0x33) << 2; // 45670123 -> 67452301
ascii_char = (ascii_char & 0xAA) >> 2 | (ascii_char & 0x55); // 67452301 -> *7654321
// Translate non-printable chars
if ((ascii_char < 32) || (ascii_char > 126)) {
// output_text += "[" + to_string_dec_uint(ascii_char) + "]";
output_text += ".";
} else
output_text += ascii_char;
}
state->ascii_data <<= 20; // Remaining bits are for next time...
}
}
state->output = output_text;
if (state->mode == STATE_HAVE_ADDRESS)
state->mode = STATE_CLEAR;
}
} /* namespace pocsag */

View File

@@ -24,7 +24,7 @@
#define __POCSAG_H__
#define POCSAG_PREAMBLE_LENGTH 576
#define POCSAG_TIMEOUT (576 * 2) // Preamble length * 2
#define POCSAG_TIMEOUT (576 * 2) // Preamble length * 2
#define POCSAG_SYNCWORD 0x7CD215D8
#define POCSAG_IDLEWORD 0x7A89C197
#define POCSAG_AUDIO_RATE 24000
@@ -38,50 +38,48 @@ namespace pocsag {
// Todo: these enums suck, make a better decode_batch
enum Mode : uint32_t {
STATE_CLEAR,
STATE_HAVE_ADDRESS,
STATE_GETTING_MSG
STATE_CLEAR,
STATE_HAVE_ADDRESS,
STATE_GETTING_MSG
};
enum OutputType : uint32_t {
EMPTY,
ADDRESS,
MESSAGE
EMPTY,
ADDRESS,
MESSAGE
};
enum MessageType : uint32_t {
ADDRESS_ONLY,
NUMERIC_ONLY,
ALPHANUMERIC
ADDRESS_ONLY,
NUMERIC_ONLY,
ALPHANUMERIC
};
struct POCSAGState {
uint32_t function;
uint32_t address;
Mode mode = STATE_CLEAR;
OutputType out_type = EMPTY;
uint32_t ascii_data;
uint32_t ascii_idx;
uint32_t errors;
std::string output;
uint32_t function;
uint32_t address;
Mode mode = STATE_CLEAR;
OutputType out_type = EMPTY;
uint32_t ascii_data;
uint32_t ascii_idx;
uint32_t errors;
std::string output;
};
const pocsag::BitRate pocsag_bitrates[4] = {
pocsag::BitRate::FSK512,
pocsag::BitRate::FSK1200,
pocsag::BitRate::FSK2400,
pocsag::BitRate::FSK3200
};
pocsag::BitRate::FSK512,
pocsag::BitRate::FSK1200,
pocsag::BitRate::FSK2400,
pocsag::BitRate::FSK3200};
std::string bitrate_str(BitRate bitrate);
std::string flag_str(PacketFlag packetflag);
void insert_BCH(BCHCode& BCH_code, uint32_t * codeword);
void insert_BCH(BCHCode& BCH_code, uint32_t* codeword);
uint32_t get_digit_code(char code);
void pocsag_encode(const MessageType type, BCHCode& BCH_code, const uint32_t function, const std::string message,
const uint32_t address, std::vector<uint32_t>& codewords);
void pocsag_decode_batch(const POCSAGPacket& batch, POCSAGState * const state);
void pocsag_encode(const MessageType type, BCHCode& BCH_code, const uint32_t function, const std::string message, const uint32_t address, std::vector<uint32_t>& codewords);
void pocsag_decode_batch(const POCSAGPacket& batch, POCSAGState* const state);
} /* namespace pocsag */
#endif/*__POCSAG_H__*/
#endif /*__POCSAG_H__*/

View File

@@ -31,67 +31,67 @@
namespace pocsag {
enum BitRate : uint32_t {
UNKNOWN,
FSK512 = 512,
FSK1200 = 1200,
FSK2400 = 2400,
FSK3200 = 3200
UNKNOWN,
FSK512 = 512,
FSK1200 = 1200,
FSK2400 = 2400,
FSK3200 = 3200
};
enum PacketFlag : uint32_t {
NORMAL,
TIMED_OUT,
TOO_LONG
NORMAL,
TIMED_OUT,
TOO_LONG
};
class POCSAGPacket {
public:
void set_timestamp(const Timestamp& value) {
timestamp_ = value;
}
Timestamp timestamp() const {
return timestamp_;
}
public:
void set_timestamp(const Timestamp& value) {
timestamp_ = value;
}
void set(const size_t index, const uint32_t data) {
if (index < 16)
codewords[index] = data;
}
Timestamp timestamp() const {
return timestamp_;
}
uint32_t operator[](const size_t index) const {
return (index < 16) ? codewords[index] : 0;
}
void set_bitrate(const uint16_t bitrate) {
bitrate_ = bitrate;
}
uint16_t bitrate() const {
return bitrate_;
}
void set_flag(const PacketFlag flag) {
flag_ = flag;
}
PacketFlag flag() const {
return flag_;
}
void set(const size_t index, const uint32_t data) {
if (index < 16)
codewords[index] = data;
}
void clear() {
codewords.fill(0);
bitrate_ = 0u;
flag_ = NORMAL;
}
uint32_t operator[](const size_t index) const {
return (index < 16) ? codewords[index] : 0;
}
private:
uint16_t bitrate_ { 0 };
PacketFlag flag_ { NORMAL };
std::array <uint32_t, 16> codewords { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
Timestamp timestamp_ { };
void set_bitrate(const uint16_t bitrate) {
bitrate_ = bitrate;
}
uint16_t bitrate() const {
return bitrate_;
}
void set_flag(const PacketFlag flag) {
flag_ = flag;
}
PacketFlag flag() const {
return flag_;
}
void clear() {
codewords.fill(0);
bitrate_ = 0u;
flag_ = NORMAL;
}
private:
uint16_t bitrate_{0};
PacketFlag flag_{NORMAL};
std::array<uint32_t, 16> codewords{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
Timestamp timestamp_{};
};
} /* namespace pocsag */
#endif/*__POCSAG_PACKET_H__*/
#endif /*__POCSAG_PACKET_H__*/

View File

@@ -39,4 +39,4 @@ constexpr size_t adc1_rssi_input = 1;
} /* namespace portapack */
#endif/*__PORTAPACK_ADC_H__*/
#endif /*__PORTAPACK_ADC_H__*/

View File

@@ -38,7 +38,7 @@ namespace rev_20150901 {
extern const std::array<uint16_t, 3328> block_0;
extern const std::array<uint16_t, 512> block_1;
const Config config { block_0, block_1 };
const Config config{block_0, block_1};
} /* namespace rev_20150901 */
@@ -47,11 +47,11 @@ namespace rev_20170522 {
extern const std::array<uint16_t, 3328> block_0;
extern const std::array<uint16_t, 512> block_1;
const Config config { block_0, block_1 };
const Config config{block_0, block_1};
} /* namespace rev_20170522 */
} /* namespace cpld */
} /* namespace portapack */
#endif/*__PORTAPACK_CPLD_DATA_H__*/
#endif /*__PORTAPACK_CPLD_DATA_H__*/

View File

@@ -43,25 +43,25 @@ constexpr size_t i2s0_rx_gpdma_channel_number = 3;
constexpr size_t adc1_gpdma_channel_number = 4;
constexpr size_t adc0_gpdma_channel_number = 5;
constexpr gpdma::mux::MUX gpdma_mux {
.peripheral_0 = gpdma::mux::Peripheral0::SGPIO14,
.peripheral_1 = gpdma::mux::Peripheral1::TIMER0_MATCH_0,
.peripheral_2 = gpdma::mux::Peripheral2::TIMER0_MATCH_1,
.peripheral_3 = gpdma::mux::Peripheral3::TIMER1_MATCH_0,
.peripheral_4 = gpdma::mux::Peripheral4::TIMER1_MATCH_1,
.peripheral_5 = gpdma::mux::Peripheral5::TIMER2_MATCH_0,
.peripheral_6 = gpdma::mux::Peripheral6::TIMER2_MATCH_1,
.peripheral_7 = gpdma::mux::Peripheral7::TIMER3_MATCH_0,
.peripheral_8 = gpdma::mux::Peripheral8::TIMER3_MATCH_1,
.peripheral_9 = gpdma::mux::Peripheral9::I2S0_DMAREQ_1,
.peripheral_10 = gpdma::mux::Peripheral10::I2S0_DMAREQ_2,
.peripheral_11 = gpdma::mux::Peripheral11::SSP1_RX,
.peripheral_12 = gpdma::mux::Peripheral12::SSP1_TX,
.peripheral_13 = gpdma::mux::Peripheral13::ADC0,
.peripheral_14 = gpdma::mux::Peripheral14::ADC1,
.peripheral_15 = gpdma::mux::Peripheral15::DAC,
constexpr gpdma::mux::MUX gpdma_mux{
.peripheral_0 = gpdma::mux::Peripheral0::SGPIO14,
.peripheral_1 = gpdma::mux::Peripheral1::TIMER0_MATCH_0,
.peripheral_2 = gpdma::mux::Peripheral2::TIMER0_MATCH_1,
.peripheral_3 = gpdma::mux::Peripheral3::TIMER1_MATCH_0,
.peripheral_4 = gpdma::mux::Peripheral4::TIMER1_MATCH_1,
.peripheral_5 = gpdma::mux::Peripheral5::TIMER2_MATCH_0,
.peripheral_6 = gpdma::mux::Peripheral6::TIMER2_MATCH_1,
.peripheral_7 = gpdma::mux::Peripheral7::TIMER3_MATCH_0,
.peripheral_8 = gpdma::mux::Peripheral8::TIMER3_MATCH_1,
.peripheral_9 = gpdma::mux::Peripheral9::I2S0_DMAREQ_1,
.peripheral_10 = gpdma::mux::Peripheral10::I2S0_DMAREQ_2,
.peripheral_11 = gpdma::mux::Peripheral11::SSP1_RX,
.peripheral_12 = gpdma::mux::Peripheral12::SSP1_TX,
.peripheral_13 = gpdma::mux::Peripheral13::ADC0,
.peripheral_14 = gpdma::mux::Peripheral14::ADC1,
.peripheral_15 = gpdma::mux::Peripheral15::DAC,
};
} /* namespace portapack */
#endif/*__PORTAPACK_DMA_H__*/
#endif /*__PORTAPACK_DMA_H__*/

Some files were not shown because too many files have changed in this diff Show More