Add software

This commit is contained in:
RocketGod
2022-09-22 09:26:57 -07:00
parent fee0ab05fd
commit 957ea3d712
4511 changed files with 1943182 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2018 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "acars_packet.hpp"
#include "crc.hpp"
#include <cstdlib>
namespace acars {
size_t Packet::length() const {
return packet_.size();
}
bool Packet::is_valid() const {
return true; //length_valid() && crc_ok();
}
Timestamp Packet::received_at() const {
return packet_.timestamp();
}
uint8_t Packet::block_id() const {
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);
}
return result;
}
uint32_t Packet::read(const size_t start_bit, const size_t length) const {
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));
}
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));
}
return (acars_fcs.checksum() == (unsigned)field_crc.read(data_length(), fcs_length));
}
size_t Packet::data_and_fcs_length() const {
return length() - 8;
}
size_t Packet::data_length() const {
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;
}
return true;
}
} /* namespace ais */

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2018 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __ACARS_PACKET_H__
#define __ACARS_PACKET_H__
#include "baseband_packet.hpp"
#include "field_reader.hpp"
#include <cstdint>
#include <cstddef>
#include <string>
namespace acars {
class Packet {
public:
constexpr Packet(
const baseband::Packet& packet
) : packet_ { packet },
field_ { packet_ }
{
}
size_t length() const;
bool is_valid() const;
Timestamp received_at() const;
uint8_t block_id() const;
std::string registration_number() 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;
bool crc_ok() const;
private:
using Reader = FieldReader<baseband::Packet, BitRemapByteReverse>;
using CRCReader = FieldReader<baseband::Packet, BitRemapNone>;
const baseband::Packet packet_;
const Reader field_;
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__*/

View File

@@ -0,0 +1,135 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __ADC_H__
#define __ADC_H__
#include "hal.h"
namespace lpc43xx {
namespace adc {
constexpr size_t clock_rate_max = 4500000U;
struct CR {
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)
;
}
};
struct Config {
uint32_t cr;
};
template<uint32_t BaseAddress>
class ADC {
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_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;
clock_disable();
}
static void interrupts_disable() {
adcp().INTEN = 0;
}
static void interrupts_enable(const uint32_t mask) {
adcp().INTEN = mask;
}
static void start_burst() {
adcp().CR |= (1U << 16);
}
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 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;
}
}
}
private:
static LPC_ADCx_Type& adcp() {
return *reinterpret_cast<LPC_ADCx_Type*>(BaseAddress);
}
};
} /* namespace adc */
} /* namespace lpc43xx */
#endif/*__ADC_H__*/

View File

@@ -0,0 +1,384 @@
/*
* Copyright (C) 2014 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "adsb.hpp"
#include "sine_table.hpp"
#include <math.h>
namespace adsb {
void make_frame_adsb(ADSBFrame& frame, const uint32_t ICAO_address) {
frame.clear();
frame.push_byte((DF_ADSB << 3) | 5); // DF and CA
frame.push_byte(ICAO_address >> 16);
frame.push_byte(ICAO_address >> 8);
frame.push_byte(ICAO_address & 0xFF);
}
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);
frame.push_byte(TC_IDENT << 3); // No aircraft category
// 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;
}
/*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();
}*/
void encode_frame_squawk(ADSBFrame& frame, const uint32_t squawk) {
uint32_t squawk_coded;
frame.clear();
frame.push_byte(DF_EHS_SQUAWK << 3); // DF
frame.push_byte(0);
// 12 11 10 9 8 7 6 5 4 3 2 1 0
// 31 30 29 28 27 26 25 24 23 22 21 20 19
// D4 B4 D2 B2 D1 B1 __ A4 C4 A2 C2 A1 C1
// ABCD = code (octal, 0000~7777)
// FEDCBA9876543210
// xAAAxBBBxCCCxDDD
// x421x421x421x421
squawk_coded = ((squawk << 10) & 0x1000) | // D4
((squawk << 1) & 0x0800) | // B4
((squawk << 9) & 0x0400) | // D2
((squawk << 0) & 0x0200) | // B2
((squawk << 8) & 0x0100) | // D1
((squawk >> 1) & 0x0080) | // B1
((squawk >> 9) & 0x0020) | // A4
((squawk >> 2) & 0x0010) | // C4
((squawk >> 10) & 0x0008) | // A2
((squawk >> 3) & 0x0004) | // C2
((squawk >> 11) & 0x0002) | // A1
((squawk >> 4) & 0x0001); // C1
frame.push_byte(squawk_coded >> 5);
frame.push_byte(squawk_coded << 3);
frame.make_CRC();
}
float cpr_mod(float a, float 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))));
}
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;
}
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:
//return cpr_NL_approx(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;
return nl;
}
float cpr_Dlon(float lat, int is_odd) {
return 360.0 / cpr_N(lat, is_odd);
}
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);
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;
// Q-bit must be present
if (raw_data[5] & 1)
position.altitude = ((((raw_data[5] & 0xFE) << 3) | ((raw_data[6] & 0xF0) >> 4)) * 25) - 1000;
// 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];
// Calculate the coefficients
cpr_lon_even = loncprE / CPR_MAX_VALUE;
cpr_lon_odd = loncprO / CPR_MAX_VALUE;
cpr_lat_odd = latcprO / CPR_MAX_VALUE;
cpr_lat_even = latcprE / CPR_MAX_VALUE;
// 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);
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;
}
// speed is in knots
// vertical rate 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, v_rate_coded;
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) + (pi / 2)) * speed);
velo_ns = static_cast<int32_t>(sin_f32(DEG_TO_RAD(angle)) * speed);
v_rate_coded = (v_rate / 64) + 1;
velo_ew_abs = abs(velo_ew) + 1;
velo_ns_abs = abs(velo_ns) + 1;
v_rate_coded_abs = abs(v_rate_coded);
make_frame_adsb(frame, ICAO_address);
frame.push_byte((TC_AIRBORNE_VELO << 3) | 1); // Subtype: 1 (subsonic)
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_coded < 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};
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
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(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;
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
velo.speed = sqrt(velo_ns*velo_ns + velo_ew*velo_ew);
if(velo.speed){
//calculate heading in degrees from ew/ns velocities
int16_t heading_temp = (int16_t)(atan2(velo_ew,velo_ns) * 180.0 / pi);
// 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

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2014 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __ADSB_H__
#define __ADSB_H__
#include "adsb_frame.hpp"
#include "ui.hpp"
#include <cstring>
#include <string>
namespace adsb {
enum downlink_format {
DF_ADSB = 17,
DF_EHS_SQUAWK = 21
};
enum type_code {
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
};
struct adsb_pos {
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
};
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
};
const float PI = 3.14159265358979323846;
const float NZ = 15.0;
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);
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);
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_squawk(ADSBFrame& frame, const uint32_t squawk);
} /* namespace adsb */
#endif/*__ADSB_H__*/

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "adsb_frame.hpp"
namespace adsb {
} /* namespace adsb */

View File

@@ -0,0 +1,131 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __ADSB_FRAME_H__
#define __ADSB_FRAME_H__
#include <cstring>
#include <string>
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 char icao_id_lut[65] = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ##### ###############0123456789######";
class ADSBFrame {
public:
uint8_t get_DF() {
return (raw_data[0] >> 3);
}
uint8_t get_msg_type() {
return (raw_data[4] >> 3);
}
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;
}
void clear() {
index = 0;
memset(raw_data, 0, 14);
}
void push_byte(uint8_t byte) {
if (index >= 14)
return;
raw_data[index++] = byte;
}
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__*/

View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ais_baseband.hpp"

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __AIS_BASEBAND_H__
#define __AIS_BASEBAND_H__
#include <cstdint>
#include <cstddef>
#include <complex>
#include <array>
#include <bitset>
#include <utility>
namespace baseband {
namespace ais {
// Translate+Rectangular window filter
// 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 },
} };
} /* namespace ais */
} /* namespace baseband */
#endif/*__AIS_BASEBAND_H__*/

View File

@@ -0,0 +1,220 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ais_packet.hpp"
#include "crc.hpp"
#include <cstdlib>
namespace ais {
struct PacketLengthRange {
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 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_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;
}
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
} };
struct PacketLengthValidator {
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);
}
};
static constexpr char char_to_ascii(const uint8_t c) {
return (c ^ 32) + 32;
}
size_t Packet::length() const {
return packet_.size();
}
bool Packet::is_valid() const {
return length_valid() && crc_ok();
}
Timestamp Packet::received_at() const {
return packet_.timestamp();
}
uint32_t Packet::message_id() const {
return field_.read(0, 6);
}
MMSI Packet::user_id() const {
return field_.read(8, 30);
}
MMSI Packet::source_id() const {
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);
}
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));
}
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)),
};
}
Latitude Packet::latitude(const size_t start_bit) const {
return field_.read(start_bit, 27);
}
Longitude Packet::longitude(const size_t start_bit) const {
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));
}
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;
}
size_t Packet::data_length() const {
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 PacketLengthValidator packet_length_valid;
if( !packet_length_valid(message_id(), data_length()) ) {
return false;
}
return true;
}
} /* namespace ais */

View File

@@ -0,0 +1,148 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __AIS_PACKET_H__
#define __AIS_PACKET_H__
#include "baseband_packet.hpp"
#include "field_reader.hpp"
#include <cstdint>
#include <cstddef>
#include <string>
namespace ais {
struct DateTime {
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>
struct LatLonBase {
constexpr LatLonBase(
) : LatLonBase { raw_not_available }
{
}
constexpr LatLonBase(
const int32_t raw
) : raw_ { raw }
{
}
constexpr LatLonBase(
const LatLonBase& other
) : raw_ { other.raw_ }
{
}
LatLonBase& operator=( const LatLonBase &)=default;
int32_t normalized() const {
return static_cast<int32_t>(raw() << sign_extend_shift) / (1 << sign_extend_shift);
}
int32_t raw() const {
return raw_;
}
bool is_not_available() const {
return raw() == raw_not_available;
}
bool is_valid() const {
return (normalized() >= raw_valid_min) && (normalized() <= raw_valid_max);
}
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>;
using Longitude = LatLonBase<28, 180, 0x6791AC0>;
using RateOfTurn = int8_t;
using SpeedOverGround = uint16_t;
using CourseOverGround = uint16_t;
using TrueHeading = uint16_t;
using MMSI = uint32_t;
class Packet {
public:
constexpr Packet(
const baseband::Packet& packet
) : packet_ { packet },
field_ { packet_ }
{
}
size_t length() const;
bool is_valid() const;
Timestamp received_at() const;
uint32_t message_id() const;
MMSI user_id() const;
MMSI source_id() 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;
DateTime datetime(const size_t start_bit) const;
Latitude latitude(const size_t start_bit) const;
Longitude longitude(const size_t start_bit) const;
bool crc_ok() const;
private:
using Reader = FieldReader<baseband::Packet, BitRemapByteReverse>;
using CRCReader = FieldReader<baseband::Packet, BitRemapNone>;
const baseband::Packet packet_;
const Reader field_;
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__*/

View File

@@ -0,0 +1,323 @@
/*
* Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ak4951.hpp"
#include "portapack_io.hpp"
using namespace portapack;
#include <ch.h>
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);
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);
}
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);
}
void AK4951::init() {
reset();
// Write dummy address to "release" the reset.
write(0x00, 0x00);
configure_digital_interface_i2s();
configure_digital_interface_external_slave();
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);
// Pause for VCOM and REGFIL pins to stabilize.
chThdSleepMilliseconds(2);
headphone_mute();
// 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.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 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 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 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();
}
bool AK4951::reset() {
io.audio_reset_state(true);
// PDN# pulse must be >200ns
chThdSleepMicroseconds(10);
io.audio_reset_state(false);
return true;
}
void AK4951::set_digtal_volume_control(const reg_t value) {
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);
}
void AK4951::headphone_mute() {
set_digtal_volume_control(0xff);
}
void AK4951::set_dac_power(const bool enable) {
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);
}
void AK4951::set_speaker_power(const bool enable) {
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);
}
void AK4951::headphone_enable() {
set_dac_power(true);
set_headphone_power(true);
// Wait for headphone amplifier charge pump power-up.
chThdSleepMilliseconds(35);
}
void AK4951::headphone_disable() {
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);
// 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);
// 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);
}
void AK4951::speaker_disable() {
// 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);
// 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() {
// map.r.digital_mic.DMIC = 0;
// update(Register::DigitalMic);
const uint_fast8_t mgain = 0b0111;
map.r.signal_select_1.MGAIN20 = mgain & 7;
map.r.signal_select_1.PMMP = 1;
map.r.signal_select_1.MPSEL = 1; // MPWR2 pin
map.r.signal_select_1.MGAIN3 = (mgain >> 3) & 1;
update(Register::SignalSelect1);
map.r.signal_select_2.INL = 0b01; // Lch input signal = LIN2
map.r.signal_select_2.INR = 0b01; // Rch input signal = RIN2
map.r.signal_select_2.MICL = 0; // MPWR = 2.4V
update(Register::SignalSelect2);
// map.r.r_ch_mic_gain_setting.MGR = 0x80; // Microphone sensitivity correction = 0dB.
// update(Register::RchMicGainSetting);
/*
map.r.timer_select.FRN = ?;
map.r.timer_select.FRATT = ?;
map.r.timer_select.ADRST = 0b??;
update(Register::TimerSelect);
map.r.alc_timer_select. = ?;
update(Register::ALCTimerSelect);
map.r.alc_mode_control_1. = ?;
map.r.alc_mode_control_1.ALC = 1;
update(Register::ALCModeControl1);
map.r.alc_mode_control_2.REF = ?;
update(Register::ALCModeControl2);
*/
// map.r.l_ch_input_volume_control.IV = 0xe1;
// update(Register::LchInputVolumeControl);
// map.r.r_ch_input_volume_control.IV = 0xe1;
// update(Register::RchInputVolumeControl);
/*
map.r.auto_hpf_control.STG = 0b00;
map.r.auto_hpf_control.SENC = 0b011;
map.r.auto_hpf_control.AHPF = 0;
update(Register::AutoHPFControl);
*/
map.r.digital_filter_select_1.HPFAD = 1; // HPF1 (after ADC) = on
map.r.digital_filter_select_1.HPFC = 0b11; // 2336.8 Hz @ fs=48k
update(Register::DigitalFilterSelect1);
/*
map.r.digital_filter_select_2.HPF = 0;
map.r.digital_filter_select_2.LPF = 0;
map.r.digital_filter_select_2.FIL3 = 0;
map.r.digital_filter_select_2.EQ0 = 0;
map.r.digital_filter_select_2.GN = 0b00;
update(Register::DigitalFilterSelect2);
map.r.digital_filter_select_3.EQ1 = 0;
map.r.digital_filter_select_3.EQ2 = 0;
map.r.digital_filter_select_3.EQ3 = 0;
map.r.digital_filter_select_3.EQ4 = 0;
map.r.digital_filter_select_3.EQ5 = 0;
update(Register::DigitalFilterSelect3);
*/
map.r.digital_filter_mode.PFSDO = 0; // ADC (+ 1st order HPF) Output
map.r.digital_filter_mode.ADCPF = 1; // ADC Output (default)
update(Register::DigitalFilterMode);
// ... Set coefficients ...
map.r.power_management_1.PMADL = 1; // ADC Lch = Lch input signal
map.r.power_management_1.PMADR = 1; // ADC Rch = Rch input signal
map.r.power_management_1.PMPFIL = 0; // Programmable filter unused, routed around.
update(Register::PowerManagement1);
// 1059/fs, 22ms @ 48kHz
chThdSleepMilliseconds(22);
}
void AK4951::microphone_disable() {
map.r.power_management_1.PMADL = 0;
map.r.power_management_1.PMADR = 0;
map.r.power_management_1.PMPFIL = 0;
update(Register::PowerManagement1);
map.r.alc_mode_control_1.ALC = 0;
update(Register::ALCModeControl1);
}
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];
}
void AK4951::update(const Register 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());
}
} /* namespace ak4951 */
} /* namespace asahi_kasei */

View File

