Add software
This commit is contained in:
107
Software/portapack-mayhem/firmware/common/acars_packet.cpp
Normal file
107
Software/portapack-mayhem/firmware/common/acars_packet.cpp
Normal 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 */
|
||||
75
Software/portapack-mayhem/firmware/common/acars_packet.hpp
Normal file
75
Software/portapack-mayhem/firmware/common/acars_packet.hpp
Normal 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__*/
|
||||
135
Software/portapack-mayhem/firmware/common/adc.hpp
Normal file
135
Software/portapack-mayhem/firmware/common/adc.hpp
Normal 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__*/
|
||||
384
Software/portapack-mayhem/firmware/common/adsb.cpp
Normal file
384
Software/portapack-mayhem/firmware/common/adsb.cpp
Normal 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 */
|
||||
111
Software/portapack-mayhem/firmware/common/adsb.hpp
Normal file
111
Software/portapack-mayhem/firmware/common/adsb.hpp
Normal 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__*/
|
||||
27
Software/portapack-mayhem/firmware/common/adsb_frame.cpp
Normal file
27
Software/portapack-mayhem/firmware/common/adsb_frame.cpp
Normal 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 */
|
||||
131
Software/portapack-mayhem/firmware/common/adsb_frame.hpp
Normal file
131
Software/portapack-mayhem/firmware/common/adsb_frame.hpp
Normal 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__*/
|
||||
22
Software/portapack-mayhem/firmware/common/ais_baseband.cpp
Normal file
22
Software/portapack-mayhem/firmware/common/ais_baseband.cpp
Normal 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"
|
||||
47
Software/portapack-mayhem/firmware/common/ais_baseband.hpp
Normal file
47
Software/portapack-mayhem/firmware/common/ais_baseband.hpp
Normal 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__*/
|
||||
220
Software/portapack-mayhem/firmware/common/ais_packet.cpp
Normal file
220
Software/portapack-mayhem/firmware/common/ais_packet.cpp
Normal 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 */
|
||||
148
Software/portapack-mayhem/firmware/common/ais_packet.hpp
Normal file
148
Software/portapack-mayhem/firmware/common/ais_packet.hpp
Normal 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__*/
|
||||
323
Software/portapack-mayhem/firmware/common/ak4951.cpp
Normal file
323
Software/portapack-mayhem/firmware/common/ak4951.cpp
Normal 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 */
|
||||
886
Software/portapack-mayhem/firmware/common/ak4951.hpp
Normal file
886
Software/portapack-mayhem/firmware/common/ak4951.hpp
Normal 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__*/
|
||||
27
Software/portapack-mayhem/firmware/common/aprs_packet.cpp
Normal file
27
Software/portapack-mayhem/firmware/common/aprs_packet.cpp
Normal 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 */
|
||||
495
Software/portapack-mayhem/firmware/common/aprs_packet.hpp
Normal file
495
Software/portapack-mayhem/firmware/common/aprs_packet.hpp
Normal 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__*/
|
||||
100
Software/portapack-mayhem/firmware/common/backlight.cpp
Normal file
100
Software/portapack-mayhem/firmware/common/backlight.cpp
Normal 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 */
|
||||
120
Software/portapack-mayhem/firmware/common/backlight.hpp
Normal file
120
Software/portapack-mayhem/firmware/common/backlight.hpp
Normal 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 */
|
||||
40
Software/portapack-mayhem/firmware/common/baseband.hpp
Normal file
40
Software/portapack-mayhem/firmware/common/baseband.hpp
Normal 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__*/
|
||||
38
Software/portapack-mayhem/firmware/common/baseband_cpld.cpp
Normal file
38
Software/portapack-mayhem/firmware/common/baseband_cpld.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
40
Software/portapack-mayhem/firmware/common/baseband_cpld.hpp
Normal file
40
Software/portapack-mayhem/firmware/common/baseband_cpld.hpp
Normal 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__*/
|
||||
@@ -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__*/
|
||||
392
Software/portapack-mayhem/firmware/common/baseband_sgpio.cpp
Normal file
392
Software/portapack-mayhem/firmware/common/baseband_sgpio.cpp
Normal 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 */
|
||||
66
Software/portapack-mayhem/firmware/common/baseband_sgpio.hpp
Normal file
66
Software/portapack-mayhem/firmware/common/baseband_sgpio.hpp
Normal 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__*/
|
||||
364
Software/portapack-mayhem/firmware/common/bch_code.cpp
Normal file
364
Software/portapack-mayhem/firmware/common/bch_code.cpp
Normal 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);
|
||||
}
|
||||
61
Software/portapack-mayhem/firmware/common/bch_code.hpp
Normal file
61
Software/portapack-mayhem/firmware/common/bch_code.hpp
Normal 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__*/
|
||||
73
Software/portapack-mayhem/firmware/common/bit_pattern.hpp
Normal file
73
Software/portapack-mayhem/firmware/common/bit_pattern.hpp
Normal 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__*/
|
||||
53
Software/portapack-mayhem/firmware/common/bmp.hpp
Normal file
53
Software/portapack-mayhem/firmware/common/bmp.hpp
Normal 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)
|
||||
36
Software/portapack-mayhem/firmware/common/buffer.cpp
Normal file
36
Software/portapack-mayhem/firmware/common/buffer.cpp
Normal 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
|
||||
91
Software/portapack-mayhem/firmware/common/buffer.hpp
Normal file
91
Software/portapack-mayhem/firmware/common/buffer.hpp
Normal 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__*/
|
||||
@@ -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;
|
||||
}
|
||||
112
Software/portapack-mayhem/firmware/common/buffer_exchange.hpp
Normal file
112
Software/portapack-mayhem/firmware/common/buffer_exchange.hpp
Normal 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);
|
||||
};
|
||||
68
Software/portapack-mayhem/firmware/common/chibios_cpp.cpp
Normal file
68
Software/portapack-mayhem/firmware/common/chibios_cpp.cpp
Normal 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 */
|
||||
43
Software/portapack-mayhem/firmware/common/chibios_cpp.hpp
Normal file
43
Software/portapack-mayhem/firmware/common/chibios_cpp.hpp
Normal 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__*/
|
||||
139
Software/portapack-mayhem/firmware/common/complex.hpp
Normal file
139
Software/portapack-mayhem/firmware/common/complex.hpp
Normal 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__*/
|
||||
274
Software/portapack-mayhem/firmware/common/cpld_max5.cpp
Normal file
274
Software/portapack-mayhem/firmware/common/cpld_max5.cpp
Normal 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 */
|
||||
203
Software/portapack-mayhem/firmware/common/cpld_max5.hpp
Normal file
203
Software/portapack-mayhem/firmware/common/cpld_max5.hpp
Normal 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__*/
|
||||
134
Software/portapack-mayhem/firmware/common/cpld_update.cpp
Normal file
134
Software/portapack-mayhem/firmware/common/cpld_update.cpp
Normal 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 */
|
||||
47
Software/portapack-mayhem/firmware/common/cpld_update.hpp
Normal file
47
Software/portapack-mayhem/firmware/common/cpld_update.hpp
Normal 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__*/
|
||||
179
Software/portapack-mayhem/firmware/common/cpld_xilinx.cpp
Normal file
179
Software/portapack-mayhem/firmware/common/cpld_xilinx.cpp
Normal 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 */
|
||||
126
Software/portapack-mayhem/firmware/common/cpld_xilinx.hpp
Normal file
126
Software/portapack-mayhem/firmware/common/cpld_xilinx.hpp
Normal 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__*/
|
||||
195
Software/portapack-mayhem/firmware/common/crc.hpp
Normal file
195
Software/portapack-mayhem/firmware/common/crc.hpp
Normal 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__*/
|
||||
108
Software/portapack-mayhem/firmware/common/debug.cpp
Normal file
108
Software/portapack-mayhem/firmware/common/debug.cpp
Normal 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
|
||||
|
||||
}
|
||||
25
Software/portapack-mayhem/firmware/common/debug.hpp
Normal file
25
Software/portapack-mayhem/firmware/common/debug.hpp
Normal 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__*/
|
||||
22
Software/portapack-mayhem/firmware/common/dsp_fft.cpp
Normal file
22
Software/portapack-mayhem/firmware/common/dsp_fft.cpp
Normal 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"
|
||||
138
Software/portapack-mayhem/firmware/common/dsp_fft.hpp
Normal file
138
Software/portapack-mayhem/firmware/common/dsp_fft.hpp
Normal 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__*/
|
||||
22
Software/portapack-mayhem/firmware/common/dsp_fir_taps.cpp
Normal file
22
Software/portapack-mayhem/firmware/common/dsp_fir_taps.cpp
Normal 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"
|
||||
431
Software/portapack-mayhem/firmware/common/dsp_fir_taps.hpp
Normal file
431
Software/portapack-mayhem/firmware/common/dsp_fir_taps.hpp
Normal 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__*/
|
||||
83
Software/portapack-mayhem/firmware/common/dsp_iir.cpp
Normal file
83
Software/portapack-mayhem/firmware/common/dsp_iir.cpp
Normal 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;
|
||||
}
|
||||
90
Software/portapack-mayhem/firmware/common/dsp_iir.hpp
Normal file
90
Software/portapack-mayhem/firmware/common/dsp_iir.hpp
Normal 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__*/
|
||||
120
Software/portapack-mayhem/firmware/common/dsp_iir_config.hpp
Normal file
120
Software/portapack-mayhem/firmware/common/dsp_iir_config.hpp
Normal 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__*/
|
||||
22
Software/portapack-mayhem/firmware/common/dsp_sos.cpp
Normal file
22
Software/portapack-mayhem/firmware/common/dsp_sos.cpp
Normal 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"
|
||||
51
Software/portapack-mayhem/firmware/common/dsp_sos.hpp
Normal file
51
Software/portapack-mayhem/firmware/common/dsp_sos.hpp
Normal 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__*/
|
||||
37
Software/portapack-mayhem/firmware/common/dsp_sos_config.hpp
Normal file
37
Software/portapack-mayhem/firmware/common/dsp_sos_config.hpp
Normal 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__*/
|
||||
36
Software/portapack-mayhem/firmware/common/dsp_types.hpp
Normal file
36
Software/portapack-mayhem/firmware/common/dsp_types.hpp
Normal 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__*/
|
||||
112
Software/portapack-mayhem/firmware/common/emu_cc1101.hpp
Normal file
112
Software/portapack-mayhem/firmware/common/emu_cc1101.hpp
Normal 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__*/
|
||||
106
Software/portapack-mayhem/firmware/common/ert_packet.cpp
Normal file
106
Software/portapack-mayhem/firmware/common/ert_packet.cpp
Normal 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 */
|
||||
89
Software/portapack-mayhem/firmware/common/ert_packet.hpp
Normal file
89
Software/portapack-mayhem/firmware/common/ert_packet.hpp
Normal 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__*/
|
||||
24
Software/portapack-mayhem/firmware/common/event.cpp
Normal file
24
Software/portapack-mayhem/firmware/common/event.cpp
Normal 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"
|
||||
27
Software/portapack-mayhem/firmware/common/event.hpp
Normal file
27
Software/portapack-mayhem/firmware/common/event.hpp
Normal 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__*/
|
||||
65
Software/portapack-mayhem/firmware/common/field_reader.hpp
Normal file
65
Software/portapack-mayhem/firmware/common/field_reader.hpp
Normal 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__*/
|
||||
239
Software/portapack-mayhem/firmware/common/fifo.hpp
Normal file
239
Software/portapack-mayhem/firmware/common/fifo.hpp
Normal 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__*/
|
||||
54
Software/portapack-mayhem/firmware/common/gcc.cpp
Normal file
54
Software/portapack-mayhem/firmware/common/gcc.cpp
Normal 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(); }
|
||||
}
|
||||
25
Software/portapack-mayhem/firmware/common/gcc.hpp
Normal file
25
Software/portapack-mayhem/firmware/common/gcc.hpp
Normal 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__*/
|
||||
113
Software/portapack-mayhem/firmware/common/gpdma.cpp
Normal file
113
Software/portapack-mayhem/firmware/common/gpdma.cpp
Normal 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 */
|
||||
375
Software/portapack-mayhem/firmware/common/gpdma.hpp
Normal file
375
Software/portapack-mayhem/firmware/common/gpdma.hpp
Normal 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__*/
|
||||
318
Software/portapack-mayhem/firmware/common/gpio.hpp
Normal file
318
Software/portapack-mayhem/firmware/common/gpio.hpp
Normal 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__*/
|
||||
@@ -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__*/
|
||||
90
Software/portapack-mayhem/firmware/common/hackrf_gpio.hpp
Normal file
90
Software/portapack-mayhem/firmware/common/hackrf_gpio.hpp
Normal 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__*/
|
||||
32
Software/portapack-mayhem/firmware/common/hackrf_hal.cpp
Normal file
32
Software/portapack-mayhem/firmware/common/hackrf_hal.cpp
Normal 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 */
|
||||
79
Software/portapack-mayhem/firmware/common/hackrf_hal.hpp
Normal file
79
Software/portapack-mayhem/firmware/common/hackrf_hal.hpp
Normal 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__*/
|
||||
65
Software/portapack-mayhem/firmware/common/i2c_pp.cpp
Normal file
65
Software/portapack-mayhem/firmware/common/i2c_pp.cpp
Normal 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);
|
||||
}
|
||||
86
Software/portapack-mayhem/firmware/common/i2c_pp.hpp
Normal file
86
Software/portapack-mayhem/firmware/common/i2c_pp.hpp
Normal 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__*/
|
||||
277
Software/portapack-mayhem/firmware/common/i2s.hpp
Normal file
277
Software/portapack-mayhem/firmware/common/i2s.hpp
Normal 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__*/
|
||||
34
Software/portapack-mayhem/firmware/common/jammer.cpp
Normal file
34
Software/portapack-mayhem/firmware/common/jammer.cpp
Normal 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 */
|
||||
45
Software/portapack-mayhem/firmware/common/jammer.hpp
Normal file
45
Software/portapack-mayhem/firmware/common/jammer.hpp
Normal 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__*/
|
||||
41
Software/portapack-mayhem/firmware/common/jtag.cpp
Normal file
41
Software/portapack-mayhem/firmware/common/jtag.cpp
Normal 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 */
|
||||
101
Software/portapack-mayhem/firmware/common/jtag.hpp
Normal file
101
Software/portapack-mayhem/firmware/common/jtag.hpp
Normal 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__*/
|
||||
266
Software/portapack-mayhem/firmware/common/jtag_tap.cpp
Normal file
266
Software/portapack-mayhem/firmware/common/jtag_tap.cpp
Normal 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 */
|
||||
155
Software/portapack-mayhem/firmware/common/jtag_tap.hpp
Normal file
155
Software/portapack-mayhem/firmware/common/jtag_tap.hpp
Normal 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__*/
|
||||
46
Software/portapack-mayhem/firmware/common/jtag_target.hpp
Normal file
46
Software/portapack-mayhem/firmware/common/jtag_target.hpp
Normal 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__*/
|
||||
140
Software/portapack-mayhem/firmware/common/jtag_target_gpio.hpp
Normal file
140
Software/portapack-mayhem/firmware/common/jtag_target_gpio.hpp
Normal 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__*/
|
||||
660
Software/portapack-mayhem/firmware/common/lcd_ili9341.cpp
Normal file
660
Software/portapack-mayhem/firmware/common/lcd_ili9341.cpp
Normal 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 */
|
||||
124
Software/portapack-mayhem/firmware/common/lcd_ili9341.hpp
Normal file
124
Software/portapack-mayhem/firmware/common/lcd_ili9341.hpp
Normal 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__*/
|
||||
58
Software/portapack-mayhem/firmware/common/led.hpp
Normal file
58
Software/portapack-mayhem/firmware/common/led.hpp
Normal 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__*/
|
||||
106
Software/portapack-mayhem/firmware/common/lfsr_random.cpp
Normal file
106
Software/portapack-mayhem/firmware/common/lfsr_random.cpp
Normal 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;
|
||||
}
|
||||
34
Software/portapack-mayhem/firmware/common/lfsr_random.hpp
Normal file
34
Software/portapack-mayhem/firmware/common/lfsr_random.hpp
Normal 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__*/
|
||||
566
Software/portapack-mayhem/firmware/common/lpc43xx_cpp.hpp
Normal file
566
Software/portapack-mayhem/firmware/common/lpc43xx_cpp.hpp
Normal 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__*/
|
||||
96
Software/portapack-mayhem/firmware/common/manchester.cpp
Normal file
96
Software/portapack-mayhem/firmware/common/manchester.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
86
Software/portapack-mayhem/firmware/common/manchester.hpp
Normal file
86
Software/portapack-mayhem/firmware/common/manchester.hpp
Normal 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__*/
|
||||
88
Software/portapack-mayhem/firmware/common/memory_map.hpp
Normal file
88
Software/portapack-mayhem/firmware/common/memory_map.hpp
Normal 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__*/
|
||||
1140
Software/portapack-mayhem/firmware/common/message.hpp
Normal file
1140
Software/portapack-mayhem/firmware/common/message.hpp
Normal file
File diff suppressed because it is too large
Load Diff
37
Software/portapack-mayhem/firmware/common/message_queue.cpp
Normal file
37
Software/portapack-mayhem/firmware/common/message_queue.cpp
Normal 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
|
||||
118
Software/portapack-mayhem/firmware/common/message_queue.hpp
Normal file
118
Software/portapack-mayhem/firmware/common/message_queue.hpp
Normal 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__*/
|
||||
2
Software/portapack-mayhem/firmware/common/modules.h
Normal file
2
Software/portapack-mayhem/firmware/common/modules.h
Normal 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,};
|
||||
91
Software/portapack-mayhem/firmware/common/morse.cpp
Normal file
91
Software/portapack-mayhem/firmware/common/morse.cpp
Normal 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 */
|
||||
148
Software/portapack-mayhem/firmware/common/morse.hpp
Normal file
148
Software/portapack-mayhem/firmware/common/morse.hpp
Normal 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__*/
|
||||
341
Software/portapack-mayhem/firmware/common/msgpack.cpp
Normal file
341
Software/portapack-mayhem/firmware/common/msgpack.cpp
Normal 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;
|
||||
}
|
||||
101
Software/portapack-mayhem/firmware/common/msgpack.hpp
Normal file
101
Software/portapack-mayhem/firmware/common/msgpack.hpp
Normal 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
|
||||
42
Software/portapack-mayhem/firmware/common/optional.hpp
Normal file
42
Software/portapack-mayhem/firmware/common/optional.hpp
Normal 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__*/
|
||||
233
Software/portapack-mayhem/firmware/common/pins.hpp
Normal file
233
Software/portapack-mayhem/firmware/common/pins.hpp
Normal 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
Reference in New Issue
Block a user