@@ -0,0 +1,886 @@
/*
* Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __AK4951_H__
#define __AK4951_H__
#include <cstdint>
#include <array>
#include "utility.hpp"
#include "i2c_pp.hpp"
#include "audio.hpp"
namespace asahi_kasei {
namespace ak4951 {
using address_t = uint8_t;
using reg_t = uint8_t;
constexpr size_t reg_count = 0x50;
enum class Register : address_t {
PowerManagement1 = 0x00,
PowerManagement2 = 0x01,
SignalSelect1 = 0x02,
SignalSelect2 = 0x03,
SignalSelect3 = 0x04,
ModeControl1 = 0x05,
ModeControl2 = 0x06,
ModeControl3 = 0x07,
DigitalMic = 0x08,
TimerSelect = 0x09,
ALCTimerSelect = 0x0a,
ALCModeControl1 = 0x0b,
ALCModeControl2 = 0x0c,
LchInputVolumeControl = 0x0d,
RchInputVolumeControl = 0x0e,
ALCVolume = 0x0f,
_Reserved_0x10 = 0x10,
RchMicGainSetting = 0x11,
BeepControl = 0x12,
LchDigitalVolumeControl = 0x13,
RchDigitalVolumeControl = 0x14,
EQCommonGainSelect = 0x15,
EQ2CommonGainSetting = 0x16,
EQ3CommonGainSetting = 0x17,
EQ4CommonGainSetting = 0x18,
EQ5CommonGainSetting = 0x19,
AutoHPFControl = 0x1a,
DigitalFilterSelect1 = 0x1b,
DigitalFilterSelect2 = 0x1c,
DigitalFilterMode = 0x1d,
HPF2Coefficient0 = 0x1e,
HPF2Coefficient1 = 0x1f,
HPF2Coefficient2 = 0x20,
HPF2Coefficient3 = 0x21,
LPFCoefficient0 = 0x22,
LPFCoefficient1 = 0x23,
LPFCoefficient2 = 0x24,
LPFCoefficient3 = 0x25,
FIL3Coefficient0 = 0x26,
FIL3Coefficient1 = 0x27,
FIL3Coefficient2 = 0x28,
FIL3Coefficient3 = 0x29,
EQCoefficient0 = 0x2a,
EQCoefficient1 = 0x2b,
EQCoefficient2 = 0x2c,
EQCoefficient3 = 0x2d,
EQCoefficient4 = 0x2e,
EQCoefficient5 = 0x2f,
DigitalFilterSelect3 = 0x30,
DeviceInformation = 0x31,
E1Coefficient0 = 0x32,
E1Coefficient1 = 0x33,
E1Coefficient2 = 0x34,
E1Coefficient3 = 0x35,
E1Coefficient4 = 0x36,
E1Coefficient5 = 0x37,
E2Coefficient0 = 0x38,
E2Coefficient1 = 0x39,
E2Coefficient2 = 0x3a,
E2Coefficient3 = 0x3b,
E2Coefficient4 = 0x3c,
E2Coefficient5 = 0x3d,
E3Coefficient0 = 0x3e,
E3Coefficient1 = 0x3f,
E3Coefficient2 = 0x40,
E3Coefficient3 = 0x41,
E3Coefficient4 = 0x42,
E3Coefficient5 = 0x43,
E4Coefficient0 = 0x44,
E4Coefficient1 = 0x45,
E4Coefficient2 = 0x46,
E4Coefficient3 = 0x47,
E4Coefficient4 = 0x48,
E4Coefficient5 = 0x49,
E5Coefficient0 = 0x4a,
E5Coefficient1 = 0x4b,
E5Coefficient2 = 0x4c,
E5Coefficient3 = 0x4d,
E5Coefficient4 = 0x4e,
E5Coefficient5 = 0x4f,
_count,
};
static_assert(toUType(Register::_count) == reg_count, "Register::_count != reg_count");
struct PowerManagement1 {
reg_t PMADL : 1;
reg_t PMADR : 1;
reg_t PMDAC : 1;
reg_t reserved0 : 2;
reg_t PMBP : 1;
reg_t PMVCM : 1;
reg_t PMPFIL : 1;
};
static_assert(sizeof(PowerManagement1) == sizeof(reg_t), "wrong size `struct");
struct PowerManagement2 {
reg_t LOSEL : 1;
reg_t PMSL : 1;
reg_t PMPLL : 1;
reg_t MS : 1;
reg_t PMHPL : 1;
reg_t PMHPR : 1;
reg_t reserved0 : 1;
reg_t PMOSC : 1;
};
static_assert(sizeof(PowerManagement2) == sizeof(reg_t), "wrong size struct");
struct SignalSelect1 {
reg_t MGAIN20 : 3;
reg_t PMMP : 1;
reg_t MPSEL : 1;
reg_t DACS : 1;
reg_t MGAIN3 : 1;
reg_t SLPSN : 1;
};
static_assert(sizeof(SignalSelect1) == sizeof(reg_t), "wrong size struct");
struct SignalSelect2 {
reg_t INR : 2;
reg_t INL : 2;
reg_t MICL : 1;
reg_t reserved0 : 1;
reg_t SPKG : 2;
};
static_assert(sizeof(SignalSelect2) == sizeof(reg_t), "wrong size struct");
struct SignalSelect3 {
reg_t MONO : 2;
reg_t PTS : 2;
reg_t reserved0 : 1;
reg_t DACL : 1;
reg_t LVCM : 2;
};
static_assert(sizeof(SignalSelect3) == sizeof(reg_t), "wrong size struct");
struct ModeControl1 {
reg_t DIF : 2;
reg_t CKOFF : 1;
reg_t BCKO : 1;
reg_t PLL : 4;
};
static_assert(sizeof(ModeControl1) == sizeof(reg_t), "wrong size struct");
struct ModeControl2 {
reg_t FS : 4;
reg_t reserved0 : 2;
reg_t CM : 2;
};
static_assert(sizeof(ModeControl2) == sizeof(reg_t), "wrong size struct");
struct ModeControl3 {
reg_t reserved0 : 2;
reg_t IVOLC : 1;
reg_t reserved1 : 1;
reg_t DVOLC : 1;
reg_t SMUTE : 1;
reg_t THDET : 1;
reg_t TSDSEL : 1;
};
static_assert(sizeof(ModeControl3) == sizeof(reg_t), "wrong size struct");
struct DigitalMIC {
reg_t DMIC : 1;
reg_t DCLKP : 1;
reg_t reserved0 : 1;
reg_t DCLKE : 1;
reg_t PMDML : 1;
reg_t PMDMR : 1;
reg_t reserved1 : 1;
reg_t READ : 1;
};
static_assert(sizeof(DigitalMIC) == sizeof(reg_t), "wrong size struct");
struct TimerSelect {
reg_t DVTM : 1;
reg_t MOFF : 1;
reg_t reserved0 : 2;
reg_t FRN : 1;
reg_t FRATT : 1;
reg_t ADRST : 2;
};
static_assert(sizeof(TimerSelect) == sizeof(reg_t), "wrong size struct");
struct ALCTimerSelect {
reg_t RFST : 2;
reg_t WTM : 2;
reg_t EQFC : 2;
reg_t IVTM : 1;
reg_t reserved0 : 1;
};
static_assert(sizeof(ALCTimerSelect) == sizeof(reg_t), "wrong size struct");
struct ALCModeControl1 {
reg_t LMTH10 : 2;
reg_t RGAIN : 3;
reg_t ALC : 1;
reg_t LMTH2 : 1;
reg_t ALCEQN : 1;
};
static_assert(sizeof(ALCModeControl1) == sizeof(reg_t), "wrong size struct");
struct ALCModeControl2 {
reg_t REF : 8;
};
static_assert(sizeof(ALCModeControl2) == sizeof(reg_t), "wrong size struct");
struct InputVolumeControl {
reg_t IV : 8;
};
static_assert(sizeof(InputVolumeControl) == sizeof(reg_t), "wrong size struct");
using LchInputVolumeControl = InputVolumeControl;
using RchInputVolumeControl = InputVolumeControl;
struct ALCVolume {
reg_t VOL : 8;
};
static_assert(sizeof(ALCVolume) == sizeof(reg_t), "wrong size struct");
struct RchMICGainSetting {
reg_t MGR : 8;
};
static_assert(sizeof(RchMICGainSetting) == sizeof(reg_t), "wrong size struct");
struct BeepControl {
reg_t BPLVL : 4;
reg_t BEEPH : 1;
reg_t BEEPS : 1;
reg_t BPVCM : 1;
reg_t HPZ : 1;
};
static_assert(sizeof(BeepControl) == sizeof(reg_t), "wrong size struct");
struct DigitalVolumeControl {
reg_t DV : 8;
};
static_assert(sizeof(DigitalVolumeControl) == sizeof(reg_t), "wrong size struct");
using LchDigitalVolumeControl = DigitalVolumeControl;
using RchDigitalVolumeControl = DigitalVolumeControl;
struct EQCommonGainSelect {
reg_t reserved0 : 1;
reg_t EQC2 : 1;
reg_t EQC3 : 1;
reg_t EQC4 : 1;
reg_t EQC5 : 1;
reg_t reserved1 : 3;
};
static_assert(sizeof(EQCommonGainSelect) == sizeof(reg_t), "wrong size struct");
struct EQCommonGainSetting {
reg_t EQnT : 2;
reg_t EQnG : 6;
};
static_assert(sizeof(EQCommonGainSetting) == sizeof(reg_t), "wrong size struct");
using EQ2CommonGainSetting = EQCommonGainSetting;
using EQ3CommonGainSetting = EQCommonGainSetting;
using EQ4CommonGainSetting = EQCommonGainSetting;
using EQ5CommonGainSetting = EQCommonGainSetting;
struct AutoHPFControl {
reg_t STG : 2;
reg_t SENC : 3;
reg_t AHPF : 1;
reg_t reserved0 : 2;
};
static_assert(sizeof(AutoHPFControl) == sizeof(reg_t), "wrong size struct");
struct DigitalFilterSelect1 {
reg_t HPFAD : 1;
reg_t HPFC : 2;
reg_t reserved0 : 5;
};
static_assert(sizeof(DigitalFilterSelect1) == sizeof(reg_t), "wrong size struct");
struct DigitalFilterSelect2 {
reg_t HPF : 1;
reg_t LPF : 1;
reg_t reserved0 : 2;
reg_t FIL3 : 1;
reg_t EQ0 : 1;
reg_t GN : 2;
};
static_assert(sizeof(DigitalFilterSelect2) == sizeof(reg_t), "wrong size struct");
struct DigitalFilterMode {
reg_t PFSDO : 1;
reg_t ADCPF : 1;
reg_t PFDAC : 2;
reg_t PFVOL : 2;
reg_t reserved0 : 2;
};
static_assert(sizeof(DigitalFilterMode) == sizeof(reg_t), "wrong size struct");
struct Coefficient14L {
reg_t l : 8;
};
struct Coefficient14H {
reg_t h : 6;
reg_t reserved0 : 2;
};
static_assert(sizeof(Coefficient14L) == sizeof(reg_t), "wrong size struct");
static_assert(sizeof(Coefficient14H) == sizeof(reg_t), "wrong size struct");
using Coefficient16L = Coefficient14L;
struct Coefficient16H {
reg_t h : 8;
};
static_assert(sizeof(Coefficient16H) == sizeof(reg_t), "wrong size struct");
using HPF2Coefficient0 = Coefficient14L;
using HPF2Coefficient1 = Coefficient14H;
using HPF2Coefficient2 = Coefficient14L;
using HPF2Coefficient3 = Coefficient14H;
using LPFCoefficient0 = Coefficient14L;
using LPFCoefficient1 = Coefficient14H;
using LPFCoefficient2 = Coefficient14L;
using LPFCoefficient3 = Coefficient14H;
using FIL3Coefficient0 = Coefficient14L;
struct FIL3Coefficient1 {
reg_t h : 6;
reg_t reserved0 : 1;
reg_t s : 1;
};
static_assert(sizeof(FIL3Coefficient1) == sizeof(reg_t), "wrong size struct");
using FIL3Coefficient2 = Coefficient14L;
using FIL3Coefficient3 = Coefficient14H;
using EQCoefficient0 = Coefficient16L;
using EQCoefficient1 = Coefficient16H;
using EQCoefficient2 = Coefficient14L;
using EQCoefficient3 = Coefficient14H;
using EQCoefficient4 = Coefficient16L;
using EQCoefficient5 = Coefficient16H;
struct DigitalFilterSelect3 {
reg_t EQ1 : 1;
reg_t EQ2 : 1;
reg_t EQ3 : 1;
reg_t EQ4 : 1;
reg_t EQ5 : 1;
reg_t reserved0 : 3;
};
static_assert(sizeof(DigitalFilterSelect3) == sizeof(reg_t), "wrong size struct");
struct DeviceInformation {
reg_t DVN : 4;
reg_t REV : 4;
};
static_assert(sizeof(DeviceInformation) == sizeof(reg_t), "wrong size struct");
using E1Coefficient0 = Coefficient16L;
using E1Coefficient1 = Coefficient16H;
using E1Coefficient2 = Coefficient16L;
using E1Coefficient3 = Coefficient16H;
using E1Coefficient4 = Coefficient16L;
using E1Coefficient5 = Coefficient16H;
using E2Coefficient0 = Coefficient16L;
using E2Coefficient1 = Coefficient16H;
using E2Coefficient2 = Coefficient16L;
using E2Coefficient3 = Coefficient16H;
using E2Coefficient4 = Coefficient16L;
using E2Coefficient5 = Coefficient16H;
using E3Coefficient0 = Coefficient16L;
using E3Coefficient1 = Coefficient16H;
using E3Coefficient2 = Coefficient16L;
using E3Coefficient3 = Coefficient16H;
using E3Coefficient4 = Coefficient16L;
using E3Coefficient5 = Coefficient16H;
using E4Coefficient0 = Coefficient16L;
using E4Coefficient1 = Coefficient16H;
using E4Coefficient2 = Coefficient16L;
using E4Coefficient3 = Coefficient16H;
using E4Coefficient4 = Coefficient16L;
using E4Coefficient5 = Coefficient16H;
using E5Coefficient0 = Coefficient16L;
using E5Coefficient1 = Coefficient16H;
using E5Coefficient2 = Coefficient16L;
using E5Coefficient3 = Coefficient16H;
using E5Coefficient4 = Coefficient16L;
using E5Coefficient5 = Coefficient16H;
struct Register_Type {
PowerManagement1 power_management_1;
PowerManagement2 power_management_2;
SignalSelect1 signal_select_1;
SignalSelect2 signal_select_2;
SignalSelect3 signal_select_3;
ModeControl1 mode_control_1;
ModeControl2 mode_control_2;
ModeControl3 mode_control_3;
DigitalMIC digital_mic;
TimerSelect timer_select;
ALCTimerSelect alc_timer_select;
ALCModeControl1 alc_mode_control_1;
ALCModeControl2 alc_mode_control_2;
LchInputVolumeControl l_ch_input_volume_control;
RchInputVolumeControl r_ch_input_volume_control;
ALCVolume alc_volume;
reg_t _reserved_0x10;
RchMICGainSetting r_ch_mic_gain_setting;
BeepControl beep_control;
LchDigitalVolumeControl l_ch_digital_volume_control;
RchDigitalVolumeControl r_ch_digital_volume_control;
EQCommonGainSelect eq_common_gain_select;
EQ2CommonGainSetting eq2_common_gain_setting;
EQ3CommonGainSetting eq3_common_gain_setting;
EQ4CommonGainSetting eq4_common_gain_setting;
EQ5CommonGainSetting eq5_common_gain_setting;
AutoHPFControl auto_hpf_control;
DigitalFilterSelect1 digital_filter_select_1;
DigitalFilterSelect2 digital_filter_select_2;
DigitalFilterMode digital_filter_mode;
HPF2Coefficient0 hpf_2_coefficient_0;
HPF2Coefficient1 hpf_2_coefficient_1;
HPF2Coefficient2 hpf_2_coefficient_2;
HPF2Coefficient3 hpf_2_coefficient_3;
LPFCoefficient0 lpf_coefficient_0;
LPFCoefficient1 lpf_coefficient_1;
LPFCoefficient2 lpf_coefficient_2;
LPFCoefficient3 lpf_coefficient_3;
FIL3Coefficient0 fil_3_coefficient_0;
FIL3Coefficient1 fil_3_coefficient_1;
FIL3Coefficient2 fil_3_coefficient_2;
FIL3Coefficient3 fil_3_coefficient_3;
EQCoefficient0 eq_coefficient_0;
EQCoefficient1 eq_coefficient_1;
EQCoefficient2 eq_coefficient_2;
EQCoefficient3 eq_coefficient_3;
EQCoefficient4 eq_coefficient_4;
EQCoefficient5 eq_coefficient_5;
DigitalFilterSelect3 digital_filter_select_3;
DeviceInformation device_information;
E1Coefficient0 e1_coefficient_0;
E1Coefficient1 e1_coefficient_1;
E1Coefficient2 e1_coefficient_2;
E1Coefficient3 e1_coefficient_3;
E1Coefficient4 e1_coefficient_4;
E1Coefficient5 e1_coefficient_5;
E2Coefficient0 e2_coefficient_0;
E2Coefficient1 e2_coefficient_1;
E2Coefficient2 e2_coefficient_2;
E2Coefficient3 e2_coefficient_3;
E2Coefficient4 e2_coefficient_4;
E2Coefficient5 e2_coefficient_5;
E3Coefficient0 e3_coefficient_0;
E3Coefficient1 e3_coefficient_1;
E3Coefficient2 e3_coefficient_2;
E3Coefficient3 e3_coefficient_3;
E3Coefficient4 e3_coefficient_4;
E3Coefficient5 e3_coefficient_5;
E4Coefficient0 e4_coefficient_0;
E4Coefficient1 e4_coefficient_1;
E4Coefficient2 e4_coefficient_2;
E4Coefficient3 e4_coefficient_3;
E4Coefficient4 e4_coefficient_4;
E4Coefficient5 e4_coefficient_5;
E5Coefficient0 e5_coefficient_0;
E5Coefficient1 e5_coefficient_1;
E5Coefficient2 e5_coefficient_2;
E5Coefficient3 e5_coefficient_3;
E5Coefficient4 e5_coefficient_4;
E5Coefficient5 e5_coefficient_5;
};
static_assert(sizeof(Register_Type) == reg_count * sizeof(reg_t), "Register_Type wrong size");
struct RegisterMap {
constexpr RegisterMap(
Register_Type values
) : r(values)
{
}
union {
Register_Type r;
std::array<reg_t, reg_count> w;
};
};
static_assert(sizeof(RegisterMap) == reg_count * sizeof(reg_t), "RegisterMap type wrong size");
constexpr RegisterMap default_after_reset { Register_Type {
.power_management_1 = {
.PMADL = 0,
.PMADR = 0,
.PMDAC = 0,
.reserved0 = 0,
.PMBP = 0,
.PMVCM = 0,
.PMPFIL = 0,
},
.power_management_2 = {
.LOSEL = 0,
.PMSL = 0,
.PMPLL = 0,
.MS = 0,
.PMHPL = 0,
.PMHPR = 0,
.reserved0 = 0,
.PMOSC = 0,
},
.signal_select_1 = {
.MGAIN20 = 0b110,
.PMMP = 0,
.MPSEL = 0,
.DACS = 0,
.MGAIN3 = 0,
.SLPSN = 0,
},
.signal_select_2 = {
.INR = 0b00,
.INL = 0b00,
.MICL = 0,
.reserved0 = 0,
.SPKG = 0b00,
},
.signal_select_3 = {
.MONO = 0b00,
.PTS = 0b01,
.reserved0 = 0,
.DACL = 0,
.LVCM = 0b01,
},
.mode_control_1 = {
.DIF = 0b10,
.CKOFF = 0,
.BCKO = 0,
.PLL = 0b0101,
},
.mode_control_2 = {
.FS = 0b1011,
.reserved0 = 0,
.CM = 0b00,
},
.mode_control_3 = {
.reserved0 = 0,
.IVOLC = 1,
.reserved1 = 0,
.DVOLC = 1,
.SMUTE = 0,
.THDET = 0,
.TSDSEL = 0,
},
.digital_mic = {
.DMIC = 0,
.DCLKP = 0,
.reserved0 = 0,
.DCLKE = 0,
.PMDML = 0,
.PMDMR = 1,
.reserved1 = 0,
.READ = 0,
},
.timer_select = {
.DVTM = 0,
.MOFF = 0,
.reserved0 = 0,
.FRN = 0,
.FRATT = 0,
.ADRST = 0b00,
},
.alc_timer_select = {
.RFST = 0b00,
.WTM = 0b00,
.EQFC = 0b10,
.IVTM = 1,
.reserved0 = 0,
},
.alc_mode_control_1 = {
.LMTH10 = 0b00,
.RGAIN = 0b000,
.ALC = 0,
.LMTH2 = 0,
.ALCEQN = 0,
},
.alc_mode_control_2 = {
.REF = 0xe1,
},
.l_ch_input_volume_control = {
.IV = 0xe1,
},
.r_ch_input_volume_control = {
.IV = 0xe1,
},
.alc_volume = {
.VOL = 0x00, // Read-only.
},
._reserved_0x10 = 0x80,
.r_ch_mic_gain_setting = {
.MGR = 0x80,
},
.beep_control = {
.BPLVL = 0b0000,
.BEEPH = 0,
.BEEPS = 0,
.BPVCM = 0,
.HPZ = 0,
},
.l_ch_digital_volume_control = {
.DV = 0x18,
},
.r_ch_digital_volume_control = {
.DV = 0x18,
},
.eq_common_gain_select = {
.reserved0 = 0,
.EQC2 = 0,
.EQC3 = 0,
.EQC4 = 0,
.EQC5 = 0,
.reserved1 = 0,
},
.eq2_common_gain_setting = {
.EQnT = 0b00,
.EQnG = 0b000000,
},
.eq3_common_gain_setting = {
.EQnT = 0b00,
.EQnG = 0b000000,
},
.eq4_common_gain_setting = {
.EQnT = 0b00,
.EQnG = 0b000000,
},
.eq5_common_gain_setting = {
.EQnT = 0b00,
.EQnG = 0b000000,
},
.auto_hpf_control = {
.STG = 0b00,
.SENC = 0b011,
.AHPF = 0,
.reserved0 = 0,
},
.digital_filter_select_1 = {
.HPFAD = 1,
.HPFC = 0b00,
.reserved0 = 0,
},
.digital_filter_select_2 = {
.HPF = 0,
.LPF = 0,
.reserved0 = 0,
.FIL3 = 0,
.EQ0 = 0,
.GN = 0b00,
},
.digital_filter_mode = {
.PFSDO = 1,
.ADCPF = 1,
.PFDAC = 0b00,
.PFVOL = 0b00,
.reserved0 = 0,
},
.hpf_2_coefficient_0 = { .l = 0xb0 },
.hpf_2_coefficient_1 = { .h = 0x1f, .reserved0 = 0 },
.hpf_2_coefficient_2 = { .l = 0x9f },
.hpf_2_coefficient_3 = { .h = 0x20, .reserved0 = 0 },
.lpf_coefficient_0 = { .l = 0x00 },
.lpf_coefficient_1 = { .h = 0x00, .reserved0 = 0 },
.lpf_coefficient_2 = { .l = 0x00 },
.lpf_coefficient_3 = { .h = 0x00, .reserved0 = 0 },
.fil_3_coefficient_0 = { .l = 0x00 },
.fil_3_coefficient_1 = { .h = 0x00, .reserved0 = 0, .s = 0 },
.fil_3_coefficient_2 = { .l = 0x00 },
.fil_3_coefficient_3 = { .h = 0x00, .reserved0 = 0 },
.eq_coefficient_0 = { .l = 0x00 },
.eq_coefficient_1 = { .h = 0x00 },
.eq_coefficient_2 = { .l = 0x00 },
.eq_coefficient_3 = { .h = 0x00, .reserved0 = 0 },
.eq_coefficient_4 = { .l = 0x00 },
.eq_coefficient_5 = { .h = 0x00 },
.digital_filter_select_3 = {
.EQ1 = 0,
.EQ2 = 0,
.EQ3 = 0,
.EQ4 = 0,
.EQ5 = 0,
.reserved0 = 0,
},
.device_information = {
.DVN = 0b0001,
.REV = 0b1100,
},
.e1_coefficient_0 = { .l = 0x00 },
.e1_coefficient_1 = { .h = 0x00 },
.e1_coefficient_2 = { .l = 0x00 },
.e1_coefficient_3 = { .h = 0x00 },
.e1_coefficient_4 = { .l = 0x00 },
.e1_coefficient_5 = { .h = 0x00 },
.e2_coefficient_0 = { .l = 0x00 },
.e2_coefficient_1 = { .h = 0x00 },
.e2_coefficient_2 = { .l = 0x00 },
.e2_coefficient_3 = { .h = 0x00 },
.e2_coefficient_4 = { .l = 0x00 },
.e2_coefficient_5 = { .h = 0x00 },
.e3_coefficient_0 = { .l = 0x00 },
.e3_coefficient_1 = { .h = 0x00 },
.e3_coefficient_2 = { .l = 0x00 },
.e3_coefficient_3 = { .h = 0x00 },
.e3_coefficient_4 = { .l = 0x00 },
.e3_coefficient_5 = { .h = 0x00 },
.e4_coefficient_0 = { .l = 0x00 },
.e4_coefficient_1 = { .h = 0x00 },
.e4_coefficient_2 = { .l = 0x00 },
.e4_coefficient_3 = { .h = 0x00 },
.e4_coefficient_4 = { .l = 0x00 },
.e4_coefficient_5 = { .h = 0x00 },
.e5_coefficient_0 = { .l = 0x00 },
.e5_coefficient_1 = { .h = 0x00 },
.e5_coefficient_2 = { .l = 0x00 },
.e5_coefficient_3 = { .h = 0x00 },
.e5_coefficient_4 = { .l = 0x00 },
.e5_coefficient_5 = { .h = 0x00 },
} };
class AK4951 : public audio::Codec {
public:
constexpr AK4951(
I2C& bus,
const I2C::address_t bus_address
) : bus(bus),
bus_address(bus_address)
{
}
std::string name() const override {
return "AK4951";
}
bool detected();
void init() override;
bool reset() override;
volume_range_t headphone_gain_range() const override {
return { -89.5_dB, 12.0_dB };
}
void headphone_enable() override;
void headphone_disable() override;
void speaker_enable();
void speaker_disable();
void set_headphone_volume(const volume_t volume) override;
void headphone_mute();
void microphone_enable();
void microphone_disable();
size_t reg_count() const override {
return asahi_kasei::ak4951::reg_count;
}
size_t reg_bits() const override {
return 8;
}
uint32_t reg_read(const size_t reg_address) override {
return read(reg_address);
}
private:
I2C& bus;
const I2C::address_t bus_address;
RegisterMap map { default_after_reset };
enum class LineOutSelect {
Speaker,
Line,
};
void configure_digital_interface_i2s();
void configure_digital_interface_external_slave();
void configure_digital_interface_external_master();
void set_digtal_volume_control(const reg_t value);
void set_dac_power(const bool enable);
void set_headphone_power(const bool enable);
void set_speaker_power(const bool enable);
void select_line_out(const LineOutSelect value);
reg_t read(const address_t reg_address);
void update(const Register reg);
void write(const address_t reg_address, const reg_t value);
};
} /* namespace ak4951 */
} /* namespace asahi_kasei */
#endif/*__AK4951_H__*/

View File

@@ -0,0 +1,27 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "aprs_packet.hpp"
namespace aprs {
} /* namespace zwave */

View File

@@ -0,0 +1,495 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __APRS_PACKET_H__
#define __APRS_PACKET_H__
#include <cstdint>
#include <cstddef>
#include <cctype>
#include "baseband.hpp"
namespace aprs {
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;
};
enum ADDRESS_TYPE {
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;
}
};
} /* namespace aprs */
#endif/*__APRS_PACKET_H__*/

View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "backlight.hpp"
#include "portapack_io.hpp"
namespace portapack {
void BacklightOnOff::on() {
if( !is_on() ) {
io.lcd_backlight(true);
on_ = true;
}
}
void BacklightOnOff::off() {
if( is_on() ) {
io.lcd_backlight(false);
on_ = false;
}
}
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;
}
if( is_on() ) {
pulses(target);
} else {
level_ = target;
}
}
void BacklightCAT4004::on() {
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;
pulses(target_level);
}
}
void BacklightCAT4004::off() {
if( is_on() ) {
io.lcd_backlight(false);
chThdSleepMilliseconds(ms_pwrdwn);
on_ = false;
}
}
void BacklightCAT4004::pulses(value_t target) {
while(level() != target) {
pulse();
}
}
void BacklightCAT4004::pulse() {
io.lcd_backlight(false);
halPolledDelay(ticks_lo);
io.lcd_backlight(true);
halPolledDelay(ticks_hi);
level_ -= 1;
if( level_ < 0 ) {
level_ = levels() - 1;
}
}
} /* namespace portapack */

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <cstdint>
namespace portapack {
class Backlight {
public:
using value_t = int_fast8_t;
virtual ~Backlight() = default;
virtual value_t levels() 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 on() = 0;
virtual void off() = 0;
virtual bool is_on() const = 0;
};
class BacklightBase : public Backlight {
public:
void increase() override {
set_level(level() + 1);
}
void decrease() override {
set_level(level() - 1);
}
};
class BacklightOnOff : public BacklightBase {
public:
value_t levels() const override {
return 1;
}
void set_level(const value_t) override {
}
value_t level() const override {
return levels() - 1;
}
void on() override;
void off() override;
bool is_on() const override {
return on_;
}
private:
static constexpr value_t maximum_level = 1;
bool on_ { false };
};
class BacklightCAT4004 : public BacklightBase {
public:
value_t levels() const override {
return maximum_level + 1;
}
void set_level(const value_t value) override;
value_t level() const override {
return level_;
}
void on() override;
void off() override;
bool is_on() const override {
return on_;
}
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;
value_t level_ { initial_brightness };
bool on_ { false };
void pulses(value_t target);
void pulse();
};
} /* namespace portapack */

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __BASEBAND_H__
#define __BASEBAND_H__
#include "complex.hpp"
#include "buffer.hpp"
namespace baseband {
using sample_t = complex8_t;
using buffer_t = buffer_t<sample_t>;
enum class Direction {
Receive = 0,
Transmit = 1,
};
} /* namespace baseband */
#endif/*__BASEBAND_H__*/

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "baseband_cpld.hpp"
#include "hackrf_gpio.hpp"
using namespace hackrf::one;
namespace baseband {
void CPLD::init() {
set_invert(false);
gpio_baseband_invert.output();
}
void CPLD::set_invert(const bool invert) {
gpio_baseband_invert.write(invert);
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __BASEBAND_CPLD_H__
#define __BASEBAND_CPLD_H__
#include <cstdint>
namespace baseband {
class CPLD {
public:
void init();
void set_invert(const bool invert);
private:
};
}
#endif/*__BASEBAND_CPLD_H__*/

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __BASEBAND_PACKET_H__
#define __BASEBAND_PACKET_H__
#include "baseband.hpp"
#include <cstddef>
#include <bitset>
namespace baseband {
class Packet {
public:
void set_timestamp(const Timestamp& value) {
timestamp_ = value;
}
Timestamp timestamp() const {
return timestamp_;
}
void add(const bool symbol) {
if( count < capacity() ) {
data[count++] = symbol;
}
}
uint_fast8_t operator[](const size_t index) const {
return (index < size()) ? data[index] : 0;
}
size_t size() const {
return count;
}
size_t capacity() const {
return data.size();
}
void clear() {
count = 0;
}
private:
std::bitset<2560> data { };
Timestamp timestamp_ { };
size_t count { 0 };
};
} /* namespace baseband */
#endif/*__BASEBAND_PACKET_H__*/

View File

@@ -0,0 +1,392 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "baseband_sgpio.hpp"
#include "baseband.hpp"
#include "utility.hpp"
namespace baseband {
/*
struct PinConfig {
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)
{
}
};
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;
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, },
} };
*/
/*
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,
};
enum class P_OE_CFG : uint8_t {
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,
};
enum class CONCAT_ENABLE : uint8_t {
EXTERNAL_DATA_PIN = 0x0,
CONCATENATE_DATA = 0x1,
};
enum class CLK_CAPTURE_MODE : uint8_t {
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,
};
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,
};
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,
};
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 uint32_t gpio_outreg(const Direction direction) {
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)
;
}
constexpr uint32_t out_mux_cfg(const P_OUT_CFG out, const P_OE_CFG oe) {
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)
;
}
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)
;
}
constexpr uint32_t pos(
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)
);
}
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
;
}
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
;
}
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
;
}
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
;
}
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 },
};
void SGPIO::init() {
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();
// 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);
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;
}
// 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 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);
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;
slice_enable_mask |= (1U << slice_index);
}
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->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);
}
set_slice_counter_enables(slice_enable_mask);
}
} /* namespace baseband */

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __BASEBAND_GPIO_H__
#define __BASEBAND_GPIO_H__
#include <cstdint>
#include "baseband.hpp"
#include "hal.h"
namespace baseband {
class SGPIO {
public:
void init();
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_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;
}
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;
}
};
}
#endif/*__BASEBAND_GPIO_H__*/

View File

@@ -0,0 +1,364 @@
/*
* Copyright (C) 2015 Craig Shelley (craig@microtron.org.uk)
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include <math.h>
#include <stdlib.h>
#include <ch.h>
#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;
}
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? :)
*/
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;
} 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 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.
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;
}
}
return retval;
}
/*
* Example usage BCH(31,21,5)
*
* p[] = coefficients of primitive polynomial used to generate GF(2**5)
* m = order of the field GF(2**5) = 5
* n = 2**5 - 1 = 31
* t = 2 = error correcting capability
* d = 2*t + 1 = 5 = designed minimum distance
* k = n - deg(g(x)) = 21 = dimension
* g[] = coefficients of generator polynomial, g(x) [n - k + 1]=[11]
* alpha_to [] = log table of GF(2**5)
* index_of[] = antilog table of GF(2**5)
* data[] = coefficients of data polynomial, i(x)
* 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];
}
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);
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2015 Craig Shelley (craig@microtron.org.uk)
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __BCHCODE_H__
#define __BCHCODE_H__
#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;
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__*/

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __BIT_PATTERN_H__
#define __BIT_PATTERN_H__
#include <cstdint>
#include <cstddef>
class BitHistory {
public:
void add(const uint_fast8_t bit) {
history = (history << 1) | (bit & 1);
}
uint64_t value() const {
return history;
}
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 }
{
}
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__*/

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2014 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#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;
};
#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];
};
#pragma pack(pop)

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "buffer.hpp"
#if defined(LPC43XX_M4)
#include "lpc43xx_m4.h"
Timestamp Timestamp::now() {
// 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) );
return timestamp;
}
#endif

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __BUFFER_H__
#define __BUFFER_H__
#include <cstdint>
#include <cstddef>
/* LPC43xx RTC structure. Avoiding using the ChibiOS-defined structure because
* it pulls in all sorts of dependencies and initialization and other stuff that
* the M0 needs to remain in control of.
*
* But yes, this is a hack, and something better is needed. It's too tangled of
* a knot to tackle at the moment, though...
*/
#if defined(LPC43XX_M4)
struct Timestamp {
uint32_t tv_date { 0 };
uint32_t tv_time { 0 };
static Timestamp now();
};
#endif
#if defined(LPC43XX_M0)
#include "lpc43xx_cpp.hpp"
using Timestamp = lpc43xx::rtc::RTC;
#endif
template<typename T>
struct buffer_t {
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(
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 }
{
}
operator bool() const {
return (p != nullptr);
}
};
#endif/*__BUFFER_H__*/

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "buffer_exchange.hpp"
BufferExchange* BufferExchange::obj { nullptr };
BufferExchange::BufferExchange(
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;
}
BufferExchange::BufferExchange(
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;
}
BufferExchange::~BufferExchange() {
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;
}
// 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;
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include "ch.h"
#include "message.hpp"
#include "fifo.hpp"
#include "io.hpp"
class 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;
#if defined(LPC43XX_M0)
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);
}
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();
}
StreamBuffer* get() {
return get(fifo_buffers_for_baseband);
}
bool put(StreamBuffer* const p) {
return fifo_buffers_for_application->in(p);
}
#endif
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 { };
void check_fifo_isr() {
if (!empty())
wakeup_isr();
}
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

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "chibios_cpp.hpp"
#include <cstdint>
#include <ch.h>
void* operator new(size_t size) {
return chHeapAlloc(0x0, size);
}
void* operator new[](size_t size) {
return chHeapAlloc(0x0, size);
}
void operator delete(void* p) noexcept {
chHeapFree(p);
}
void operator delete[](void* p) noexcept {
chHeapFree(p);
}
void operator delete(void* ptr, std::size_t) noexcept {
::operator delete(ptr);
}
void operator delete[](void* ptr, std::size_t) noexcept {
::operator delete(ptr);
}
extern uint8_t __heap_base__[];
extern uint8_t __heap_end__[];
namespace chibios {
size_t heap_size() {
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);
}
} /* namespace chibios */

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __CHIBIOS_CPP_H__
#define __CHIBIOS_CPP_H__
#include <cstddef>
/* Override new/delete to use Chibi/OS heap functions */
/* NOTE: Do not inline these, it doesn't work. ;-) */
void* operator new(size_t size);
void* operator new[](size_t size);
void operator delete(void* p);
void operator delete[](void* p);
void operator delete(void* ptr, std::size_t);
void operator delete[](void* ptr, std::size_t);
namespace chibios {
size_t heap_size();
size_t heap_used();
} /* namespace chibios */
#endif/*__CHIBIOS_CPP_H__*/

View File

@@ -0,0 +1,139 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __COMPLEX_H__
#define __COMPLEX_H__
#include <cstdint>
#include <complex>
#include <cmath>
constexpr float pi { 3.141592653589793238462643383279502884f };
namespace std {
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(
int8_t re = 0,
int8_t im = 0
) : _v { re, im }
{
}
// constexpr complex(
// const complex& o
// ) : _rep { o._rep }
// {
// }
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; }
constexpr uint16_t __rep() const {
return _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;
// constexpr complex(
// rep_type r
// ) : _rep { r }
// {
// }
constexpr complex(
int16_t re = 0,
int16_t im = 0
) : _v { re, im }
{
}
// constexpr complex(
// const complex& o
// ) : _rep { o._rep }
// {
// }
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; }
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 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;
};
};
} /* namespace std */
using complex8_t = std::complex<int8_t>;
using complex16_t = std::complex<int16_t>;
using complex32_t = std::complex<int32_t>;
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__*/

View File

@@ -0,0 +1,274 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "cpld_max5.hpp"
#include "jtag.hpp"
#include <cstdint>
#include <array>
namespace cpld {
namespace max5 {
void CPLD::bypass() {
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);
}
}
void CPLD::sample(std::bitset<240>& 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);
}
void CPLD::clamp() {
shift_ir(instruction_t::CLAMP);
jtag.runtest_tck(93);
}
void CPLD::enable() {
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
}
/* Sector erase:
* Involves shifting in the instruction to erase the device and applying
* an erase pulse or pulses. The erase pulse is automatically generated
* internally by waiting in the run, test, or idle state for the
* specified erase pulse time of 500 ms for the CFM block and 500 ms for
* each sector of the user flash memory (UFM) block.
*/
void CPLD::bulk_erase() {
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();
/* 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);
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
}
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;
}
uint32_t CPLD::crc() {
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
}
bool CPLD::idcode_ok() {
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
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:
* 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 CPLD::silicon_id_ok() {
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)
);
}
uint32_t CPLD::usercode() {
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
}
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
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
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
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
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;
}
} /* namespace max5 */
} /* namespace cpld */

View File

@@ -0,0 +1,203 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __CPLD_MAX5_H__
#define __CPLD_MAX5_H__
#include "jtag.hpp"
#include "crc.hpp"
#include <cstdint>
#include <cstddef>
#include <array>
#include <bitset>
namespace cpld {
namespace max5 {
struct Config {
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)
{
}
void bypass();
void sample();
void sample(std::bitset<240>& value);
void extest(std::bitset<240>& value);
void clamp();
void reset() {
jtag.reset();
}
void run_test_idle() {
jtag.run_test_idle();
}
bool idcode_ok();
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();
uint32_t usercode();
void disable();
void bulk_erase();
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 is_blank();
uint32_t crc();
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;
using ir_t = uint16_t;
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_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);
}
void shift_dr(std::bitset<240>& value) {
for(size_t i=0; i<value.size(); i++) {
value[i] = shift_dr(1, value[i]);
}
}
uint32_t shift_dr(const size_t count, const uint32_t value) {
return jtag.shift_dr(count, value);
}
jtag::JTAG& jtag;
std::array<uint16_t, 5> read_silicon_id();
void sector_select(const uint16_t id);
void erase_sector(const uint16_t id);
void program_block(
const uint16_t id,
const uint16_t* const data,
const size_t count
);
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 verify_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());
}
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.exit_isp();
}
private:
CPLD& cpld;
};
*/
} /* namespace max5 */
} /* namespace cpld */
#endif/*__CPLD_MAX5_H__*/

View File

@@ -0,0 +1,134 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "cpld_update.hpp"
#include "hackrf_gpio.hpp"
#include "portapack_hal.hpp"
#include "jtag_target_gpio.hpp"
#include "cpld_max5.hpp"
#include "cpld_xilinx.hpp"
#include "portapack_cpld_data.hpp"
#include "hackrf_cpld_data.hpp"
namespace portapack {
namespace cpld {
bool 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 };
/* Unknown state */
cpld.reset();
cpld.run_test_idle();
/* Run-Test/Idle */
if( !cpld.idcode_ok() ) {
return false;
}
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 false;
}
/* 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);
}
/* 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();
}
return ok;
}
} /* namespace cpld */
} /* namespace portapack */
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,
};
}
bool load_sram() {
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);
return ok;
}
bool verify_eeprom() {
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;
}
void init_from_eeprom() {
auto jtag_target_hackrf_cpld = jtag_target_hackrf();
hackrf::one::cpld::CPLD hackrf_cpld { jtag_target_hackrf_cpld };
hackrf_cpld.init_from_eeprom();
}
} /* namespace cpld */
} /* namespace hackrf */

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __CPLD_UPDATE_H__
#define __CPLD_UPDATE_H__
#include "portapack_cpld_data.hpp"
namespace portapack {
namespace cpld {
bool update_if_necessary(
const Config config
);
} /* namespace cpld */
} /* namespace portapack */
namespace hackrf {
namespace cpld {
bool load_sram();
bool verify_eeprom();
void init_from_eeprom();
} /* namespace cpld */
} /* namespace hackrf */
#endif/*__CPLD_UPDATE_H__*/

View File

@@ -0,0 +1,179 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "cpld_xilinx.hpp"
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);
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);
}
disable();
bypass();
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);
reset();
enable();
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 };
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);
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);
reset();
bypass();
enable();
shift_ir(instruction_t::ISC_READ);
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);
}
disable();
bypass();
tap.state(state_t::test_logic_reset);
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);
reset();
enable();
discharge();
init();
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);
}
void XC2C64A::reset() {
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);
}
void XC2C64A::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);
}
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);
}
void XC2C64A::disable() {
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);
}
} /* namespace xilinx */
} /* namespace cpld */

View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __CPLD_XILINX_H__
#define __CPLD_XILINX_H__
#include "jtag_tap.hpp"
#include "utility.hpp"
#include <cstdint>
#include <cstddef>
#include <array>
namespace cpld {
namespace xilinx {
using jtag::tap::state_t;
class XC2C64A {
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_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 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>;
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);
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;
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;
using ir_t = uint8_t;
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
};
bool shift_ir(const instruction_t instruction);
void reset();
void enable();
void enable_otf();
void discharge();
void init();
void disable();
bool bypass();
};
} /* namespace xilinx */
} /* namespace cpld */
#endif/*__CPLD_XILINX_H__*/

View File

@@ -0,0 +1,195 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __CRC_H__
#define __CRC_H__
#include <cstddef>
#include <cstdint>
#include <limits>
#include <array>
/* Inspired by
* http://www.barrgroup.com/Embedded-Systems/How-To/CRC-Calculation-C-Code
*
* ...then munged into a simplified implementation of boost::crc_basic and
* boost::crc_optimal.
* http://www.boost.org/doc/libs/release/libs/crc/
*
* Copyright 2001, 2004 Daryle Walker. Use, modification, and distribution are
* subject to the Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
*
*/
template<size_t Width, bool RevIn = false, bool RevOut = false>
class CRC {
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 }
{
}
value_type get_initial_remainder() const {
return initial_remainder;
}
void reset(value_type new_initial_remainder) {
remainder = new_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_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_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());
}
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;
static constexpr size_t width() {
return Width;
}
static constexpr value_type top_bit() {
return 1U << (width() - 1);
}
static constexpr value_type mask() {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
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;
}
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));
}
}
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);
}
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));
}
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;
uint32_t a { 1 };
uint32_t b { 0 };
void feed_one(const uint8_t c) {
a = (a + c) % mod;
b = (b + a) % mod;
}
};
#endif/*__CRC_H__*/

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "debug.hpp"
#include <ch.h>
#include <hal.h>
#include "portapack_shared_memory.hpp"
#if defined(LPC43XX_M0)
static void debug_indicate_error_init() {
// TODO: Get knowledge of LED GPIO port/bit from shared place.
LPC_GPIO->CLR[2] = (1 << 2);
}
static void debug_indicate_error_update() {
// Flash RX (yellow) LED to indicate baseband error.
// TODO: Get knowledge of LED GPIO port/bit from shared place.
LPC_GPIO->NOT[2] = (1 << 2);
}
#endif
#if defined(LPC43XX_M4)
static void debug_indicate_error_init() {
// TODO: Get knowledge of LED GPIO port/bit from shared place.
LPC_GPIO->CLR[2] = (1 << 8);
}
static void debug_indicate_error_update() {
// Flash TX (red) LED to indicate baseband error.
// TODO: Get knowledge of LED GPIO port/bit from shared place.
LPC_GPIO->NOT[2] = (1 << 8);
}
#endif
static void runtime_error() {
debug_indicate_error_init();
while(true) {
volatile size_t n = 1000000U;
while(n--);
debug_indicate_error_update();
}
}
extern "C" {
void port_halt(void) {
// Copy debug panic message to M0 region.
const auto* p = dbg_panic_msg;
for(size_t i=0; i<sizeof(shared_memory.m4_panic_msg); i++) {
if( *p == 0 ) {
shared_memory.m4_panic_msg[i] = 0;
} else {
shared_memory.m4_panic_msg[i] = *(p++);
}
}
port_disable();
runtime_error();
}
#if defined(LPC43XX_M4)
CH_IRQ_HANDLER(MemManageVector) {
#if CH_DBG_ENABLED
chDbgPanic("MemManage");
#else
chSysHalt();
#endif
}
CH_IRQ_HANDLER(BusFaultVector) {
#if CH_DBG_ENABLED
chDbgPanic("BusFault");
#else
chSysHalt();
#endif
}
CH_IRQ_HANDLER(UsageFaultVector) {
#if CH_DBG_ENABLED
chDbgPanic("UsageFault");
#else
chSysHalt();
#endif
}
#endif
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DEBUG_H__
#define __DEBUG_H__
#endif/*__DEBUG_H__*/

View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "dsp_fft.hpp"

View File

@@ -0,0 +1,138 @@
/*
* Copyright (C) 2013 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_FFT_H__
#define __DSP_FFT_H__
#include <cstdint>
#include <cstddef>
#include <complex>
#include <cmath>
#include <type_traits>
#include <array>
#include "dsp_types.hpp"
#include "complex.hpp"
#include "hal.h"
#include "utility.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()
};
}
} /* namespace std */
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");
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>
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");
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>
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");
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>
void fft_swap_in_place(std::array<T, N>& data) {
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]);
}
}
/* 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>
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;
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;
}
}
}
#endif/*__DSP_FFT_H__*/

View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "dsp_fir_taps.hpp"

View File

@@ -0,0 +1,431 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_FIR_TAPS_H__
#define __DSP_FIR_TAPS_H__
#include <cstdint>
#include <array>
#include "complex.hpp"
template<size_t N>
struct fir_taps_real {
float low_frequency_normalized;
float high_frequency_normalized;
float transition_normalized;
std::array<int16_t, N> taps;
};
template<size_t N>
struct fir_taps_complex {
float low_frequency_normalized;
float high_frequency_normalized;
float transition_normalized;
std::array<complex16_t, N> taps;
};
// NBFM 16K0F3E emission type /////////////////////////////////////////////
// IFIR image-reject filter: fs=3072000, pass=8000, stop=344000, decim=8, fout=384000
constexpr fir_taps_real<24> taps_16k0_decim_0 {
.low_frequency_normalized = -8000.0f / 3072000.0f,
.high_frequency_normalized = 8000.0f / 3072000.0f,
.transition_normalized = 336000.0f / 3072000.0f,
.taps = { {
1, 67, 165, 340, 599, 944, 1361, 1820,
2278, 2684, 2988, 3152, 3152, 2988, 2684, 2278,
1820, 1361, 944, 599, 340, 165, 67, 1,
} },
};
// IFIR prototype filter: fs=384000, pass=8000, stop=40000, decim=8, fout=48000
constexpr fir_taps_real<32> taps_16k0_decim_1 {
.low_frequency_normalized = -8000.0f / 384000.0f,
.high_frequency_normalized = 8000.0f / 384000.0f,
.transition_normalized = 32000.0f / 384000.0f,
.taps = { {
-26, -125, -180, -275, -342, -359, -286, -90,
250, 733, 1337, 2011, 2688, 3289, 3740, 3982,
3982, 3740, 3289, 2688, 2011, 1337, 733, 250,
-90, -286, -359, -342, -275, -180, -125, -26,
} },
};
// Channel filter: fs=48000, pass=8000, stop=12400, decim=1, fout=48000
constexpr fir_taps_real<32> taps_16k0_channel {
.low_frequency_normalized = -8000.0f / 48000.0f,
.high_frequency_normalized = 8000.0f / 48000.0f,
.transition_normalized = 4400.0f / 48000.0f,
.taps = { {
-73, -285, -376, -8, 609, 538, -584, -1387,
-148, 2173, 1959, -2146, -5267, -297, 12915, 24737,
24737, 12915, -297, -5267, -2146, 1959, 2173, -148,
-1387, -584, 538, 609, -8, -376, -285, -73,
} },
};
// NBFM 11K0F3E emission type /////////////////////////////////////////////
// IFIR image-reject filter: fs=3072000, pass=5500, stop=341500, decim=8, fout=384000
constexpr fir_taps_real<24> taps_11k0_decim_0 {
.low_frequency_normalized = -5500.0f / 3072000.0f,
.high_frequency_normalized = 5500.0f / 3072000.0f,
.transition_normalized = 336000.0f / 3072000.0f,
.taps = { {
38, 102, 220, 406, 668, 1004, 1397, 1822,
2238, 2603, 2875, 3020, 3020, 2875, 2603, 2238,
1822, 1397, 1004, 668, 406, 220, 102, 38,
} },
};
// IFIR prototype filter: fs=384000, pass=5500, stop=42500, decim=8, fout=48000
constexpr fir_taps_real<32> taps_11k0_decim_1 {
.low_frequency_normalized = -5500.0f / 384000.0f,
.high_frequency_normalized = 5500.0f / 384000.0f,
.transition_normalized = 37000.0f / 384000.0f,
.taps = { {
-42, -87, -157, -234, -298, -318, -255, -75,
246, 713, 1306, 1976, 2656, 3265, 3724, 3971,
3971, 3724, 3265, 2656, 1976, 1306, 713, 246,
-75, -255, -318, -298, -234, -157, -87, -42,
} },
};
// Channel filter: fs=48000, pass=5500, stop=8900, decim=1, fout=48000
constexpr fir_taps_real<32> taps_11k0_channel {
.low_frequency_normalized = -5500.0f / 48000.0f,
.high_frequency_normalized = 5500.0f / 48000.0f,
.transition_normalized = 3400.0f / 48000.0f,
.taps = { {
-68, -345, -675, -867, -582, 247, 1222, 1562,
634, -1379, -3219, -3068, 310, 6510, 13331, 17795,
17795, 13331, 6510, 310, -3068, -3219, -1379, 634,
1562, 1222, 247, -582, -867, -675, -345, -68,
} },
};
// NBFM 8K50F3E emission type /////////////////////////////////////////////
// IFIR image-reject filter: fs=3072000, pass=4250, stop=340250, decim=8, fout=384000
constexpr fir_taps_real<24> taps_4k25_decim_0 {
.low_frequency_normalized = -4250.0f / 3072000.0f,
.high_frequency_normalized = 4250.0f / 3072000.0f,
.transition_normalized = 33600.0f / 3072000.0f,
.taps = { {
38, 103, 222, 409, 671, 1006, 1399, 1821,
2236, 2599, 2868, 3012, 3012, 2868, 2599, 2236,
1821, 1399, 1006, 671, 409, 222, 103, 38,
} },
};
// IFIR prototype filter: fs=384000, pass=4250, stop=43750, decim=8, fout=48000
constexpr fir_taps_real<32> taps_4k25_decim_1 {
.low_frequency_normalized = -4250.0f / 384000.0f,
.high_frequency_normalized = 4250.0f / 384000.0f,
.transition_normalized = 39500.0f / 384000.0f,
.taps = { {
-33, -74, -139, -214, -280, -306, -254, -87,
222, 682, 1274, 1951, 2644, 3268, 3741, 3996,
3996, 3741, 3268, 2644, 1951, 1274, 682, 222,
-87, -254, -306, -280, -214, -139, -74, -33,
} },
};
// Channel filter: fs=48000, pass=4250, stop=7900, decim=1, fout=48000
constexpr fir_taps_real<32> taps_4k25_channel {
.low_frequency_normalized = -4250.0f / 48000.0f,
.high_frequency_normalized = 4250.0f / 48000.0f,
.transition_normalized = 3650.0f / 48000.0f,
.taps = { {
-58, -14, 153, 484, 871, 1063, 770, -141,
-1440, -2488, -2435, -614, 3035, 7771, 12226, 14927,
14927, 12226, 7771, 3035, -614, -2435, -2488, -1440,
-141, 770, 1063, 871, 484, 153, -14, -58,
} },
};
/* CTCSS audio filter */
/* 12kHz int16_t input
* -> FIR filter, <300Hz pass, >300Hz stop, gain of 1
* -> 6kHz int16_t output, gain of 1.0 (I think).
* Padded to multiple of four taps for unrolled FIR code.
* sum(abs(taps)): 125270
*/
/*constexpr fir_taps_real<64> taps_64_lp_025_025 {
.taps = { {
0, 0, -3, -7, -13, -20, -27, -32,
-34, -33, -25, -10, 13, 47, 94, 152,
223, 307, 402, 508, 622, 742, 866, 991,
1113, 1229, 1336, 1430, 1510, 1571, 1614, 1635,
1635, 1614, 1571, 1510, 1430, 1336, 1229, 1113,
991, 866, 742, 622, 508, 402, 307, 223,
152, 94, 47, 13, -10, -25, -33, -34,
-32, -27, -20, -13, -7, -3, 0, 0
} },
};*/
/* CTCSS audio filter */
/* 24kHz int16_t input
* -> FIR filter, <300Hz pass, >300Hz stop, gain of 1
* -> 12kHz int16_t output, gain of 1.0 (I think).
* Padded to multiple of four taps for unrolled FIR code.
* sum(abs(taps)): 125270
*/
constexpr fir_taps_real<64> taps_64_lp_025_025 {
.low_frequency_normalized = 0,
.high_frequency_normalized = 0,
.transition_normalized = 0,
.taps = { {
0, 0, 2, 6, 12, 20, 32, 46,
64, 85, 110, 138, 169, 204, 241, 281,
323, 367, 412, 457, 502, 547, 590, 631,
669, 704, 735, 762, 784, 801, 812, 818,
818, 812, 801, 784, 762, 735, 704, 669,
631, 590, 547, 502, 457, 412, 367, 323,
281, 241, 204, 169, 138, 110, 85, 64,
46, 32, 20, 12, 6, 2, 0, 0
} },
};
// DSB AM 6K00A3E emission type ///////////////////////////////////////////
// IFIR image-reject filter: fs=3072000, pass=3000, stop=339000, decim=8, fout=384000
constexpr fir_taps_real<24> taps_6k0_decim_0 {
.low_frequency_normalized = -3000.0f / 3072000.0f,
.high_frequency_normalized = 3000.0f / 3072000.0f,
.transition_normalized = 336000.0f / 3072000.0f,
.taps = { {
39, 104, 224, 412, 674, 1008, 1400, 1821,
2234, 2594, 2863, 3006, 3006, 2863, 2594, 2234,
1821, 1400, 1008, 674, 412, 224, 104, 39,
} },
};
// IFIR prototype filter: fs=384000, pass=3000, stop=45000, decim=8, fout=48000
constexpr fir_taps_real<32> taps_6k0_decim_1 {
.low_frequency_normalized = -3000.0f / 384000.0f,
.high_frequency_normalized = 3000.0f / 384000.0f,
.transition_normalized = 43000.0f / 384000.0f,
.taps = { {
-26, -63, -123, -195, -263, -295, -253, -99,
199, 651, 1242, 1927, 2633, 3273, 3760, 4023,
4023, 3760, 3273, 2633, 1927, 1242, 651, 199,
-99, -253, -295, -263, -195, -123, -63, -26,
} },
};
// IFIR prototype filter: fs=48000, pass=3000, stop=6700, decim=4, fout=12000
constexpr fir_taps_real<32> taps_6k0_decim_2 {
.low_frequency_normalized = -3000.0f / 48000.0f,
.high_frequency_normalized = 3000.0f / 48000.0f,
.transition_normalized = 3700.0f / 48000.0f,
.taps = { {
95, 178, 247, 208, -21, -474, -1080, -1640,
-1857, -1411, -83, 2134, 4978, 7946, 10413, 11815,
11815, 10413, 7946, 4978, 2134, -83, -1411, -1857,
-1640, -1080, -474, -21, 208, 247, 178, 95,
} },
};
// Channel filter: fs=12000, pass=3000, stop=3300, decim=1, fout=12000
/* NOTE: Slightly less than 1.0 gain (normalized to 65536) due to max(taps) being
* slightly larger than 32767 (33312).
*/
constexpr fir_taps_complex<64> taps_6k0_dsb_channel {
.low_frequency_normalized = -3000.0f / 12000.0f,
.high_frequency_normalized = 3000.0f / 12000.0f,
.transition_normalized = 300.0f / 12000.0f,
.taps = { {
{ -69, 0 }, { -140, 0 }, { 119, 0 }, { 89, 0 },
{ -132, 0 }, { -134, 0 }, { 197, 0 }, { 167, 0 },
{ -273, 0 }, { -206, 0 }, { 372, 0 }, { 247, 0 },
{ -497, 0 }, { -289, 0 }, { 654, 0 }, { 331, 0 },
{ -854, 0 }, { -372, 0 }, { 1112, 0 }, { 411, 0 },
{ -1455, 0 }, { -446, 0 }, { 1933, 0 }, { 476, 0 },
{ -2654, 0 }, { -501, 0 }, { 3902, 0 }, { 520, 0 },
{ -6717, 0 }, { -531, 0 }, { 20478, 0 }, { 32767, 0 },
{ 20478, 0 }, { -531, 0 }, { -6717, 0 }, { 520, 0 },
{ 3902, 0 }, { -501, 0 }, { -2654, 0 }, { 476, 0 },
{ 1933, 0 }, { -446, 0 }, { -1455, 0 }, { 411, 0 },
{ 1112, 0 }, { -372, 0 }, { -854, 0 }, { 331, 0 },
{ 654, 0 }, { -289, 0 }, { -497, 0 }, { 247, 0 },
{ 372, 0 }, { -206, 0 }, { -273, 0 }, { 167, 0 },
{ 197, 0 }, { -134, 0 }, { -132, 0 }, { 89, 0 },
{ 119, 0 }, { -140, 0 }, { -69, 0 }, { 0, 0 },
} },
};
// USB AM 2K80J3E emission type ///////////////////////////////////////////
// IFIR prototype filter: fs=12000, pass=3000, stop=3300, decim=1, fout=12000
constexpr fir_taps_complex<64> taps_2k8_usb_channel {
.low_frequency_normalized = 0,
.high_frequency_normalized = 3000.0f / 12000.0f,
.transition_normalized = 300.0f / 12000.0f,
.taps = { {
{ -146, 0 }, { -41, -45 }, { -1, 10 }, { -95, 69 },
{ -194, -41 }, { -91, -158 }, { 14, -43 }, { -150, 67 },
{ -299, -133 }, { -100, -307 }, { 50, -86 }, { -254, 54 },
{ -453, -329 }, { -62, -587 }, { 170, -189 }, { -334, 0 },
{ -580, -645 }, { 104, -986 }, { 418, -304 }, { -412, -88 },
{ -680, -1178 }, { 527, -1623 }, { 970, -432 }, { -441, -196 },
{ -698, -2149 }, { 1617, -2800 }, { 2384, -507 }, { -429, -311 },
{ -545, -5181 }, { 6925, -7691 }, { 14340, 0 }, { 10601, 11773 },
{ -1499, 14261 }, { -8373, 6083 }, { -5095, -1083 }, { -265, -459 },
{ -753, 2318 }, { -2954, 1315 }, { -2064, -919 }, { -149, -459 },
{ -531, 920 }, { -1669, 355 }, { -1100, -800 }, { -44, -419 },
{ -346, 384 }, { -992, 0 }, { -580, -645 }, { 35, -332 },
{ -205, 149 }, { -577, -123 }, { -280, -485 }, { 80, -247 },
{ -91, 40 }, { -294, -131 }, { -101, -312 }, { 82, -142 },
{ -44, 9 }, { -147, -107 }, { -21, -197 }, { 79, -88 },
{ 10, 0 }, { -41, -45 }, { 15, -145 }, { 0, 0 },
} },
};
// LSB AM 2K80J3E emission type ///////////////////////////////////////////
// IFIR prototype filter: fs=12000, pass=3000, stop=3300, decim=1, fout=12000
constexpr fir_taps_complex<64> taps_2k8_lsb_channel {
.low_frequency_normalized = -3000.0f / 12000.0f,
.high_frequency_normalized = 0,
.transition_normalized = 300.0f / 12000.0f,
.taps = { {
{ -146, 0 }, { -41, 45 }, { -1, -10 }, { -95, -69 },
{ -194, 41 }, { -91, 158 }, { 14, 43 }, { -150, -67 },
{ -299, 133 }, { -100, 307 }, { 50, 86 }, { -254, -54 },
{ -453, 329 }, { -62, 587 }, { 170, 189 }, { -334, 0 },
{ -580, 645 }, { 104, 986 }, { 418, 304 }, { -412, 88 },
{ -680, 1178 }, { 527, 1623 }, { 970, 432 }, { -441, 196 },
{ -698, 2149 }, { 1617, 2800 }, { 2384, 507 }, { -429, 311 },
{ -545, 5181 }, { 6925, 7691 }, { 14340, 0 }, { 10601, -11773 },
{ -1499, -14261 }, { -8373, -6083 }, { -5095, 1083 }, { -265, 459 },
{ -753, -2318 }, { -2954, -1315 }, { -2064, 919 }, { -149, 459 },
{ -531, -920 }, { -1669, -355 }, { -1100, 800 }, { -44, 419 },
{ -346, -384 }, { -992, 0 }, { -580, 645 }, { 35, 332 },
{ -205, -149 }, { -577, 123 }, { -280, 485 }, { 80, 247 },
{ -91, -40 }, { -294, 131 }, { -101, 312 }, { 82, 142 },
{ -44, -9 }, { -147, 107 }, { -21, 197 }, { 79, 88 },
{ 10, 0 }, { -41, 45 }, { 15, 145 }, { 0, 0 },
} },
};
// USB AM 700Hz filter: fs=12000, start=600, end=800, width=200, stop=40db, decim=1, fout=12000
constexpr fir_taps_complex<64> taps_0k7_usb_channel {
.low_frequency_normalized = 600.0f / 12000.0f,
.high_frequency_normalized = 800.0f / 12000.0f,
.transition_normalized = 200.0f / 12000.0f,
.taps = { {
{ 531, 0 }, { 192, 73 }, { 181, 163 }, { 129, 254 },
{ 34, 328 }, { -97, 364 }, { -251, 345 }, { -403, 261 },
{ -524, 111 }, { -585, -92 }, { -564, -326 }, { -448, -554 },
{ -239, -737 }, { 43, -836 }, { 366, -822 }, { 681, -681 },
{ 936, -417 }, { 1085, -56 }, { 1090, 354 }, { 935, 757 },
{ 629, 1090 }, { 205, 1296 }, { -283, 1331 }, { -766, 1180 },
{ -1172, 851 }, { -1435, 384 }, { -1510, -158 }, { -1377, -702 },
{ -1049, -1165 }, { -568, -1480 }, { 0, -1596 }, { 574, -1496 },
{ 1072, -1191 }, { 1422, -724 }, { 1576, -165 }, { 1515, 406 },
{ 1251, 908 }, { 827, 1273 }, { 309, 1453 }, { -226, 1431 },
{ -703, 1218 }, { -1058, 856 }, { -1248, 405 }, { -1257, -65 },
{ -1100, -489 }, { -810, -810 }, { -441, -992 }, { -53, -1024 },
{ 297, -916 }, { 566, -699 }, { 725, -418 }, { 765, -121 },
{ 697, 148 }, { 546, 355 }, { 348, 479 }, { 138, 517 },
{ -50, 477 }, { -194, 381 }, { -280, 252 }, { -308, 118 },
{ -285, 0 }, { -228, -87 }, { -153, -138 }, { -241, -473 },
} },
};
// WFM 200KF8E emission type //////////////////////////////////////////////
// IFIR image-reject filter: fs=3072000, pass=100000, stop=484000, decim=4, fout=768000
constexpr fir_taps_real<24> taps_200k_wfm_decim_0 = {
.low_frequency_normalized = -100000.0f / 3072000.0f,
.high_frequency_normalized = 100000.0f / 3072000.0f,
.transition_normalized = 384000.0f / 3072000.0f,
.taps = { {
48, -18, -151, -364, -557, -548, -139, 789,
2187, 3800, 5230, 6071, 6071, 5230, 3800, 2187,
789, -139, -548, -557, -364, -151, -18, 48,
} },
};
// IFIR prototype filter: fs=768000, pass=100000, stop=284000, decim=2, fout=384000
constexpr fir_taps_real<16> taps_200k_wfm_decim_1 = {
.low_frequency_normalized = -100000.0f / 768000.0f,
.high_frequency_normalized = 100000.0f / 768000.0f,
.transition_normalized = 184000.0f / 768000.0f,
.taps = { {
-67, -123, 388, 622, -1342, -2185, 4599, 14486,
14486, 4599, -2185, -1342, 622, 388, -123, -67,
} },
};
/* Wideband audio filter */
/* 96kHz int16_t input
* -> FIR filter, <15kHz (0.156fs) pass, >19kHz (0.198fs) stop
* -> 48kHz int16_t output, gain of 1.0 (I think).
* Padded to multiple of four taps for unrolled FIR code.
* sum(abs(taps)): 125270
*/
constexpr fir_taps_real<64> taps_64_lp_156_198 {
.low_frequency_normalized = -0.156f,
.high_frequency_normalized = 0.156f,
.transition_normalized = 0.04f,
.taps = { {
-27, 166, 104, -36, -174, -129, 109, 287,
148, -232, -430, -130, 427, 597, 49, -716,
-778, 137, 1131, 957, -493, -1740, -1121, 1167,
2733, 1252, -2633, -4899, -1336, 8210, 18660, 23254,
18660, 8210, -1336, -4899, -2633, 1252, 2733, 1167,
-1121, -1740, -493, 957, 1131, 137, -778, -716,
49, 597, 427, -130, -430, -232, 148, 287,
109, -129, -174, -36, 104, 166, -27, 0,
} },
};
// TPMS decimation filters ////////////////////////////////////////////////
// IFIR image-reject filter: fs=2457600, pass=100000, stop=407200, decim=4, fout=614400
static constexpr fir_taps_real<24> taps_200k_decim_0 = {
.low_frequency_normalized = -100000.0f / 2457600.0f,
.high_frequency_normalized = 100000.0f / 2457600.0f,
.transition_normalized = 307200.0f / 2457600.0f,
.taps = { {
90, 94, 4, -240, -570, -776, -563, 309,
1861, 3808, 5618, 6710, 6710, 5618, 3808, 1861,
309, -563, -776, -570, -240, 4, 94, 90,
} },
};
// IFIR prototype filter: fs=614400, pass=100000, stop=207200, decim=2, fout=307200
static constexpr fir_taps_real<16> taps_200k_decim_1 = {
.low_frequency_normalized = -100000.0f / 614400.0f,
.high_frequency_normalized = 100000.0f / 614400.0f,
.transition_normalized = 107200.0f / 614400.0f,
.taps = { {
-132, -256, 545, 834, -1507, -2401, 4666, 14583,
14583, 4666, -2401, -1507, 834, 545, -256, -132,
} },
};
#endif/*__DSP_FIR_TAPS_H__*/

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "dsp_iir.hpp"
#include <hal.h>
void IIRBiquadFilter::configure(const iir_biquad_config_t& 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;
// 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];
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];
buffer_out.p[i] = y_[2];
}
x = x_;
y = y_;
}
void IIRBiquadFilter::execute_in_place(const buffer_f32_t& 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];
}
// 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])
float IIRBiquadDF2Filter::execute(float x) {
float y;
y = b0 * x + z0;
z0 = b1 * x - a1 * y + z1;
z1 = b2 * x - a2 * y;
return y;
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_IIR_H__
#define __DSP_IIR_H__
#include <array>
#include "dsp_types.hpp"
struct iir_biquad_config_t {
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_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)
{
}
// 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 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 } };
};
class IIRBiquadDF2Filter {
public:
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;
float z0 = 0;
float z1 = 0;
};
#endif/*__DSP_IIR_H__*/

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_IIR_CONFIG_H__
#define __DSP_IIR_CONFIG_H__
#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 }
};
// 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 }
};
// 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 }
};
// 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 }
};
// 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 }
};
// 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 }
};
// 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 }
};
// 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 }
};
// 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 }
};
// 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 }
};
// 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 }
};
// 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 }
};
// 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 }
};
// 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 }
};
#endif/*__DSP_IIR_CONFIG_H__*/

View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "dsp_sos.hpp"

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_SOS_H__
#define __DSP_SOS_H__
#include "dsp_iir.hpp"
#include <cstdint>
#include <cstddef>
template <size_t N>
class SOSFilter {
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)
value = filter.execute(value);
return value;
}
private:
IIRBiquadDF2Filter filters[N];
};
#endif/*__DSP_SOS_H__*/

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2020 Belousov Oleg
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_SOS_CONFIG_H__
#define __DSP_SOS_CONFIG_H__
#include "dsp_iir.hpp"
// 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 }
};
#endif/*__DSP_SOS_CONFIG_H__*/

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __DSP_TYPES_H__
#define __DSP_TYPES_H__
#include <cstdint>
#include "complex.hpp"
#include "buffer.hpp"
using buffer_c8_t = buffer_t<complex8_t>;
using buffer_c16_t = buffer_t<complex16_t>;
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__*/

View File

@@ -0,0 +1,112 @@
/*
* Copyright (C) 2017 Jared Boone, ShareBrained Technology, Inc.
* Copyright (C) 2017 Furrtek
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __EMU_CC1101_H__
#define __EMU_CC1101_H__
#include <cstdint>
#include <array>
#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
// Preamble: 8*n bits of 10101010
// Sync word: 2 bytes (can be repeated twice)
// Length: 1 byte (address + payload)
// 2-FSK: 0=-dev, 1=+dev
// 4-FSK: 00=-1/3dev, 01=-dev, 10=1/3dev, 11=+dev (preamble and sync are in 2-FSK)
// OOK: PA on or off
// ASK: Power can be adjusted
// 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;
};
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__*/

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ert_packet.hpp"
#include "crc.hpp"
namespace ert {
size_t Packet::length() const {
return decoder_.symbols_count();
}
bool Packet::is_valid() const {
return true;
}
Timestamp Packet::received_at() const {
return packet_.timestamp();
}
Packet::Type Packet::type() const {
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::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::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::IDM ) {
return reader_.read(4 * 8 + 4, 4);
}
return invalid_commodity_type;
}
FormattedSymbols Packet::symbols_formatted() const {
return format_symbols(decoder_);
}
bool Packet::crc_ok() const {
switch(type()) {
case Type::SCM: return crc_ok_scm();
case Type::IDM: return crc_ok_idm();
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;
}
bool Packet::crc_ok_idm() 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;
}
} /* namespace ert */

View File

@@ -0,0 +1,89 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __ERT_PACKET_H__
#define __ERT_PACKET_H__
#include <cstdint>
#include <cstddef>
#include "field_reader.hpp"
#include "baseband_packet.hpp"
#include "manchester.hpp"
namespace ert {
using ID = uint32_t;
using Consumption = uint32_t;
using CommodityType = uint32_t;
constexpr ID invalid_id = 0;
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,
};
Packet(
const Type type,
const baseband::Packet& packet
) : packet_ { packet },
decoder_ { packet_ },
reader_ { decoder_ },
type_ { type }
{
}
size_t length() const;
bool is_valid() const;
Timestamp received_at() const;
Type type() const;
ID id() const;
CommodityType commodity_type() const;
Consumption consumption() const;
FormattedSymbols symbols_formatted() const;
bool crc_ok() const;
private:
using Reader = FieldReader<ManchesterDecoder, BitRemapNone>;
const baseband::Packet packet_;
const ManchesterDecoder decoder_;
const Reader reader_;
const Type type_;
bool crc_ok_idm() const;
bool crc_ok_scm() const;
};
} /* namespace ert */
#endif/*__ERT_PACKET_H__*/

View File

@@ -0,0 +1,24 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "event.hpp"
#include "ch.h"

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __EVENT_H__
#define __EVENT_H__
#include "ch.h"
#endif/*__EVENT_H__*/

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __FIELD_READER_H__
#define __FIELD_READER_H__
#include <cstdint>
#include <cstddef>
struct BitRemapNone {
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;
}
};
template<typename T, typename BitRemap>
class FieldReader {
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;
}
private:
const T& data;
const BitRemap bit_remap { };
};
#endif/*__FIELD_READER_H__*/

View File

@@ -0,0 +1,239 @@
/*
* Copyright (C) 2013 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __FIFO_H__
#define __FIFO_H__
#include <cstddef>
#include <algorithm>
#include <cstring>
#include <memory>
#include <hal.h>
/* FIFO implementation inspired by Linux kfifo. */
template<typename T>
class FIFO {
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() {
_in = _out;
}
void reset_out() {
_out = _in;
}
size_t len() const {
return _in - _out;
}
size_t unused() const {
return size() - (_in - _out);
}
bool is_empty() const {
return _in == _out;
}
bool is_full() const {
return unused() == 0;
}
bool in(const T& val) {
if( is_full() ) {
return false;
}
_data[_in & mask()] = val;
smp_wmb();
_in += 1;
return true;
}
size_t in(const T* const buf, size_t len) {
const size_t l = unused();
if( len > l ) {
len = l;
}
copy_in(buf, len, _in);
_in += len;
return len;
}
size_t in_r(const void* const buf, const size_t len) {
if( (len + recsize()) > unused() ) {
return 0;
}
poke_n(len);
copy_in((const T*)buf, len, _in + recsize());
_in += len + recsize();
return len;
}
bool out(T& val) {
if( is_empty() ) {
return false;
}
val = _data[_out & mask()]; // Crashes
smp_wmb(); // Ok
_out += 1; // Crashes
return true;
}
size_t out(T* const buf, size_t len) {
len = out_peek(buf, len);
_out += len;
return len;
}
bool skip() {
if( is_empty() ) {
return false;
}
size_t len = peek_n();
_out += len + recsize();
return true;
}
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);
return len;
}
size_t out_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;
}
private:
size_t size() const {
return _size;
}
static constexpr size_t esize() {
return sizeof(T);
}
size_t mask() const {
return size() - 1;
}
static constexpr size_t recsize() {
return 2;
}
void smp_wmb() {
__DMB();
}
size_t peek_n() {
size_t l = _data[_out & mask()];
if( recsize() > 1 ) {
l |= _data[(_out + 1) & mask()] << 8;
}
return l;
}
void poke_n(const size_t n) {
_data[_in & mask()] = n & 0xff;
if( recsize() > 1 ) {
_data[(_in + 1) & mask()] = (n >> 8) & 0xff;
}
}
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(&_data[off], &src[0], l * esize());
memcpy(&_data[0], &src[l], (len - l) * esize());
smp_wmb();
}
void copy_out(T* const dst, 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();
}
size_t out_copy_r(void *buf, size_t len, size_t* const n) {
*n = peek_n();
if( len > *n ) {
len = *n;
}
copy_out((T*)buf, len, _out + recsize());
return len;
}
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__*/

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "gcc.hpp"
#include <ch.h>
#if defined(TOOLCHAIN_GCC)
/* Note: Added to deal with static variables:
* undefined reference to `__dso_handle'.
* Comes up when using random C++ features, e.g. lambdas or std::function?
*/
void *__dso_handle;
/* prevents the exception handling name demangling code getting pulled in */
namespace __gnu_cxx {
void __verbose_terminate_handler() {
}
}
/* NOTE: Hack to address bloat when using C++ class virtual destructors.
*/
extern "C" __attribute__((weak)) void __cxa_pure_virtual(void) {
chSysHalt();
}
#endif
/* Implementing abort() eliminates requirement for _getpid(), _kill(),
* _exit().
*/
extern "C" void abort() {
/* while() loop to avoid noreturn-is-returning warning. */
while(1) { chSysHalt(); }
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GCC_H__
#define __GCC_H__
#endif/*__GCC_H__*/

View File

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "gpdma.hpp"
#include <array>
namespace lpc43xx {
namespace gpdma {
namespace {
struct ChannelHandlers {
TCHandler tc;
ErrHandler err;
constexpr ChannelHandlers(
) : tc(nullptr),
err(nullptr)
{
}
};
}
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;
}
void Channel::configure(
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;
}
} /* namespace channel */
extern "C" {
CH_IRQ_HANDLER(DMA_IRQHandler) {
CH_IRQ_PROLOGUE();
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;
/* 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();
CH_IRQ_EPILOGUE();
}
}
} /* namespace gpdma */
} /* namespace lpc43xx */

View File

@@ -0,0 +1,375 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GPDMA_H__
#define __GPDMA_H__
#include <cstdint>
#include <cstddef>
#include <array>
#include "hal.h"
#include "utility.hpp"
namespace lpc43xx {
namespace gpdma {
/* LPC43xx DMA appears to be the ARM PrimeCell(R) DMA Controller, or very
* closely related.
* More here: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0196g/Chdcdaeb.html
*/
constexpr size_t buffer_words(const size_t bytes, const size_t 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,
};
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;
}
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;
}
namespace mux {
enum class Peripheral0 {
SPIFI = 0,
SCT_CTOUT_2 = 1,
SGPIO14 = 2,
TIMER3_MATCH_1 = 3,
};
enum class Peripheral1 {
TIMER0_MATCH_0 = 0,
USART0_TX = 1,
};
enum class Peripheral2 {
TIMER0_MATCH_1 = 0,
USART0_RX = 1,
};
enum class Peripheral3 {
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,
};
enum class Peripheral5 {
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,
};
enum class Peripheral7 {
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,
};
enum class Peripheral9 {
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,
};
enum class Peripheral11 {
SSP1_RX = 0,
SGPIO14 = 1,
USART0_TX = 2,
};
enum class Peripheral12 {
SSP1_TX = 0,
SGPIO15 = 1,
USART0_RX = 2,
};
enum class Peripheral13 {
ADC0 = 0,
SSP1_RX = 2,
USART3_RX = 3,
};
enum class Peripheral14 {
ADC1 = 0,
SSP1_TX = 2,
USART3_TX = 3,
};
enum class Peripheral15 {
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;
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 */
namespace channel {
struct LLI {
uint32_t srcaddr;
uint32_t destaddr;
uint32_t lli;
uint32_t control;
};
struct LLIPointer {
uint32_t lm;
uint32_t r;
uint32_t lli;
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;
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;
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)
{
}
void enable() const {
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 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 configure(const LLI& first_lli, const uint32_t config) const;
const LLI* next_lli() const {
return reinterpret_cast<LLI*>(LPC_GPDMA->CH[number].LLI);
}
private:
const size_t number;
};
} /* namespace channel */
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 },
};
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);
}
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;
} /* namespace gpdma */
} /* namespace lpc43xx */
#endif/*__GPDMA_H__*/

View File

@@ -0,0 +1,318 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GPIO_H__
#define __GPIO_H__
#include <cstdint>
#include "ch.h"
#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;
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 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_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_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_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_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 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_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 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_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 };
}
};
struct Pin {
// Pin() = delete;
// Pin(const Pin&) = delete;
// Pin(Pin&&) = delete;
constexpr Pin(
const uint8_t port,
const uint8_t pad,
const PinConfig initial_config
) : _pin_port { port },
_pin_pad { pad },
_initial_config { initial_config }
{
}
/*
constexpr Pin(
const Pin& pin
) : _pin_port { pin._pin_port },
_pin_pad { pin._pin_pad },
_initial_config { pin._initial_config }
{
}
*/
void init() const {
LPC_SCU->SFSP[_pin_port][_pin_pad] = _initial_config;
}
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;
}
uint8_t _pin_port;
uint8_t _pin_pad;
uint16_t _initial_config;
};
struct GPIO {
// 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 ioportid_t port() const {
return _gpio_port;
}
constexpr iopadid_t pad() const {
return _gpio_pad;
}
constexpr Pin pin() const {
return _pin;
}
void configure() const {
_pin.mode(_gpio_mode);
}
uint_fast16_t mode() const {
return _gpio_mode;
}
void set() const {
palSetPad(_gpio_port, _gpio_pad);
}
void clear() const {
palClearPad(_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 input() const {
palSetPadMode(_gpio_port, _gpio_pad, PAL_MODE_INPUT);
}
void write(const bool value) const {
palWritePad(_gpio_port, _gpio_pad, value);
}
bool read() const {
return palReadPad(_gpio_port, _gpio_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;
};
#endif/*__GPIO_H__*/

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __HACKRF_CPLD_DATA_H__
#define __HACKRF_CPLD_DATA_H__
#include "cpld_xilinx.hpp"
namespace hackrf {
namespace one {
namespace cpld {
using CPLD = ::cpld::xilinx::XC2C64A;
extern const CPLD::verify_blocks_t verify_blocks;
} /* namespace hackrf */
} /* namespace one */
} /* namespace cpld */
#endif/*__HACKRF_CPLD_DATA_H__*/

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __HACKRF_GPIO_H__
#define __HACKRF_GPIO_H__
#include "pins.hpp"
#include "led.hpp"
#include <array>
using namespace lpc43xx;
namespace hackrf {
namespace one {
/* GPIO */
constexpr GPIO gpio_led_usb = gpio[GPIO2_1];
constexpr GPIO gpio_led_rx = gpio[GPIO2_2];
constexpr GPIO gpio_led_tx = gpio[GPIO2_8];
constexpr GPIO gpio_1v8_enable = gpio[GPIO3_6];
constexpr GPIO gpio_vregmode = gpio[GPIO3_7];
constexpr GPIO gpio_vaa_disable = gpio[GPIO2_9];
constexpr GPIO gpio_rx_mix_bp = gpio[GPIO2_12];
constexpr GPIO gpio_tx_mix_bp = gpio[GPIO2_11];
constexpr GPIO gpio_mix_bypass = gpio[GPIO5_16];
constexpr GPIO gpio_not_mix_bypass = gpio[GPIO1_0];
constexpr GPIO gpio_rx = gpio[GPIO5_5];
constexpr GPIO gpio_tx = gpio[GPIO5_15];
constexpr GPIO gpio_lp = gpio[GPIO2_10];
constexpr GPIO gpio_hp = gpio[GPIO2_0];
constexpr GPIO gpio_rx_amp = gpio[GPIO1_11];
constexpr GPIO gpio_tx_amp = gpio[GPIO2_15];
constexpr GPIO gpio_amp_bypass = gpio[GPIO0_14];
constexpr GPIO gpio_not_rx_amp_pwr = gpio[GPIO1_12];
constexpr GPIO gpio_not_tx_amp_pwr = gpio[GPIO3_5];
constexpr GPIO gpio_rffc5072_resetx = gpio[GPIO2_14];
constexpr GPIO gpio_rffc5072_select = gpio[GPIO2_13];
constexpr GPIO gpio_rffc5072_clock = gpio[GPIO5_6];
constexpr GPIO gpio_rffc5072_data = gpio[GPIO3_3];
constexpr GPIO gpio_max2837_select = gpio[GPIO0_15];
constexpr GPIO gpio_max2837_enable = gpio[GPIO2_6];
constexpr GPIO gpio_max2837_rxenable = gpio[GPIO2_5];
constexpr GPIO gpio_max2837_txenable = gpio[GPIO2_4];
constexpr GPIO gpio_max5864_select = gpio[GPIO2_7];
constexpr GPIO gpio_baseband_invert = gpio[GPIO0_13];
constexpr GPIO gpio_cpld_tdo = gpio[GPIO5_18];
constexpr GPIO gpio_cpld_tck = gpio[GPIO3_0];
constexpr GPIO gpio_cpld_tms = gpio[GPIO3_4];
constexpr GPIO gpio_cpld_tdi = gpio[GPIO3_1];
/* LEDs */
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__*/

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "hackrf_hal.hpp"
#include "lpc43xx_cpp.hpp"
using namespace lpc43xx;
namespace hackrf {
namespace one {
} /* namespace one */
} /* namespace hackrf */

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __HACKRF_HAL_H__
#define __HACKRF_HAL_H__
#include <cstdint>
#include "adc.hpp"
using namespace lpc43xx;
namespace hackrf {
namespace one {
/* Clocks */
using ClockFrequency = uint32_t;
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 max5864_spi_f = 20000000U;
constexpr ClockFrequency max2837_spi_f = 20000000U;
constexpr ClockFrequency rffc5072_reference_f = 40000000U;
constexpr ClockFrequency max2837_reference_f = 40000000U;
constexpr ClockFrequency mcu_clkin_f = 40000000U;
constexpr uint8_t si5351_i2c_address = 0x60;
/* Clock Generator */
constexpr size_t clock_generator_output_codec = 0;
constexpr size_t clock_generator_output_cpld = 1;
constexpr size_t clock_generator_output_sgpio = 2;
constexpr size_t clock_generator_output_clkout = 3;
constexpr size_t clock_generator_output_first_if = 4;
constexpr size_t clock_generator_output_second_if = 5;
constexpr size_t clock_generator_output_mcu_clkin = 7;
/* ADC0 */
using adc0 = adc::ADC<LPC_ADC0_BASE>;
/* ADC1 */
using adc1 = adc::ADC<LPC_ADC1_BASE>;
} /* namespace one */
} /* namespace hackrf */
#endif/*__HACKRF_HAL_H__*/

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "i2c_pp.hpp"
void I2C::start(const I2CConfig& config) {
i2cStart(_driver, &config);
}
void I2C::stop() {
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);
}
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);
}
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);
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __I2C_PP_H__
#define __I2C_PP_H__
#include <cstdint>
#include "ch.h"
#include "hal.h"
struct I2CClockConfig {
float clock_source_f;
float bus_f;
float high_period_ns;
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_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();
}
};
class I2C {
public:
using address_t = uint8_t;
constexpr I2C(I2CDriver* const driver) :
_driver(driver) {
}
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 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;
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__*/

View File

@@ -0,0 +1,277 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __I2S_H__
#define __I2S_H__
#include "hal.h"
#include "utility.hpp"
namespace lpc43xx {
namespace i2s {
enum class WordWidth {
Bits8 = 0x0,
Bits16 = 0x1,
Bits32 = 0x3,
};
enum class ClockSelect {
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;
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;
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;
constexpr operator uint32_t() const {
return
((y_divider & 0xff) << 0)
| ((x_divider & 0xff) << 8)
;
}
};
struct BitRate {
uint32_t bitrate;
constexpr operator uint32_t() const {
return ((bitrate & 0x3f) << 0);
}
};
struct Mode {
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)
;
}
};
struct DMA {
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)
;
}
};
struct ConfigTX {
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;
};
struct ConfigDMA {
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 },
};
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 } },
};
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);
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]);
}
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;
}
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;
}
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;
}
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(&i2s_resources.branch);
base_clock_disable(&i2s_resources.base);
}
static void rx_start() {
p().DAI &= ~(1U << 3);
}
static void rx_stop() {
p().DAI |= (1U << 3);
}
static void tx_start() {
p().DAO &= ~(1U << 3);
}
static void tx_stop() {
p().DAO |= (1U << 3);
}
static void tx_mute() {
p().DAO |= (1U << 15);
}
static void tx_unmute() {
p().DAO &= ~(1U << 15);
}
private:
static void reset() {
p().DAO |= (1U << 4);
p().DAI |= (1U << 4);
}
static LPC_I2S_Type& p() {
return *reinterpret_cast<LPC_I2S_Type*>(BaseAddress);
}
};
using i2s0 = I2S<LPC_I2S0_BASE>;
using i2s1 = I2S<LPC_I2S1_BASE>;
} /* namespace i2s */
} /* namespace lpc43xx */
#endif/*__I2S_H__*/

View File

@@ -0,0 +1,34 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "jammer.hpp"
#include "baseband_api.hpp"
#include "portapack.hpp"
using namespace portapack;
#include "string_format.hpp"
#include "utility.hpp"
namespace jammer {
} /* namespace jammer */

View File

@@ -0,0 +1,45 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#define JAMMER_CH_WIDTH 1000000
#define JAMMER_MAX_CH 24
#ifndef __JAMMER_H__
#define __JAMMER_H__
namespace jammer {
typedef struct jammer_range {
bool enabled;
int64_t min;
int64_t max;
} jammer_range_t;
enum JammerType : uint32_t {
TYPE_FSK = 0,
TYPE_TONE = 1,
TYPE_SWEEP = 2
};
} /* namespace jammer */
#endif/*__JAMMER_H__*/

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "jtag.hpp"
#include <cstdint>
#include <cstddef>
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;
}
} /* namespace jtag */

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __JTAG_H__
#define __JTAG_H__
#include "jtag_target.hpp"
#include <cstdint>
#include <cstddef>
#include <bitset>
namespace jtag {
class JTAG {
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 run_test_idle() {
/* Test-Logic-Reset -> Run-Test/Idle */
target.clock(0, 0);
}
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);
const auto result = shift(count, value);
/* Exit1 -> Update */
target.clock(1, 0);
/* Update -> Run-Test/Idle */
target.clock(0, 0);
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);
const auto result = shift(count, value);
/* Exit1 -> Update */
target.clock(1, 0);
/* Update -> Run-Test/Idle */
target.clock(0, 0);
return result;
}
private:
Target& target;
uint32_t shift(const size_t count, uint32_t value);
};
} /* namespace jtag */
#endif/*__JTAG_H__*/

View File

@@ -0,0 +1,266 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "jtag_tap.hpp"
#include "utility.hpp"
#include <string>
namespace jtag {
namespace tap {
size_t bits_t::length() const {
return count;
}
bits_t::operator bool() const {
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;
}
}
size_t bits_t::bytes() const {
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;
}
}
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;
}
#endif
namespace {
using route_t = uint16_t;
struct entry_t {
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 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 entry_t& entry(const state_t state) {
return table[toUType(state)];
}
} /* namespace */
const char* c_str(const state_t state) {
return state_name[toUType(state)];
}
/* TAPState **************************************************************/
state_t TAPState::state() const {
return _state;
}
void TAPState::advance(const bool tms) {
_state = entry(_state).tms[tms];
}
bool TAPState::advance_toward(const state_t desired_state) const {
return (entry(_state).route >> toUType(desired_state)) & 1;
}
/* TAPMachine ************************************************************/
void TAPMachine::set_run_test(const uint32_t value) {
_run_test = value;
}
void TAPMachine::set_repeat(const uint8_t value) {
_repeat = value;
}
void TAPMachine::set_end_ir(const state_t state) {
_end_ir = state;
}
void TAPMachine::set_end_dr(const state_t 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);
}
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);
}
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);
}
}
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);
}
bool TAPMachine::clock(const bool tms, const bool 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);
}
}
void TAPMachine::delay_us(const uint32_t microseconds) {
target.delay(microseconds);
}
void TAPMachine::shift_start(const state_t 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;
}
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;
}
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);
}
}
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;
}
} /* namespace tap */
} /* namespace jtag */

View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __JTAG_TAP_H__
#define __JTAG_TAP_H__
#include "jtag_target.hpp"
#include <cstdint>
#include <cstddef>
namespace jtag {
namespace tap {
class bits_t {
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 uint8_t* const p,
const size_t count
) : p { p },
count { count }
{
}
size_t length() const;
explicit operator bool() const;
bool operator[](const size_t index) const;
private:
const uint8_t* p { nullptr };
size_t count { 0 };
bool default_value { false };
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,
};
class TAPState {
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;
private:
state_t _state;
};
class TAPMachine {
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);
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_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 = {});
void state(const state_t state);
void wait(const state_t wait_state, const state_t end_state, const uint32_t wait_time);
private:
jtag::Target& target;
TAPState tap { };
uint32_t _run_test { 0 };
uint8_t _repeat { 0 };
state_t _end_ir { };
state_t _end_dr { };
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__*/

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __JTAG_TARGET_H__
#define __JTAG_TARGET_H__
#include <cstdint>
#include <cstddef>
namespace jtag {
class Target {
public:
using bit_t = uint_fast8_t;
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;
};
} /* namespace jtag */
#endif/*__JTAG_TARGET_H__*/

View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __JTAG_TARGET_GPIO_H__
#define __JTAG_TARGET_GPIO_H__
#include "jtag_target.hpp"
#include <ch.h>
#include <cstddef>
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();
gpio_tms.write(1);
gpio_tms.output();
gpio_tms.configure();
gpio_tck.write(0);
gpio_tck.output();
gpio_tck.configure();
gpio_tdo.input();
gpio_tdo.configure();
}
~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.
*/
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;
}
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;
void tck(const Target::bit_t value) {
gpio_tck.write(value);
}
void tdi(const Target::bit_t value) {
gpio_tdi.write(value);
}
void tms(const bit_t value) {
gpio_tms.write(value);
}
Target::bit_t tdo() {
return gpio_tdo.read();
}
};
} /* namespace jtag */
#endif/*__JTAG_TARGET_GPIO_H__*/

View File

@@ -0,0 +1,660 @@
/*
* Copyright (C) 2014 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "lcd_ili9341.hpp"
#include "bmp.hpp"
#include "portapack_io.hpp"
using namespace portapack;
#include "utility.hpp"
#include "ch.h"
#include "file.hpp"
#include <complex>
#include <cstring>
#include <string>
namespace lcd {
namespace {
void lcd_reset() {
io.lcd_reset_state(false);
chThdSleepMilliseconds(1);
io.lcd_reset_state(true);
chThdSleepMilliseconds(10);
io.lcd_reset_state(false);
chThdSleepMilliseconds(120);
}
void lcd_sleep_in() {
io.lcd_data_write_command_and_data(0x10, {});
// "It will be necessary to wait 5msec before sending next command,
// this is to allow time for the supply voltages and clock circuits
// to stabilize."
chThdSleepMilliseconds(5);
}
void lcd_sleep_out() {
io.lcd_data_write_command_and_data(0x11, {});
// "It will be necessary to wait 120msec after sending Sleep Out
// command (when in Sleep In Mode) before Sleep In command can be
// sent."
chThdSleepMilliseconds(120);
}
void lcd_display_on() {
io.lcd_data_write_command_and_data(0x29, {});
}
void lcd_display_off() {
io.lcd_data_write_command_and_data(0x28, {});
}
void lcd_sleep() {
lcd_display_off();
lcd_sleep_in();
}
void lcd_wake() {
lcd_sleep_out();
lcd_display_on();
}
void lcd_init() {
// LCDs are configured for IM[2:0] = 001
// 8080-I system, 16-bit parallel bus
//
// 0x3a: DBI[2:0] = 101
// MDT[1:0] = XX (if not in 18-bit mode, right?)
// Power control B
// 0
// PCEQ=1, DRV_ena=0, Power control=3
io.lcd_data_write_command_and_data(0xCF, { 0x00, 0xD9, 0x30 });
// Power on sequence control
io.lcd_data_write_command_and_data(0xED, { 0x64, 0x03, 0x12, 0x81 });
// Driver timing control A
io.lcd_data_write_command_and_data(0xE8, { 0x85, 0x10, 0x78 });
// Power control A
io.lcd_data_write_command_and_data(0xCB, { 0x39, 0x2C, 0x00, 0x34, 0x02 });
// Pump ratio control
io.lcd_data_write_command_and_data(0xF7, { 0x20 });
// Driver timing control B
io.lcd_data_write_command_and_data(0xEA, { 0x00, 0x00 });
io.lcd_data_write_command_and_data(0xB1, { 0x00, 0x1B });
// Blanking Porch Control
// VFP = 0b0000010 = 2 (number of HSYNC of vertical front porch)
// VBP = 0b0000010 = 2 (number of HSYNC of vertical back porch)
// HFP = 0b0001010 = 10 (number of DOTCLOCK of horizontal front porch)
// HBP = 0b0010100 = 20 (number of DOTCLOCK of horizontal back porch)
io.lcd_data_write_command_and_data(0xB5, { 0x02, 0x02, 0x0a, 0x14 });
// Display Function Control
// PT[1:0] = 0b10
// PTG[1:0] = 0b10
// ISC[3:0] = 0b0010 (scan cycle interval of gate driver: 5 frames)
// SM = 0 (gate driver pin arrangement in combination with GS)
// SS = 1 (source output scan direction S720 -> S1)
// GS = 0 (gate output scan direction G1 -> G320)
// REV = 1 (normally white)
// NL = 0b100111 (default)
// PCDIV = 0b000000 (default?)
io.lcd_data_write_command_and_data(0xB6, { 0x0A, 0xA2, 0x27, 0x00 });
// Power Control 1
//VRH[5:0]
io.lcd_data_write_command_and_data(0xC0, { 0x1B });
// Power Control 2
//SAP[2:0];BT[3:0]
io.lcd_data_write_command_and_data(0xC1, { 0x12 });
// VCOM Control 1
io.lcd_data_write_command_and_data(0xC5, { 0x32, 0x3C });
// VCOM Control 2
io.lcd_data_write_command_and_data(0xC7, { 0x9B });
// Memory Access Control
// Invert X and Y memory access order, so upper-left of
// screen is (0,0) when writing to display.
io.lcd_data_write_command_and_data(0x36, {
(1 << 7) | // MY=1
(1 << 6) | // MX=1
(0 << 5) | // MV=0
(1 << 4) | // ML=1: reverse vertical refresh to simplify scrolling logic
(1 << 3) // BGR=1: For Kingtech LCD, BGR filter.
});
// COLMOD: Pixel Format Set
// DPI=101 (16 bits/pixel), DBI=101 (16 bits/pixel)
io.lcd_data_write_command_and_data(0x3A, { 0x55 });
//io.lcd_data_write_command_and_data(0xF6, { 0x01, 0x30 });
// WEMODE=1 (reset column and page number on overflow)
// MDT[1:0]
// EPF[1:0]=00 (use channel MSB for LSB)
// RIM=0 (If COLMOD[6:4]=101 (65k color), 16-bit RGB interface (1 transfer/pixel))
// RM=0 (system interface/VSYNC interface)
// DM[1:0]=00 (internal clock operation)
// ENDIAN=0 (doesn't matter with 16-bit interface)
io.lcd_data_write_command_and_data(0xF6, { 0x01, 0x30, 0x00 });
// 3Gamma Function Disable
io.lcd_data_write_command_and_data(0xF2, { 0x00 });
// Gamma curve selected
io.lcd_data_write_command_and_data(0x26, { 0x01 });
// Set Gamma
io.lcd_data_write_command_and_data(0xE0, {
0x0F, 0x1D, 0x19, 0x0E, 0x10, 0x07, 0x4C, 0x63,
0x3F, 0x03, 0x0D, 0x00, 0x26, 0x24, 0x04
});
// Set Gamma
io.lcd_data_write_command_and_data(0xE1, {
0x00, 0x1C, 0x1F, 0x02, 0x0F, 0x03, 0x35, 0x25,
0x47, 0x04, 0x0C, 0x0B, 0x29, 0x2F, 0x05
});
lcd_wake();
// Turn on Tearing Effect Line (TE) output signal.
io.lcd_data_write_command_and_data(0x35, { 0b00000000 });
}
void lcd_set(const uint_fast8_t command, const uint_fast16_t start, const uint_fast16_t end) {
io.lcd_data_write_command_and_data(command, {
static_cast<uint8_t>(start >> 8), static_cast<uint8_t>(start & 0xff),
static_cast<uint8_t>(end >> 8), static_cast<uint8_t>(end & 0xff)
});
}
void lcd_ramwr_start() {
io.lcd_data_write_command_and_data(0x2c, {});
}
void lcd_ramrd_start() {
io.lcd_data_write_command_and_data(0x2e, {});
io.lcd_read_word();
}
void lcd_caset(const uint_fast16_t start_column, uint_fast16_t end_column) {
lcd_set(0x2a, start_column, end_column);
}
void lcd_paset(const uint_fast16_t start_page, const uint_fast16_t end_page) {
lcd_set(0x2b, start_page, end_page);
}
void lcd_start_ram_write(
const ui::Point p,
const ui::Size s
) {
lcd_caset(p.x(), p.x() + s.width() - 1);
lcd_paset(p.y(), p.y() + s.height() - 1);
lcd_ramwr_start();
}
void lcd_start_ram_read(
const ui::Point p,
const ui::Size s
) {
lcd_caset(p.x(), p.x() + s.width() - 1);
lcd_paset(p.y(), p.y() + s.height() - 1);
lcd_ramrd_start();
}
void lcd_start_ram_write(
const ui::Rect& r
) {
lcd_start_ram_write(r.location(), r.size());
}
void lcd_start_ram_read(
const ui::Rect& r
) {
lcd_start_ram_read(r.location(), r.size());
}
void lcd_vertical_scrolling_definition(
const uint_fast16_t top_fixed_area,
const uint_fast16_t vertical_scrolling_area,
const uint_fast16_t bottom_fixed_area
) {
io.lcd_data_write_command_and_data(0x33, {
static_cast<uint8_t>(top_fixed_area >> 8),
static_cast<uint8_t>(top_fixed_area & 0xff),
static_cast<uint8_t>(vertical_scrolling_area >> 8),
static_cast<uint8_t>(vertical_scrolling_area & 0xff),
static_cast<uint8_t>(bottom_fixed_area >> 8),
static_cast<uint8_t>(bottom_fixed_area & 0xff)
});
}
void lcd_vertical_scrolling_start_address(
const uint_fast16_t vertical_scrolling_pointer
) {
io.lcd_data_write_command_and_data(0x37, {
static_cast<uint8_t>(vertical_scrolling_pointer >> 8),
static_cast<uint8_t>(vertical_scrolling_pointer & 0xff)
});
}
}
void ILI9341::init() {
lcd_reset();
lcd_init();
}
void ILI9341::shutdown() {
lcd_reset();
}
void ILI9341::sleep() {
lcd_sleep();
}
void ILI9341::wake() {
lcd_wake();
}
void ILI9341::fill_rectangle(ui::Rect r, const ui::Color c) {
const auto r_clipped = r.intersect(screen_rect());
if( !r_clipped.is_empty() ) {
lcd_start_ram_write(r_clipped);
size_t count = r_clipped.width() * r_clipped.height();
io.lcd_write_pixels(c, count);
}
}
void ILI9341::fill_rectangle_unrolled8(ui::Rect r, const ui::Color c) {
const auto r_clipped = r.intersect(screen_rect());
if( !r_clipped.is_empty() ) {
lcd_start_ram_write(r_clipped);
size_t count = r_clipped.width() * r_clipped.height();
io.lcd_write_pixels_unrolled8(c, count);
}
}
void ILI9341::render_line(const ui::Point p, const uint8_t count, const ui::Color* line_buffer) {
lcd_start_ram_write(p, { count, 1 });
io.lcd_write_pixels(line_buffer, count);
}
void ILI9341::render_box(const ui::Point p, const ui::Size s, const ui::Color* line_buffer) {
lcd_start_ram_write(p, s);
io.lcd_write_pixels(line_buffer, s.width() * s.height());
}
// RLE_4 BMP loader (delta not implemented)
void ILI9341::drawBMP(const ui::Point p, const uint8_t * bitmap, const bool transparency) {
const bmp_header_t * bmp_header = (const bmp_header_t *)bitmap;
uint32_t data_idx;
uint8_t by, c, count, transp_idx = 0;
ui::Color line_buffer[240];
uint16_t px = 0, py;
ui::Color palette[16];
// Abort if bad depth or no RLE
if ((bmp_header->bpp != 4) ||
(bmp_header->compression != 2)) return;
data_idx = bmp_header->image_data;
const bmp_palette_t * bmp_palette = (const bmp_palette_t *)&bitmap[bmp_header->BIH_size + 14];
// Convert palette and find pure magenta index (alpha color key)
for (c = 0; c < 16; c++) {
palette[c] = ui::Color(bmp_palette->color[c].R, bmp_palette->color[c].G, bmp_palette->color[c].B);
if ((bmp_palette->color[c].R == 0xFF) &&
(bmp_palette->color[c].G == 0x00) &&
(bmp_palette->color[c].B == 0xFF)) transp_idx = c;
}
if (!transparency) {
py = bmp_header->height + 16;
do {
by = bitmap[data_idx++];
if (by) {
count = by >> 1;
by = bitmap[data_idx++];
for (c = 0; c < count; c++) {
line_buffer[px++] = palette[by >> 4];
if (px < bmp_header->width) line_buffer[px++] = palette[by & 15];
}
if (data_idx & 1) data_idx++;
} else {
by = bitmap[data_idx++];
if (by == 0) {
render_line({p.x(), p.y() + py}, bmp_header->width, line_buffer);
py--;
px = 0;
} else if (by == 1) {
break;
} else if (by == 2) {
// Delta
} else {
count = by >> 1;
for (c = 0; c < count; c++) {
by = bitmap[data_idx++];
line_buffer[px++] = palette[by >> 4];
if (px < bmp_header->width) line_buffer[px++] = palette[by & 15];
}
if (data_idx & 1) data_idx++;
}
}
} while (1);
} else {
py = bmp_header->height;
do {
by = bitmap[data_idx++];
if (by) {
count = by >> 1;
by = bitmap[data_idx++];
for (c = 0; c < count; c++) {
if ((by >> 4) != transp_idx) draw_pixel({static_cast<ui::Coord>(p.x() + px), static_cast<ui::Coord>(p.y() + py)}, palette[by >> 4]);
px++;
if (px < bmp_header->width) {
if ((by & 15) != transp_idx) draw_pixel({static_cast<ui::Coord>(p.x() + px), static_cast<ui::Coord>(p.y() + py)}, palette[by & 15]);
}
px++;
}
if (data_idx & 1) data_idx++;
} else {
by = bitmap[data_idx++];
if (by == 0) {
py--;
px = 0;
} else if (by == 1) {
break;
} else if (by == 2) {
// Delta
} else {
count = by >> 1;
for (c = 0; c < count; c++) {
by = bitmap[data_idx++];
if ((by >> 4) != transp_idx) draw_pixel({static_cast<ui::Coord>(p.x() + px), static_cast<ui::Coord>(p.y() + py)}, palette[by >> 4]);
px++;
if (px < bmp_header->width) {
if ((by & 15) != transp_idx) draw_pixel({static_cast<ui::Coord>(p.x() + px), static_cast<ui::Coord>(p.y() + py)}, palette[by & 15]);
}
px++;
}
if (data_idx & 1) data_idx++;
}
}
} while (1);
}
}
/*
Draw BMP from SD card.
Currently supported formats:
16bpp ARGB, RGB565
24bpp RGB
32bpp ARGB
*/
bool ILI9341::drawBMP2(const ui::Point p, const std::string file) {
File bmpimage;
size_t file_pos = 0;
uint16_t pointer = 0;
int16_t px = 0, py, width, height;
bmp_header_t bmp_header;
uint8_t type = 0;
char buffer[257];
ui::Color line_buffer[240];
auto result = bmpimage.open(file);
if(result.is_valid())
return false;
bmpimage.seek(file_pos);
auto read_size = bmpimage.read(&bmp_header, sizeof(bmp_header));
if (!((bmp_header.signature == 0x4D42) && // "BM" Signature
(bmp_header.planes == 1) && // Seems always to be 1
(bmp_header.compression == 0 || bmp_header.compression == 3 ))) { // No compression
return false;
}
switch(bmp_header.bpp) {
case 16:
file_pos = 0x36;
memset(buffer, 0, 16);
bmpimage.read(buffer, 16);
if(buffer[1] == 0x7C)
type = 3; // A1R5G5B5
else
type = 0; // R5G6B5
break;
case 24:
type = 1;
break;
case 32:
default:
type = 2;
break;
}
width = bmp_header.width;
height = bmp_header.height;
file_pos = bmp_header.image_data;
py = height + 16;
while(1) {
while(px < width) {
bmpimage.seek(file_pos);
memset(buffer, 0, 257);
read_size = bmpimage.read(buffer, 256);
if (read_size.is_error())
return false; // Read error
pointer = 0;
while(pointer < 256) {
if(pointer + 4 > 256)
break;
switch(type) {
case 0:
case 3:
if(!type)
line_buffer[px] = ui::Color((uint16_t)buffer[pointer] | ((uint16_t)buffer[pointer + 1] << 8));
else
line_buffer[px] = ui::Color(((uint16_t)buffer[pointer] & 0x1F) | ((uint16_t)buffer[pointer] & 0xE0) << 1 | ((uint16_t)buffer[pointer + 1] & 0x7F) << 9);
pointer += 2;
file_pos += 2;
break;
case 1:
default:
line_buffer[px] = ui::Color(buffer[pointer + 2], buffer[pointer + 1], buffer[pointer]);
pointer += 3;
file_pos += 3;
break;
case 2:
line_buffer[px] = ui::Color(buffer[pointer + 2], buffer[pointer + 1], buffer[pointer]);
pointer += 4;
file_pos += 4;
break;
}
px++;
if(px >= width) {
break;
}
}
if(read_size.value() != 256)
break;
}
render_line({ p.x(), p.y() + py }, px, line_buffer);
px = 0;
py--;
if(read_size.value() < 256 || py < 0)
break;
}
return true;
}
void ILI9341::draw_line(const ui::Point start, const ui::Point end, const ui::Color color) {
int x0 = start.x();
int y0 = start.y();
int x1 = end.x();
int y1 = end.y();
int dx = std::abs(x1-x0), sx = x0<x1 ? 1 : -1;
int dy = std::abs(y1-y0), sy = y0<y1 ? 1 : -1;
int err = (dx>dy ? dx : -dy)/2, e2;
for(;;){
draw_pixel({static_cast<ui::Coord>(x0), static_cast<ui::Coord>(y0)}, color);
if (x0==x1 && y0==y1) break;
e2 = err;
if (e2 >-dx) { err -= dy; x0 += sx; }
if (e2 < dy) { err += dx; y0 += sy; }
}
}
void ILI9341::fill_circle(
const ui::Point center,
const ui::Dim radius,
const ui::Color foreground,
const ui::Color background
) {
const uint32_t radius2 = radius * radius;
for(int32_t y=-radius; y<radius; y++) {
const int32_t y2 = y * y;
for(int32_t x=-radius; x<radius; x++) {
const int32_t x2 = x * x;
const uint32_t d2 = x2 + y2;
const bool inside = d2 < radius2;
const auto color = inside ? foreground : background;
draw_pixel({ x + center.x(), y + center.y() }, color);
}
}
}
void ILI9341::draw_pixel(
const ui::Point p,
const ui::Color color
) {
if( screen_rect().contains(p) ) {
lcd_start_ram_write(p, { 1, 1 });
io.lcd_write_pixel(color);
}
}
void ILI9341::draw_pixels(
const ui::Rect r,
const ui::Color* const colors,
const size_t count
) {
/* TODO: Assert that rectangle width x height < count */
lcd_start_ram_write(r);
io.lcd_write_pixels(colors, count);
}
void ILI9341::read_pixels(
const ui::Rect r,
ui::ColorRGB888* const colors,
const size_t count
) {
/* TODO: Assert that rectangle width x height < count */
lcd_start_ram_read(r);
io.lcd_read_bytes(
reinterpret_cast<uint8_t*>(colors),
count * sizeof(ui::ColorRGB888)
);
}
void ILI9341::draw_bitmap(
const ui::Point p,
const ui::Size size,
const uint8_t* const pixels,
const ui::Color foreground,
const ui::Color background
) {
lcd_start_ram_write(p, size);
const size_t count = size.width() * size.height();
for(size_t i=0; i<count; i++) {
const auto pixel = pixels[i >> 3] & (1U << (i & 0x7));
io.lcd_write_pixel(pixel ? foreground : background);
}
}
void ILI9341::draw_glyph(
const ui::Point p,
const ui::Glyph& glyph,
const ui::Color foreground,
const ui::Color background
) {
draw_bitmap(p, glyph.size(), glyph.pixels(), foreground, background);
}
void ILI9341::scroll_set_area(
const ui::Coord top_y,
const ui::Coord bottom_y
) {
scroll_state.top_area = top_y;
scroll_state.bottom_area = height() - bottom_y;
scroll_state.height = bottom_y - top_y;
lcd_vertical_scrolling_definition(scroll_state.top_area, scroll_state.height, scroll_state.bottom_area);
}
ui::Coord ILI9341::scroll_set_position(
const ui::Coord position
) {
scroll_state.current_position = position % scroll_state.height;
const uint_fast16_t address = scroll_state.top_area + scroll_state.current_position;
lcd_vertical_scrolling_start_address(address);
return address;
}
ui::Coord ILI9341::scroll(const int32_t delta) {
return scroll_set_position(scroll_state.current_position + scroll_state.height - delta);
}
ui::Coord ILI9341::scroll_area_y(const ui::Coord y) const {
const auto wrapped_y = (scroll_state.current_position + y) % scroll_state.height;
return wrapped_y + scroll_state.top_area;
}
void ILI9341::scroll_disable() {
lcd_vertical_scrolling_definition(0, height(), 0);
lcd_vertical_scrolling_start_address(0);
}
} /* namespace lcd */

View File

@@ -0,0 +1,124 @@
/*
* Copyright (C) 2014 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __LCD_ILI9341_H__
#define __LCD_ILI9341_H__
#include "ui.hpp"
#include "ui_text.hpp"
#include <cstdint>
#include <array>
namespace lcd {
class ILI9341 {
public:
constexpr ILI9341(
) : scroll_state { 0, 0, height(), 0 }
{
}
ILI9341(const ILI9341&) = delete;
ILI9341(ILI9341&&) = delete;
void operator=(const ILI9341&) = delete;
void init();
void shutdown();
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 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());
}
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_bitmap(
const ui::Point p,
const ui::Size size,
const uint8_t* const data,
const ui::Color foreground,
const ui::Color background
);
void draw_glyph(
const ui::Point p,
const ui::Glyph& glyph,
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();
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() }; }
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__*/

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __LED_H__
#define __LED_H__
#include "gpio.hpp"
struct LED {
constexpr LED(const GPIO gpio) :
_gpio { gpio } {
}
void setup() const {
_gpio.clear();
_gpio.output();
_gpio.configure();
}
void on() const {
_gpio.set();
}
void off() const {
_gpio.clear();
}
void toggle() const {
_gpio.toggle();
}
void write(const bool value) const {
_gpio.write(value);
}
private:
const GPIO _gpio;
};
#endif/*__LED_H__*/

View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#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
};
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;
}
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--;
}
}
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;
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __LFSR_RANDOM_HPP__
#define __LFSR_RANDOM_HPP__
#include <cstdint>
#include <cstddef>
using lfsr_word_t = uint32_t;
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__*/

View File

@@ -0,0 +1,566 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __LPC43XX_CPP_H__
#define __LPC43XX_CPP_H__
#include <cstdint>
#include <hal.h>
#include "utility.hpp"
namespace lpc43xx {
#if defined(LPC43XX_M4)
namespace m4 {
static inline bool flag_saturation() {
return __get_APSR() & (1U << 27);
}
static inline void clear_flag_saturation() {
uint32_t flags = 1;
__asm volatile ("MSR APSR_nzcvqg, %0" : : "r" (flags));
}
} /* namespace m4 */
#endif
namespace creg {
static_assert(offsetof(LPC_CREG_Type, CREG0) == 0x004, "CREG0 offset wrong");
static_assert(offsetof(LPC_CREG_Type, M4MEMMAP) == 0x100, "M4MEMMAP offset wrong");
static_assert(offsetof(LPC_CREG_Type, CREG5) == 0x118, "CREG5 offset wrong");
static_assert(offsetof(LPC_CREG_Type, CHIPID) == 0x200, "CHIPID offset wrong");
static_assert(offsetof(LPC_CREG_Type, M0SUBMEMMAP) == 0x308, "M0SUBMEMMAP offset wrong");
static_assert(offsetof(LPC_CREG_Type, M0APPTXEVENT) == 0x400, "M0APPTXEVENT offset wrong");
static_assert(offsetof(LPC_CREG_Type, USB0FLADJ) == 0x500, "USB0FLADJ offset wrong");
static_assert(offsetof(LPC_CREG_Type, USB1FLADJ) == 0x600, "USB1FLADJ offset wrong");
namespace m4txevent {
#if defined(LPC43XX_M0)
inline void enable() {
nvicEnableVector(M4CORE_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_M4TXEVENT_IRQ_PRIORITY));
}
inline void disable() {
nvicDisableVector(M4CORE_IRQn);
}
#endif
#if defined(LPC43XX_M4)
inline void assert_event() {
__SEV();
}
#endif
inline void clear() {
LPC_CREG->M4TXEVENT = 0;
}
} /* namespace m4txevent */
namespace m0apptxevent {
#if defined(LPC43XX_M4)
inline void enable() {
nvicEnableVector(M0CORE_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_M0APPTXEVENT_IRQ_PRIORITY));
}
inline void disable() {
nvicDisableVector(M0CORE_IRQn);
}
#endif
#if defined(LPC43XX_M0)
inline void assert_event() {
__SEV();
}
#endif
inline void clear() {
LPC_CREG->M0APPTXEVENT = 0;
}
} /* namespace */
} /* 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,
};
struct IDIV_CTRL {
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)
;
}
};
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;
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;
constexpr operator uint32_t() const {
return ((mdec & 0x1ffff) << 0);
}
};
struct NP_DIV {
uint32_t pdec;
uint32_t ndec;
constexpr operator uint32_t() const {
return
((pdec & 0x7f) << 0)
| ((ndec & 0x3ff) << 12)
;
}
};
struct FRAC {
uint32_t pllfract_ctrl;
constexpr operator uint32_t() const {
return ((pllfract_ctrl & 0x3fffff) << 0);
}
};
inline void ctrl(const CTRL& value) {
LPC_CGU->PLL0AUDIO_CTRL = value;
}
inline void mdiv(const MDIV& value) {
LPC_CGU->PLL0AUDIO_MDIV = value;
}
inline void np_div(const NP_DIV& value) {
LPC_CGU->PLL0AUDIO_NP_DIV = value;
}
inline void frac(const FRAC& value) {
LPC_CGU->PLL0AUDIO_FRAC = value;
}
inline void power_up() {
LPC_CGU->PLL0AUDIO_CTRL &= ~(1U << 0);
}
inline void power_down() {
LPC_CGU->PLL0AUDIO_CTRL |= (1U << 0);
}
inline bool is_locked() {
return LPC_CGU->PLL0AUDIO_STAT & (1U << 0);
}
inline void clock_enable() {
LPC_CGU->PLL0AUDIO_CTRL |= (1U << 4);
}
inline void clock_disable() {
LPC_CGU->PLL0AUDIO_CTRL &= ~(1U << 4);
}
} /* namespace pll0audio */
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;
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;
}
inline void enable() {
LPC_CGU->PLL1_CTRL &= ~(1U << 0);
}
inline void disable() {
LPC_CGU->PLL1_CTRL |= (1U << 0);
}
inline void direct() {
LPC_CGU->PLL1_CTRL |= (1U << 7);
}
inline bool is_locked() {
return LPC_CGU->PLL1_STAT & (1U << 0);
}
} /* namespace pll1 */
} /* namespace cgu */
namespace ccu1 {
static_assert(offsetof(LPC_CCU1_Type, CLK_ADCHS_STAT) == 0xb04, "CLK_ADCHS_STAT offset wrong");
} /* namespace ccu1 */
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,
};
enum class Status {
NotActive = 0b00,
ActivatedByRGUInput = 0b01,
ActivatedBySoftware = 0b11,
};
inline void reset(const Reset reset) {
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;
}
inline Status status(const Reset reset) {
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;
}
inline uint32_t external_status(const Reset reset) {
return LPC_RGU->RESET_EXT_STAT[toUType(reset)];
}
inline uint64_t operator|(Reset r1, Reset r2) {
return (1ULL << toUType(r1)) | (1ULL << toUType(r2));
}
inline uint64_t operator|(uint64_t m, Reset r) {
return m | (1ULL << toUType(r));
}
static_assert(offsetof(LPC_RGU_Type, RESET_CTRL[0]) == 0x100, "RESET_CTRL[0] offset wrong");
static_assert(offsetof(LPC_RGU_Type, RESET_STATUS[0]) == 0x110, "RESET_STATUS[0] offset wrong");
static_assert(offsetof(LPC_RGU_Type, RESET_ACTIVE_STATUS[0]) == 0x150, "RESET_ACTIVE_STATUS[0] offset wrong");
static_assert(offsetof(LPC_RGU_Type, RESET_EXT_STAT[1]) == 0x404, "RESET_EXT_STAT[1] offset wrong");
static_assert(offsetof(LPC_RGU_Type, RESET_EXT_STAT[60]) == 0x4f0, "RESET_EXT_STAT[60] offset wrong");
} /* namespace rgu */
namespace scu {
struct SFS {
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)
;
}
};
static_assert(offsetof(LPC_SCU_Type, PINTSEL0) == 0xe00, "PINTSEL0 offset wrong");
} /* namespace scu */
namespace sgpio {
static_assert(offsetof(LPC_SGPIO_Type, MASK_A) == 0x0200, "SGPIO MASK_A offset wrong");
static_assert(offsetof(LPC_SGPIO_Type, GPIO_OUTREG) == 0x0214, "SGPIO GPIO_OUTREG offset wrong");
static_assert(offsetof(LPC_SGPIO_Type, CTRL_DISABLE) == 0x0220, "SGPIO CTRL_DISABLE offset wrong");
static_assert(offsetof(LPC_SGPIO_Type, CLR_EN_0) == 0x0f00, "SGPIO CLR_EN_0 offset wrong");
static_assert(offsetof(LPC_SGPIO_Type, CLR_EN_1) == 0x0f20, "SGPIO CLR_EN_1 offset wrong");
static_assert(offsetof(LPC_SGPIO_Type, CLR_EN_2) == 0x0f40, "SGPIO CLR_EN_2 offset wrong");
static_assert(offsetof(LPC_SGPIO_Type, CLR_EN_3) == 0x0f60, "SGPIO CLR_EN_3 offset wrong");
static_assert(offsetof(LPC_SGPIO_Type, SET_STATUS_3) == 0x0f74, "SGPIO SET_STATUS_3 offset wrong");
static_assert(sizeof(LPC_SGPIO_Type) == 0x0f78, "SGPIO type size wrong");
} /* namespace sgpio */
namespace gpdma {
static_assert(offsetof(LPC_GPDMA_Type, SYNC) == 0x034, "GPDMA SYNC offset wrong");
static_assert(offsetof(LPC_GPDMA_Type, CH[0]) == 0x100, "GPDMA CH[0] offset wrong");
static_assert(offsetof(LPC_GPDMA_Type, CH[7]) == 0x1e0, "GPDMA CH[7] offset wrong");
} /* namespace gpdma */
namespace sdmmc {
static_assert(offsetof(LPC_SDMMC_Type, RESP0) == 0x030, "SDMMC RESP0 offset wrong");
static_assert(offsetof(LPC_SDMMC_Type, TCBCNT) == 0x05c, "SDMMC TCBCNT offset wrong");
static_assert(offsetof(LPC_SDMMC_Type, RST_N) == 0x078, "SDMMC RST_N offset wrong");
static_assert(offsetof(LPC_SDMMC_Type, BMOD) == 0x080, "SDMMC BMOD offset wrong");
static_assert(offsetof(LPC_SDMMC_Type, DATA) == 0x100, "SDMMC DATA offset wrong");
} /* namespace sdmmc */
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;
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");
} /* namespace spifi */
namespace timer {
static_assert(offsetof(LPC_TIMER_Type, MR[0]) == 0x018, "TIMER MR[0] offset wrong");
static_assert(offsetof(LPC_TIMER_Type, CCR) == 0x028, "TIMER CCR offset wrong");
static_assert(offsetof(LPC_TIMER_Type, EMR) == 0x03c, "TIMER EMR offset wrong");
static_assert(offsetof(LPC_TIMER_Type, CTCR) == 0x070, "TIMER CTCR offset wrong");
} /* namespace timer */
namespace rtc {
namespace interrupt {
inline void clear_all() {
LPC_RTC->ILR = (1U << 1) | (1U << 0);
}
inline void enable_second_inc() {
LPC_RTC->CIIR = (1U << 0);
}
} /* namespace */
#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(
) : RTCTime { 0, 0 }
{
}
uint16_t year() const {
return (tv_date >> 16) & 0xfff;
}
uint8_t month() const {
return (tv_date >> 8) & 0x00f;
}
uint8_t day() const {
return (tv_date >> 0) & 0x01f;
}
uint8_t hour() const {
return (tv_time >> 16) & 0x01f;
}
uint8_t minute() const {
return (tv_time >> 8) & 0x03f;
}
uint8_t second() const {
return (tv_time >> 0) & 0x03f;
}
};
#endif
static_assert(offsetof(LPC_RTC_Type, CCR) == 0x008, "RTC CCR offset wrong");
static_assert(offsetof(LPC_RTC_Type, ASEC) == 0x060, "RTC ASEC offset wrong");
} /* namespace rtc */
} /* namespace lpc43xx */
#endif/*__LPC43XX_CPP_H__*/

View File

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "manchester.hpp"
#include "string_format.hpp"
size_t ManchesterBase::symbols_count() const {
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 };
}
}
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 };
}
}
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;
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];
data <<= 1;
data |= symbol.value;
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);
}
}
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;
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __MANCHESTER_H__
#define __MANCHESTER_H__
#include <cstdint>
#include <cstddef>
#include <bitset>
#include <string>
#include "baseband_packet.hpp"
struct DecodedSymbol {
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;
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;
};
class BiphaseMDecoder : public ManchesterBase {
public:
using ManchesterBase::ManchesterBase;
DecodedSymbol operator[](const size_t index) const;
};
template<typename T>
T operator|(const T& l, const DecodedSymbol& r) {
return l | r.value;
}
struct FormattedSymbols {
const std::string data;
const std::string errors;
};
FormattedSymbols format_symbols(
const ManchesterBase& decoder
);
void manchester_encode(uint8_t * dest, uint8_t * src, const size_t length, const size_t sense = 0);
#endif/*__MANCHESTER_H__*/

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __MEMORY_MAP_H__
#define __MEMORY_MAP_H__
#include <cstddef>
#include <cstdint>
#include "lpc43xx_cpp.hpp"
using namespace lpc43xx;
#include "utility.hpp"
namespace portapack {
namespace memory {
struct region_t {
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 end() const {
return base_ + size_;
}
constexpr size_t size() const {
return 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 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 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_hackrf = local_sram_0;
} /* namespace map */
} /* namespace memory */
} /* namespace portapack */
#endif/*__MEMORY_MAP_H__*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "message_queue.hpp"
#include "lpc43xx_cpp.hpp"
using namespace lpc43xx;
#if defined(LPC43XX_M0)
void MessageQueue::signal() {
creg::m0apptxevent::assert_event();
}
#endif
#if defined(LPC43XX_M4)
void MessageQueue::signal() {
creg::m4txevent::assert_event();
}
#endif

View File

@@ -0,0 +1,118 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __MESSAGE_QUEUE_H__
#define __MESSAGE_QUEUE_H__
#include <cstdint>
#include "message.hpp"
#include "fifo.hpp"
#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);
}
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");
return push(&message, sizeof(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;
}
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();
}
}
bool is_empty() const {
return fifo.is_empty();
}
void reset() {
fifo.reset();
}
private:
FIFO<uint8_t> fifo;
Mutex mutex_write { };
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;
}
bool skip() {
return fifo.skip();
}
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;
}
size_t len() const {
return fifo.len();
}
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__*/

View File

@@ -0,0 +1,2 @@
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

@@ -0,0 +1,91 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "morse.hpp"
#include "baseband_api.hpp"
#include "portapack.hpp"
using namespace portapack;
#include "utility.hpp"
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;
}
} /* namespace morse */

View File

@@ -0,0 +1,148 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __MORSE_H__
#define __MORSE_H__
#include "tonesets.hpp"
#include "portapack_shared_memory.hpp"
#define MORSE_DOT 1
#define MORSE_DASH 3
#define MORSE_SYMBOL_SPACE 1
#define MORSE_LETTER_SPACE 3
#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);
constexpr char foxhunt_codes[11][4] = {
{ "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
};
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
};
} /* namespace morse */
#endif/*__MORSE_H__*/

View File

@@ -0,0 +1,341 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#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_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_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];
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_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
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::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::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, 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;
}
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;
}
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, 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;
}
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

@@ -0,0 +1,101 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __MSGPACK_H__
#define __MSGPACK_H__
#include "ui.hpp"
#include <memory>
#include <cstring>
#define MSGPACK_NIL 0xC0
#define MSGPACK_FALSE 0xC2
#define MSGPACK_TRUE 0xC3
#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_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_ARR16 0xDC
#define MSGPACK_TYPE_ARR32 0xDD
#define MSGPACK_TYPE_MAP16 0xDE
#define MSGPACK_TYPE_MAP32 0xDF
class MsgPack {
public:
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);
// 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;
};
#endif

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2016 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __OPTIONAL_H__
#define __OPTIONAL_H__
#include <utility>
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 } { };
bool is_valid() const { return valid_; };
T value() const { return value_; };
private:
T value_;
bool valid_;
};
#endif/*__OPTIONAL_H__*/

View File

@@ -0,0 +1,233 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PINS_H__
#define __PINS_H__
#include "gpio.hpp"
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,
};
constexpr Pin pins[] = {
[P0_0] = { 0, 0, PinConfig::sgpio_inout_fast(3) }, /* SGPIO0/P75/BANK2F3M3: CPLD.89/HOST_DATA0(IO) */
[P0_1] = { 0, 1, PinConfig::sgpio_inout_fast(3) }, /* SGPIO1/BANK2F3M5: CPLD.79/HOST_DATA1(IO) */
[P1_0] = { 1, 0, PinConfig::sgpio_inout_fast(6) }, /* SGPIO7/P76/BANK2F3M7: CPLD.77/HOST_DATA7(IO) */
[P1_1] = { 1, 1, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* P1_1/P74: 10K PU, BOOT0 */
[P1_2] = { 1, 2, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* P1_2/P73: 10K PD, BOOT1 */
[P1_3] = { 1, 3, { .mode=5, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* SSP1_MISO/P41: MAX2837.DOUT(O) */
[P1_4] = { 1, 4, { .mode=5, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* SSP1_MOSI/P40: MAX2837.DIN(I), MAX5864.DIN(I) */
[P1_5] = { 1, 5, { .mode=0, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* SD_POW: PortaPack CPLD.TDO(O) */
[P1_6] = { 1, 6, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=0 } }, /* SD_CMD: PortaPack SD.CMD(IO) */
[P1_7] = { 1, 7, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* !MIX_BYPASS/P35: U1.VCTL1(I), U11.VCTL2(I), U9.V2(I) */
[P1_8] = { 1, 8, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* SD_VOLT0: PortaPack CPLD.TMS(I) */
[P1_9] = { 1, 9, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=0 } }, /* SD_DAT0: PortaPack SD.DAT0(IO) */
[P1_10] = { 1, 10, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=0 } }, /* SD_DAT1: PortaPack SD.DAT1(IO) */
[P1_11] = { 1, 11, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=0 } }, /* SD_DAT2: PortaPack SD.DAT2(IO) */
[P1_12] = { 1, 12, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=0 } }, /* SD_DAT3: PortaPack SD.DAT3(IO) */
[P1_13] = { 1, 13, { .mode=7, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* SD_CD: PortaPack SD.CD(O) */
[P1_14] = { 1, 14, PinConfig::sgpio_out_fast_with_pullup(6) }, /* SGPIO10/P78/BANK2F3M8: CPLD.76/HOST_DISABLE(I) */
[P1_15] = { 1, 15, PinConfig::sgpio_inout_fast(2) }, /* SGPIO2/BANK2F3M9: CPLD.74/HOST_DATA2(IO) */
[P1_16] = { 1, 16, PinConfig::sgpio_inout_fast(2) }, /* SGPIO3/BANK2F3M10: CPLD.72/HOST_DATA3(IO) */
[P1_17] = { 1, 17, PinConfig::sgpio_out_fast_with_pullup(6) }, /* SGPIO11/P79/BANK2F3M11: CPLD.71/HOST_DIRECTION(I) */
[P1_18] = { 1, 18, PinConfig::gpio_out_with_pulldown(0) }, /* SGPIO12/BANK2F3M12: CPLD.70/HOST_INVERT(I) */
[P1_19] = { 1, 19, { .mode=1, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* SSP1_SCK/P39: MAX2837.SCLK(I), MAX5864.SCLK(I) */
[P1_20] = { 1, 20, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* CS_XCVR/P53: MAX2837.CS(I) */
[P2_0] = { 2, 0, { .mode=4, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* U0_TXD: PortaPack P2_0/IO_STBX */
[P2_1] = { 2, 1, { .mode=4, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* U0_RXD: PortaPack P2_1/ADDR */
[P2_2] = { 2, 2, PinConfig::sgpio_inout_fast(0) }, /* SGPIO6/BANK2F3M16: CPLD.61/HOST_DATA6(IO) */
[P2_3] = { 2, 3, { .mode=4, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* I2C1_SDA: PortaPack P2_3/LCD_TE */
[P2_4] = { 2, 4, { .mode=4, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* I2C1_SCL: PortaPack P2_4/LCD_RDX */
[P2_5] = { 2, 5, { .mode=4, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* RX/P43: U7.VCTL1(I), U10.VCTL1(I), U2.VCTL1(I) */
[P2_6] = { 2, 6, { .mode=4, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* MIXER_SCLK/P31: 33pF, RFFC5072.SCLK(I) */
[P2_7] = { 2, 7, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* ISP: 10K PU, Unused */
[P2_8] = { 2, 8, { .mode=4, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* P2_8: 10K PD, BOOT2, DFU switch, PortaPack P2_8/<unused> */
[P2_9] = { 2, 9, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* P2_9: 10K PD, BOOT3, PortaPack P2_9/LCD_WRX */
[P2_10] = { 2, 10, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* AMP_BYPASS/P50: U14.V2(I), U12.V2(I) */
[P2_11] = { 2, 11, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* RX_AMP/P49: U12.V1(I), U14.V3(I) */
[P2_12] = { 2, 12, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* !RX_AMP_PWR/P52: 10K PU, Q1.G(I), power to U13 (RX amp) */
[P2_13] = { 2, 13, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* P2_13: PortaPack P2_13/DIR */
[P3_0] = { 3, 0, { .mode=2, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* I2S0_TX_SCK: PortaPack I2S0_TX_SCK(I) */
[P3_1] = { 3, 1, { .mode=0, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* I2S0_RX_WS: PortaPack I2S0_TX_WS(I). Input enabled to fold back into RX. */
[P3_2] = { 3, 2, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* I2S0_RX_SDA: PortaPack I2S0_TX_SDA(I) */
[P4_0] = { 4, 0, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* HP/P44: U6.VCTL1(I), U5.VCTL2(I) */
[P4_1] = { 4, 1, PinConfig::gpio_led(0) }, /* LED1: LED1.A(I) */
[P4_2] = { 4, 2, PinConfig::gpio_led(0) }, /* LED2: LED2.A(I) */
[P4_3] = { 4, 3, PinConfig::sgpio_in_fast(7) }, /* SGPIO9/P77/BANK2F3M1: CPLD.91/HOST_CAPTURE(O) */
[P4_4] = { 4, 4, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TXENABLE/P55: MAX2837.TXENABLE(I) */
[P4_5] = { 4, 5, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* RXENABLE/P56: MAX2837.RXENABLE(I) */
[P4_6] = { 4, 6, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* XCVR_EN: 10K PD, MAX2837.ENABLE(I) */
[P4_7] = { 4, 7, { .mode=1, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=0 } }, /* GP_CLKIN/P72/MCU_CLK: SI5351C.CLK7(O) */
[P4_8] = { 4, 8, PinConfig::floating_input_with_pull(0, 4) }, /* SGPIO13/BANK2F3M2: CPLD.90/HOST_SYNC_EN(I) */
[P4_9] = { 4, 9, PinConfig::floating_input(4) }, /* SGPIO14/BANK2F3M4: CPLD.81(I) */
[P4_10] = { 4, 10, PinConfig::floating_input(4) }, /* SGPIO15/BANK2F3M6: CPLD.78(I) */
[P5_0] = { 5, 0, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* !VAA_ENABLE: 10K PU, Q3.G(I), power to VAA */
[P5_1] = { 5, 1, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* LP/P45: U6.VCTL2(I), U5.VCTL1(I) */
[P5_2] = { 5, 2, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TX_MIX_BP/P46: U9.V1(I) */
[P5_3] = { 5, 3, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* RX_MIX_BP/P47: U9.V3(I) */
[P5_4] = { 5, 4, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* MIXER_ENX/P32: 10K PU, 33pF, RFFC5072.ENX(I) */
[P5_5] = { 5, 5, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* MIXER_RESETX/P33: 10K PU, 33pF, RFFC5072.RESETX(I) */
[P5_6] = { 5, 6, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TX_AMP/P48: U12.V3(I), U14.V1(I) */
[P5_7] = { 5, 7, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* CS_AD/P54: MAX5864.CS(I) */
[P6_0] = { 6, 0, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* I2S0_RX_MCLK: Unused */
[P6_1] = { 6, 1, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* CPLD_TCK: CPLD.TCK(I), PortaPack CPLD.TCK(I) */
[P6_2] = { 6, 2, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* CPLD_TDI: CPLD.TDI(I), PortaPack I2S0_RX_SDA(O), PortaPack CPLD.TDI(I) */
[P6_3] = { 6, 3, PinConfig::sgpio_inout_fast(2) }, /* SGPIO4/BANK2F3M14: CPLD.67/HOST_DATA4(IO) */
[P6_4] = { 6, 4, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* MIXER_SDATA/P27: 33pF, RFFC5072.SDATA(IO) */
[P6_5] = { 6, 5, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* CPLD_TMS: CPLD.TMS(I) */
[P6_6] = { 6, 6, PinConfig::sgpio_inout_fast(2) }, /* SGPIO5/BANK2F3M15: CPLD.64/HOST_DATA5(IO) */
[P6_7] = { 6, 7, { .mode=4, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TX/P42: U7.VCTL2(I), U10.VCTL2(I), U2.VCTL2(I) */
[P6_8] = { 6, 8, { .mode=4, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* MIX_BYPASS/P34: U1.VCTL2(I), U11.VCTL1(I) */
[P6_9] = { 6, 9, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* !TX_AMP_PWR/P51: 10K PU, Q2.G(I), power to U25 (TX amp) */
[P6_10] = { 6, 10, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* EN1V8/P70: 10K PD, TPS62410.EN2(I), 1V8LED.A(I) */
[P6_11] = { 6, 11, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* VREGMODE/P69: TPS62410.MODE/DATA(I) */
[P6_12] = { 6, 12, PinConfig::gpio_led(0) }, /* LED3: LED3.A(I) */
[P7_0] = { 7, 0, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_8: PortaPack GPIO3_8(IO) */
[P7_1] = { 7, 1, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_9: PortaPack GPIO3_9(IO) */
[P7_2] = { 7, 2, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_10: PortaPack GPIO3_10(IO) */
[P7_3] = { 7, 3, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_11: PortaPack GPIO3_11(IO) */
[P7_4] = { 7, 4, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_12: PortaPack GPIO3_12(IO) */
[P7_5] = { 7, 5, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_13: PortaPack GPIO3_13(IO) */
[P7_6] = { 7, 6, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_14: PortaPack GPIO3_14(IO) */
[P7_7] = { 7, 7, PinConfig::gpio_inout_with_pulldown(0) }, /* GPIO3_15: PortaPack GPIO3_15(IO) */
[P9_5] = { 9, 5, { .mode=4, .pd=0, .pu=0, .fast=0, .input=1, .ifilt=1 } }, /* CPLD_TDO: CPLD.TDO(O) */
[P9_6] = { 9, 6, PinConfig::sgpio_in_fast(6) }, /* SGPIO8/SGPIO_CLK/P60: SI5351C.CLK2(O) */
[PF_4] = { 15, 4, { .mode=7, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* I2S0_RX_SCK: Unused */
[CLK0] = { 24, 0, { .mode=4, .pd=1, .pu=0, .fast=0, .input=1, .ifilt=0 } }, /* SD_CLK: PortaPack SD.CLK, enable input buffer for timing feedback? */
[CLK2] = { 24, 2, { .mode=6, .pd=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* I2S0_TX_CLK: PortaPack I2S0_TX_MCLK */
};
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,
};
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 },
[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 },
[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 },
[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 },
};
}
#endif/*__PINS_H__*/

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