Initial firmware commit.

This commit is contained in:
Jared Boone
2015-07-08 08:39:24 -07:00
parent 626e863257
commit dc6fee8370
357 changed files with 83134 additions and 0 deletions
+138
View File
@@ -0,0 +1,138 @@
/*
* 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;
};
class ADC {
public:
constexpr ADC(
LPC_ADCx_Type* adcp
) : adcp(adcp)
{
}
void power_up(const Config config) const {
adcp->CR = config.cr;
}
void clock_enable() const {
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;
}
}
void clock_disable() const {
if( adcp == LPC_ADC0 ) {
LPC_CCU1->CLK_APB3_ADC0_CFG.RUN = 0;
}
if( adcp == LPC_ADC1 ) {
LPC_CCU1->CLK_APB3_ADC1_CFG.RUN = 0;
}
}
void disable() const {
adcp->INTEN = 0;
adcp->CR = 0;
clock_disable();
}
void interrupts_disable() const {
adcp->INTEN = 0;
}
void interrupts_enable(const uint32_t mask) const {
adcp->INTEN = mask;
}
void start_burst() const {
adcp->CR |= (1U << 16);
}
void start_once() const {
adcp->CR |= (1U << 24);
}
void start_once(size_t n) const {
uint32_t cr = adcp->CR;
cr &= ~(0xffU);
cr |= (1 << 24) | (1 << n);
adcp->CR = cr;
}
void stop_burst() const {
adcp->CR &= ~(1U << 16);
}
uint32_t convert(size_t n) const {
start_once(n);
while(true) {
const uint32_t data = adcp->DR[n];
if( (data >> 31) & 1 ) {
return (data >> 6) & 0x3ff;
}
}
}
private:
LPC_ADCx_Type* const adcp;
};
} /* namespace adc */
} /* namespace lpc43xx */
#endif/*__ADC_H__*/
+26
View File
@@ -0,0 +1,26 @@
/*
* 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 "audio.hpp"
namespace audio {
} /* namespace audio */
+108
View File
@@ -0,0 +1,108 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __AUDIO_H__
#define __AUDIO_H__
#include "buffer.hpp"
#include "i2s.hpp"
using namespace lpc43xx;
namespace audio {
struct sample_t {
union {
struct {
int16_t left;
int16_t right;
};
uint32_t raw;
};
};
using buffer_t = buffer_t<sample_t>;
constexpr i2s::ConfigTX i2s0_config_tx {
.dao = i2s::DAO {
.wordwidth = i2s::WordWidth::Bits16,
.mono = 0,
.stop = 1,
.reset = 0,
.ws_sel = 0,
.ws_halfperiod = 0x0f,
.mute = 1,
},
.txrate = i2s::MCLKRate {
.x_divider = 0,
.y_divider = 0,
},
.txbitrate = i2s::BitRate {
.bitrate = 7,
},
.txmode = i2s::Mode {
.clksel = i2s::ClockSelect::BaseAudioClkOrExternalMCLK,
.four_pin = 0,
.mclk_out_en = 1,
},
};
constexpr i2s::ConfigRX i2s0_config_rx {
.dai = i2s::DAI {
.wordwidth = i2s::WordWidth::Bits16,
.mono = 0,
.stop = 1,
.reset = 0,
.ws_sel = 1,
.ws_halfperiod = 0x0f,
},
.rxrate = i2s::MCLKRate {
.x_divider = 0,
.y_divider = 0,
},
.rxbitrate = i2s::BitRate {
.bitrate = 7,
},
.rxmode = i2s::Mode {
.clksel = i2s::ClockSelect::BaseAudioClkOrExternalMCLK,
.four_pin = 1,
.mclk_out_en = 0,
},
};
constexpr i2s::ConfigDMA i2s0_config_dma {
.dma1 = i2s::DMA {
.rx_enable = 1,
.tx_enable = 0,
.rx_depth = 4,
.tx_depth = 0,
},
.dma2 = i2s::DMA {
.rx_enable = 0,
.tx_enable = 1,
.rx_depth = 0,
.tx_depth = 4,
},
};
} /* namespace audio */
#endif/*__AUDIO_H__*/
+42
View File
@@ -0,0 +1,42 @@
/*
* 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,
};
buffer_t wait_for_rx_buffer();
} /* namespace baseband */
#endif/*__BASEBAND_H__*/
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __BUFFER_H__
#define __BUFFER_H__
#include <cstdint>
#include <cstddef>
template<typename T>
struct buffer_t {
T* const p;
const size_t count;
const uint32_t sampling_rate;
constexpr buffer_t(
T* const p,
const size_t count
) : p { p },
count { count },
sampling_rate { 0 }
{
};
constexpr buffer_t(
T* const p,
const size_t count,
const uint32_t sampling_rate
) : p { p },
count { count },
sampling_rate { sampling_rate }
{
};
};
#endif/*__BUFFER_H__*/
+143
View File
@@ -0,0 +1,143 @@
/*
* 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>
#include <hal.h>
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 {
int8_t _v[2];
uint16_t _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; }
constexpr uint32_t __rep() const {
return _rep;
}
private:
union {
int16_t _v[2];
uint32_t _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");
#if defined(LPC43XX_M4)
static inline complex32_t multiply_conjugate_s16_s32(const complex16_t::rep_type a, const complex16_t::rep_type b) {
// conjugate: conj(a + bj) = a - bj
// multiply: (a + bj) * (c + dj) = (ac - bd) + (bc + ad)j
// conjugate-multiply: (ac + bd) + (bc - ad)j
//return { a.real() * b.real() + a.imag() * b.imag(), a.imag() * b.real() - a.real() * b.imag() };
const int32_t rr = __SMULBB(a, b);
const int32_t ii = __SMULTT(a, b);
const int32_t r = __QADD(rr, ii);
const int32_t ir = __SMULTB(a, b);
const int32_t ri = __SMULBT(a, b);
const int32_t i = __QSUB(ir, ri);
return { r, i };
}
#endif
#endif/*__COMPLEX_H__*/
+229
View File
@@ -0,0 +1,229 @@
/*
* 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 {
/* Enter ISP:
* Ensures that the I/O pins transition smoothly from user mode to ISP
* mode.
*/
void CPLD::enter_isp() {
/* Enter ISP */
shift_ir(0x2cc); //(199);
jtag.runtest_tck(18003); // 1ms
}
void CPLD::exit_isp() {
/* Exit ISP? Reset? */
shift_ir(0x201); //166);
jtag.runtest_tck(18003); // 1ms
shift_ir(0x3FF);
jtag.runtest_tck(18000); // 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(0x2F4); // 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;
}
void CPLD::sector_select(const uint16_t id) {
shift_ir(0x203); // Sector select
jtag.runtest_tck(93); // 5us
jtag.shift_dr(13, id); // Sector ID
}
bool CPLD::idcode_ok() {
shift_ir(Instruction::IDCODE);
const auto idcode = jtag.shift_dr(32, 0);
return (idcode == IDCODE);
}
std::array<uint16_t, 5> CPLD::read_silicon_id() {
sector_select(0x0089);
shift_ir(0x205);
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)
);
}
void CPLD::erase_sector(const uint16_t id) {
sector_select(id);
shift_ir(0x2F2); // Erase pulse
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(0x2F4); // 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(0x205); // 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( (id == 0) && (i == 0) ) {
// Account for bit that indicates bitstream is valid.
if( (from_device & 0xfbff) != (data[i] & 0xfbff) ) {
success = false;
}
} else {
if( from_device != data[i] ) {
success = false;
}
}
}
return success;
}
bool CPLD::is_blank_block(const uint16_t id, const size_t count) {
sector_select(id);
shift_ir(0x205); // Read
jtag.runtest_tck(93); // 5us
bool success = true;
for(size_t i=0; i<count; i++) {
const auto from_device = jtag.shift_dr(16, 0xffff);
if( from_device != 0xffff ) {
success = false;
}
}
return success;
}
bool 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 */
+167
View File
@@ -0,0 +1,167 @@
/*
* 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 <cstdint>
#include <cstddef>
#include <array>
#include <bitset>
namespace cpld {
namespace max5 {
class CPLD {
public:
constexpr CPLD(
jtag::JTAG& jtag
) : jtag(jtag)
{
}
void reset() {
jtag.reset();
}
void run_test_idle() {
jtag.run_test_idle();
}
bool idcode_ok();
void enter_isp();
/* 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();
void exit_isp(); // I think that's what the code does...
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();
std::pair<bool, uint8_t> boundary_scan();
enum class Instruction {
BYPASS = 0b1111111111,
EXTEST = 0b0000001111,
SAMPLE = 0b0000000101,
IDCODE = 0b0000000110,
USERCODE = 0b0000000111,
CLAMP = 0b0000001010,
HIGHZ = 0b0000001011
};
void shift_ir(const Instruction instruction) {
shift_ir(static_cast<uint32_t>(instruction));
}
template<size_t N>
void shift_dr(std::bitset<N>& bits) {
jtag.shift_dr(bits);
}
private:
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);
const uint32_t IDCODE = 0b00000010000010100101000011011101;
const size_t IR_LENGTH = 10;
void shift_ir(const uint32_t value) {
jtag.shift_ir(IR_LENGTH, value);
}
};
/*
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__*/
+133
View File
@@ -0,0 +1,133 @@
/*
* 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 "cpu_clock.hpp"
#include <ch.h>
#include <hal.h>
#include "lpc43xx_cpp.hpp"
using namespace lpc43xx;
constexpr uint32_t systick_count(const uint32_t clock_source_f) {
return clock_source_f / CH_FREQUENCY;
}
constexpr uint32_t systick_load(const uint32_t clock_source_f) {
return systick_count(clock_source_f) - 1;
}
constexpr auto systick_count_irc = systick_load(clock_source_irc_f);
constexpr auto systick_count_pll1 = systick_load(clock_source_pll1_f);
constexpr auto systick_count_pll1_step = systick_load(clock_source_pll1_step_f);
static void set_clock(LPC_CGU_BASE_CLK_Type& clk, const cgu::CLK_SEL clock_source) {
clk.AUTOBLOCK = 1;
clk.CLK_SEL = toUType(clock_source);
}
void cpu_clock_irc() {
/* Set M4 clock to safe default speed (~12MHz IRC) */
set_clock(LPC_CGU->BASE_M4_CLK, cgu::CLK_SEL::IRC);
systick_adjust_period(systick_count_irc);
halLPCSetSystemClock(clock_source_irc_f);
}
void cpu_xtal_start() {
LPC_CGU->XTAL_OSC_CTRL.BYPASS = 0;
LPC_CGU->XTAL_OSC_CTRL.HF = 0;
LPC_CGU->XTAL_OSC_CTRL.ENABLE = 0;
halPolledDelay(US2RTT(250));
}
void cpu_clock_max_speed() {
/* Incantation from LPC43xx UM10503 section 12.2.1.1, to bring the M4
* core clock speed to the 110 - 204MHz range.
*/
cpu_clock_irc();
cpu_xtal_start();
/* Step into the 90-110MHz M4 clock range */
cgu::pll1::ctrl({
.pd = 0,
.bypass = 0,
.fbsel = 0,
.direct = 0,
.psel = 0,
.autoblock = 1,
.nsel = 0,
.msel = 16,
.clk_sel = cgu::CLK_SEL::XTAL,
});
while( !cgu::pll1::is_locked() );
/* Switch M4 clock to PLL1 running at intermediate rate */
set_clock(LPC_CGU->BASE_M4_CLK, cgu::CLK_SEL::PLL1);
systick_adjust_period(systick_count_pll1_step);
halLPCSetSystemClock(clock_source_pll1_step_f);
/* Delay >50us at 90-110MHz clock speed */
halPolledDelay(US2RTT(50));
/* Remove /2P divider from PLL1 output to achieve full speed */
cgu::pll1::direct();
systick_adjust_period(systick_count_pll1);
halLPCSetSystemClock(clock_source_pll1_f);
}
void cpu_start_audio_pll() {
cgu::pll0audio::ctrl({
.pd = 1,
.bypass = 0,
.directi = 0,
.directo = 0,
.clken = 0,
.frm = 0,
.autoblock = 1,
.pllfract_req = 1,
.sel_ext = 0,
.mod_pd = 0,
.clk_sel = cgu::CLK_SEL::XTAL,
});
/* For 12MHz clock source, 48kHz audio rate, 256Fs MCLK:
* Fout=12.288MHz, Fcco=417.792MHz
* PDEC=3, NDEC=1, PLLFRACT=0x1a1cac
*/
cgu::pll0audio::mdiv({
.mdec = 0x5B6A,
});
cgu::pll0audio::np_div({
.pdec = 3,
.ndec = 1,
});
cgu::pll0audio::frac({
.pllfract_ctrl = 0x1a1cac,
});
cgu::pll0audio::power_up();
while( !cgu::pll0audio::is_locked() );
cgu::pll0audio::clock_enable();
set_clock(LPC_CGU->BASE_AUDIO_CLK, cgu::CLK_SEL::PLL0AUDIO);
}
+35
View File
@@ -0,0 +1,35 @@
/*
* 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 __CPU_CLOCK_H__
#define __CPU_CLOCK_H__
#include <cstdint>
constexpr uint32_t clock_source_irc_f = 12000000;
constexpr uint32_t clock_source_gp_clkin = 20000000;
constexpr uint32_t clock_source_pll1_step_f = 100000000;
constexpr uint32_t clock_source_pll1_f = 200000000;
void cpu_clock_max_speed();
void cpu_start_audio_pll();
#endif/*__CPU_CLOCK_H__*/
+72
View File
@@ -0,0 +1,72 @@
/*
* 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>
static void runtime_error() {
debug_indicate_error_init();
while(true) {
volatile size_t n = 1000000U;
while(n--);
debug_indicate_error_update();
}
}
extern "C" {
void __early_init(void) {
/* Enable unaligned exception handler */
SCB_CCR |= (1 << 3);
#if defined(LPC43XX_M4)
/* Enable MemManage, BusFault, UsageFault exception handlers */
SCB_SHCSR |= (1 << 16);
SCB_SHCSR |= (1 << 17);
SCB_SHCSR |= (1 << 18);
#endif
}
void port_halt(void) {
port_disable();
runtime_error();
}
#if defined(LPC43XX_M4)
CH_IRQ_HANDLER(MemManageVector) {
CH_IRQ_PROLOGUE();
chSysHalt();
}
CH_IRQ_HANDLER(BusFaultVector) {
CH_IRQ_PROLOGUE();
chSysHalt();
}
CH_IRQ_HANDLER(UsageFaultVector) {
CH_IRQ_PROLOGUE();
chSysHalt();
}
#endif
}
+29
View File
@@ -0,0 +1,29 @@
/*
* 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__
// Defined by application to indicate error in board/hardware-specific manner.
void debug_indicate_error_init();
void debug_indicate_error_update();
#endif/*__DEBUG_H__*/
+22
View File
@@ -0,0 +1,22 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "dsp_fft.hpp"
+109
View File
@@ -0,0 +1,109 @@
/*
* 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 "complex.hpp"
#include "hal.h"
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 */
constexpr bool power_of_two(const size_t n) {
return (n & (n - 1)) == 0;
}
constexpr size_t log_2(const size_t n, const size_t p = 0) {
return (n <= 1) ? p : log_2(n / 2, p + 1);
}
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_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; 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) {
static_assert(power_of_two(N), "only defined for N == power of two");
/* Provide data to this function, pre-swapped. */
for(size_t mmax = 1; N > mmax; mmax <<= 1) {
const float theta = -pi / mmax;
const float wtemp = std::sin(0.5f * theta);
const T wp {
-2.0f * wtemp * wtemp,
std::sin(theta)
};
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__*/
+34
View File
@@ -0,0 +1,34 @@
/*
* 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>;
#endif/*__DSP_TYPES_H__*/
+204
View File
@@ -0,0 +1,204 @@
/*
* 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 <algorithm>
#include <cstring>
/* FIFO implementation inspired by Linux kfifo. */
template<typename T, size_t K>
class FIFO {
public:
constexpr FIFO(
) : _in { 0 },
_out { 0 }
{
}
void reset() {
_in = _out = 0;
}
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 len() > mask();
}
/*
bool in(const T& val) {
const bool is_not_full = !is_full();
if( is_not_full ) {
_data[_in & mask()] = val;
smp_wmb();
_in++;
}
return is_not_full;
}
*/
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()];
smp_wmb();
_out += 1;
return true;
}
*/
size_t out(T* const buf, size_t len) {
len = out_peek(buf, len);
_out += len;
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:
static constexpr size_t size() {
return (1UL << K);
}
static constexpr size_t esize() {
return sizeof(T);
}
static constexpr size_t mask() {
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 _data[size()];
size_t _in;
size_t _out;
};
#endif/*__FIFO_H__*/
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "gcc.hpp"
#include <ch.h>
#if defined(TOOLCHAIN_GCC)
/* Note: Added to deal with static variables:
* undefined reference to `__dso_handle'.
* Comes up when using random C++ features, e.g. lambdas or std::function?
*/
void *__dso_handle;
/* prevents the exception handling name demangling code getting pulled in */
namespace __gnu_cxx {
void __verbose_terminate_handler() {
}
}
/* NOTE: Hack to address bloat when using C++ class virtual destructors.
*/
extern "C" __attribute__((weak)) void __cxa_pure_virtual(void) {
chSysHalt();
}
#endif
/* Implementing abort() eliminates requirement for _getpid(), _kill(),
* _exit().
*/
extern "C" void abort() {
/* while() loop to avoid noreturn-is-returning warning. */
while(1) { chSysHalt(); }
}
+25
View File
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GCC_H__
#define __GCC_H__
#endif/*__GCC_H__*/
+114
View File
@@ -0,0 +1,114 @@
/*
* 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_force();
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" {
LOCATE_IN_RAM
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 */
+363
View File
@@ -0,0 +1,363 @@
/*
* 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_force() 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 },
} };
class Controller {
public:
void enable() const {
LPC_GPDMA->CONFIG |= (1U << 0);
}
void disable() const {
for(const auto& channel : channels) {
channel.disable_force();
}
LPC_GPDMA->CONFIG &= ~(1U << 0);
}
};
constexpr Controller controller;
} /* namespace gpdma */
} /* namespace lpc43xx */
#endif/*__GPDMA_H__*/
+306
View File
@@ -0,0 +1,306 @@
/*
* 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 : 3;
const uint32_t pd : 1;
const uint32_t pu : 1;
const uint32_t fast : 1;
const uint32_t input : 1;
const uint32_t ifilt : 1;
constexpr operator uint16_t() {
return
((~ifilt) << 7)
| (input << 6)
| (fast << 5)
| ((~pu) << 4)
| (pd << 3)
| (mode << 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 };
}
};
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] & ~(7U << 0)) | 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__*/
+90
View File
@@ -0,0 +1,90 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __HACKRF_GPIO_H__
#define __HACKRF_GPIO_H__
#include "pins.hpp"
#include "led.hpp"
#include <array>
using namespace lpc43xx;
namespace hackrf {
namespace one {
/* GPIO */
constexpr GPIO gpio_led_usb = gpio[GPIO2_1];
constexpr GPIO gpio_led_rx = gpio[GPIO2_2];
constexpr GPIO gpio_led_tx = gpio[GPIO2_8];
constexpr GPIO gpio_1v8_enable = gpio[GPIO3_6];
constexpr GPIO gpio_vregmode = gpio[GPIO3_7];
constexpr GPIO gpio_vaa_disable = gpio[GPIO2_9];
constexpr GPIO gpio_rx_mix_bp = gpio[GPIO2_12];
constexpr GPIO gpio_tx_mix_bp = gpio[GPIO2_11];
constexpr GPIO gpio_mix_bypass = gpio[GPIO5_16];
constexpr GPIO gpio_not_mix_bypass = gpio[GPIO1_0];
constexpr GPIO gpio_rx = gpio[GPIO5_5];
constexpr GPIO gpio_tx = gpio[GPIO5_15];
constexpr GPIO gpio_lp = gpio[GPIO2_10];
constexpr GPIO gpio_hp = gpio[GPIO2_0];
constexpr GPIO gpio_rx_amp = gpio[GPIO1_11];
constexpr GPIO gpio_tx_amp = gpio[GPIO2_15];
constexpr GPIO gpio_amp_bypass = gpio[GPIO0_14];
constexpr GPIO gpio_not_rx_amp_pwr = gpio[GPIO1_12];
constexpr GPIO gpio_not_tx_amp_pwr = gpio[GPIO3_5];
constexpr GPIO gpio_rffc5072_resetx = gpio[GPIO2_14];
constexpr GPIO gpio_rffc5072_select = gpio[GPIO2_13];
constexpr GPIO gpio_rffc5072_clock = gpio[GPIO5_6];
constexpr GPIO gpio_rffc5072_data = gpio[GPIO3_3];
constexpr GPIO gpio_max2837_select = gpio[GPIO0_15];
constexpr GPIO gpio_max2837_enable = gpio[GPIO2_6];
constexpr GPIO gpio_max2837_rxenable = gpio[GPIO2_5];
constexpr GPIO gpio_max2837_txenable = gpio[GPIO2_4];
constexpr GPIO gpio_max5864_select = gpio[GPIO2_7];
constexpr std::array<GPIO, 3> gpios_baseband_decimation {
gpio[GPIO5_12],
gpio[GPIO5_13],
gpio[GPIO5_14]
};
constexpr GPIO gpio_baseband_q_invert = gpio[GPIO0_13];
/* 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__*/
+82
View File
@@ -0,0 +1,82 @@
/*
* 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 {
void reset() {
/* "The reset delay is counted in IRC clock cycles. If the core frequency
* CCLK is much higher than the IRC frequency, add a software delay of
* fCCLK/fIRC clock cycles between resetting and accessing any of the
* peripheral blocks."
*/
rgu::reset_mask(
/* Don't reset SCU, may trip up SPIFI pins if running from SPIFI
* memory.
*/
/*rgu::Reset::SCU */
rgu::Reset::LCD
| rgu::Reset::USB0
| rgu::Reset::USB1
| rgu::Reset::DMA
| rgu::Reset::SDIO
| rgu::Reset::EMC
| rgu::Reset::ETHERNET
| rgu::Reset::GPIO
| rgu::Reset::TIMER0
| rgu::Reset::TIMER1
| rgu::Reset::TIMER2
| rgu::Reset::TIMER3
| rgu::Reset::RITIMER
| rgu::Reset::SCT
| rgu::Reset::MOTOCONPWM
| rgu::Reset::QEI
| rgu::Reset::ADC0
| rgu::Reset::ADC1
| rgu::Reset::DAC
| rgu::Reset::UART0
| rgu::Reset::UART1
| rgu::Reset::UART2
| rgu::Reset::UART3
| rgu::Reset::I2C0
| rgu::Reset::I2C1
| rgu::Reset::SSP0
| rgu::Reset::SSP1
| rgu::Reset::I2S
/* Don't reset SPIFI if running from SPIFI memory */
/*| rgu::Reset::SPIFI*/
| rgu::Reset::CAN1
| rgu::Reset::CAN0
/* Don't reset M0 if that's the core we're running on! */
/*| rgu::Reset::M0APP */
| rgu::Reset::SGPIO
| rgu::Reset::SPI
);
}
} /* namespace one */
} /* namespace hackrf */
+81
View File
@@ -0,0 +1,81 @@
/*
* 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 = 50000000U;
constexpr ClockFrequency max2837_reference_f = 50000000U;
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 */
constexpr adc::ADC adc0 { LPC_ADC0 };
/* ADC1 */
constexpr adc::ADC adc1 { LPC_ADC1 };
void reset();
} /* namespace one */
} /* namespace hackrf */
#endif/*__HACKRF_HAL_H__*/
+65
View File
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "i2c_pp.hpp"
void I2C::start(const I2CConfig& config) {
i2cStart(_driver, &config);
}
void I2C::stop() {
i2cStop(_driver);
}
bool I2C::transfer(
const address_t slave_address,
const uint8_t* const data_tx, const size_t count_tx,
uint8_t* const data_rx, const size_t count_rx,
systime_t timeout
) {
i2cAcquireBus(_driver);
const msg_t status = i2cMasterTransmitTimeout(
_driver, slave_address, data_tx, count_tx, data_rx, count_rx, timeout
);
i2cReleaseBus(_driver);
return (status == RDY_OK);
}
bool I2C::receive(
const address_t slave_address,
uint8_t* const data, const size_t count,
systime_t timeout
) {
i2cAcquireBus(_driver);
const msg_t status = i2cMasterReceiveTimeout(
_driver, slave_address, data, count, timeout
);
i2cReleaseBus(_driver);
return (status == RDY_OK);
}
bool I2C::transmit(
const address_t slave_address,
const uint8_t* const data, const size_t count,
systime_t timeout
) {
return transfer(slave_address, data, count, NULL, 0, timeout);
}
+96
View File
@@ -0,0 +1,96 @@
/*
* 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;
constexpr I2CClockConfig(
float clock_source_f,
float bus_f,
float high_period_ns
) : clock_source_f(clock_source_f),
bus_f(bus_f),
high_period_ns(high_period_ns)
{
}
static constexpr float period_ns(const float f) {
return 1e9 / f;
}
constexpr uint32_t i2c_period_count() {
return period_ns(bus_f) / period_ns(clock_source_f) + 0.5f;
}
constexpr uint32_t i2c_high_count() {
return high_period_ns / period_ns(clock_source_f) + 0.5f;
}
constexpr uint32_t i2c_low_count() {
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__*/
+242
View File
@@ -0,0 +1,242 @@
/*
* 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;
};
struct ConfigRX {
uint32_t dai;
uint32_t rxrate;
uint32_t rxbitrate;
uint32_t rxmode;
};
struct ConfigDMA {
uint32_t dma1;
uint32_t dma2;
};
template<uint32_t BaseAddress>
class I2S {
public:
static constexpr LPC_I2S_Type* Peripheral = reinterpret_cast<LPC_I2S_Type*>(BaseAddress);
static void configure(
const ConfigTX& config_tx,
const ConfigRX& config_rx
) {
reset();
/* I2S operates in master mode, use PLL0AUDIO as MCLK source for TX. */
/* NOTE: Documentation of CREG6 is quite confusing. Refer to "I2S clocking and
* pin connections" and other I2S diagrams for more clarity.
*/
if( Peripheral == LPC_I2S0 ) {
LPC_CREG->CREG6 |=
(1U << 12)
| (1U << 13)
;
}
if( Peripheral == LPC_I2S1 ) {
LPC_CREG->CREG6 |=
(1U << 14)
| (1U << 15)
;
}
Peripheral->DAO = config_tx.dao;
Peripheral->TXRATE = config_tx.txrate;
Peripheral->TXBITRATE = config_tx.txbitrate;
Peripheral->TXMODE = config_tx.txmode;
Peripheral->DAI = config_rx.dai;
Peripheral->RXRATE = config_rx.rxrate;
Peripheral->RXBITRATE = config_rx.rxbitrate;
Peripheral->RXMODE = config_rx.rxmode;
}
static void configure(
const ConfigTX& config_tx,
const ConfigRX& config_rx,
const ConfigDMA& config_dma
) {
configure(config_tx, config_rx);
Peripheral->DMA1 = config_dma.dma1;
Peripheral->DMA2 = config_dma.dma2;
}
static void rx_start() {
Peripheral->DAI &= ~(1U << 3);
}
static void rx_stop() {
Peripheral->DAI |= (1U << 3);
}
static void tx_start() {
Peripheral->DAO &= ~(1U << 3);
}
static void tx_stop() {
Peripheral->DAO |= (1U << 3);
}
static void tx_mute() {
Peripheral->DAO |= (1U << 15);
}
static void tx_unmute() {
Peripheral->DAO &= ~(1U << 15);
}
private:
static void reset() {
Peripheral->DAO |= (1U << 4);
Peripheral->DAI |= (1U << 4);
}
};
using i2s0 = I2S<LPC_I2S0_BASE>;
using i2s1 = I2S<LPC_I2S1_BASE>;
} /* namespace i2s */
} /* namespace lpc43xx */
#endif/*__I2S_H__*/
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "jtag.hpp"
#include <cstdint>
#include <cstddef>
namespace jtag {
uint32_t JTAG::shift(const size_t count, uint32_t value) {
for(size_t i=0; i<count; i++) {
const auto tdo = target.clock(
(i == (count - 1)) ? 1 : 0,
value & 1
);
value >>= 1;
value |= tdo << (count - 1);
}
return value;
}
} /* namespace jtag */
+134
View File
@@ -0,0 +1,134 @@
/*
* 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 <cstdint>
#include <cstddef>
#include <bitset>
namespace jtag {
class Target {
public:
using bit_t = uint_fast8_t;
virtual ~Target() {
}
virtual void delay(const size_t n) = 0;
virtual jtag::Target::bit_t clock(
const jtag::Target::bit_t tms_value,
const jtag::Target::bit_t tdi_value
) = 0;
};
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;
}
template<size_t N>
void shift_dr(std::bitset<N>& bits) {
/* Run-Test/Idle -> Select-DR-Scan */
target.clock(1, 0);
/* Scan -> Capture -> Shift */
target.clock(0, 0);
target.clock(0, 0);
for(size_t i=0; i<bits.size(); i++) {
bits[i] = target.clock(
(i == (bits.size() - 1)) ? 1 : 0,
bits[i]
);
}
/* Exit1 -> Update */
target.clock(1, 0);
/* Update -> Run-Test/Idle */
target.clock(0, 0);
}
private:
Target& target;
uint32_t shift(const size_t count, uint32_t value);
};
} /* namespace jtag */
#endif/*__JTAG_H__*/
+140
View File
@@ -0,0 +1,140 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __JTAG_TARGET_GPIO_H__
#define __JTAG_TARGET_GPIO_H__
#include "jtag.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__*/
+328
View File
@@ -0,0 +1,328 @@
/*
* 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 "lcd_ili9341.hpp"
#include "portapack_io.hpp"
using namespace portapack;
#include "utility.hpp"
#include "ch.h"
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_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
});
// Exit Sleep
io.lcd_data_write_command_and_data(0x11, {});
chThdSleepMilliseconds(120);
// Display on
io.lcd_data_write_command_and_data(0x29, {});
// 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_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.w - 1);
lcd_paset(p.y, p.y + s.h - 1);
lcd_ramwr_start();
}
void lcd_start_ram_write(
const ui::Rect& r
) {
lcd_start_ram_write(r.pos, 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();
io.lcd_backlight(1);
}
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.size.w * r_clipped.size.h;
io.lcd_write_pixels(c, count);
}
}
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({
static_cast<ui::Coord>(x + center.x),
static_cast<ui::Coord>(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.pos, r.size);
io.lcd_write_pixels(colors, count);
}
void ILI9341::draw_glyph(
const ui::Point p,
const ui::Glyph& glyph,
const ui::Color foreground,
const ui::Color background
) {
lcd_start_ram_write(p, glyph.size());
const size_t count = glyph.w() * glyph.h();
const auto pixels = glyph.pixels();
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::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 */
+96
View File
@@ -0,0 +1,96 @@
/*
* 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 __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, 320, 0 }
{
}
ILI9341(const ILI9341&) = delete;
ILI9341(ILI9341&&) = delete;
void operator=(const ILI9341&) = delete;
void init();
void fill_rectangle(ui::Rect r, const ui::Color c);
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);
template<size_t N>
void draw_pixels(
const ui::Rect r,
const std::array<ui::Color, N>& colors
) {
draw_pixels(r, colors.data(), colors.size());
}
void draw_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 {
uint16_t top_area;
uint16_t bottom_area;
uint16_t height;
uint16_t current_position;
};
scroll_t scroll_state;
void draw_pixels(const ui::Rect r, const ui::Color* const colors, const size_t count);
};
} /* namespace lcd */
#endif/*__LCD_ILI9341_H__*/
+58
View File
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __LED_H__
#define __LED_H__
#include "gpio.hpp"
struct LED {
constexpr LED(const GPIO gpio) :
_gpio { gpio } {
}
void setup() const {
_gpio.clear();
_gpio.output();
_gpio.configure();
}
void on() const {
_gpio.set();
}
void off() const {
_gpio.clear();
}
void toggle() const {
_gpio.toggle();
}
void write(const bool value) const {
_gpio.write(value);
}
private:
const GPIO _gpio;
};
#endif/*__LED_H__*/
+531
View File
@@ -0,0 +1,531 @@
/*
* 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 {
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_M4)
inline void assert() {
__SEV();
}
#endif
inline void clear() {
LPC_CREG->M4TXEVENT = 0;
}
} /* namespace m4txevent */
namespace m0apptxevent {
#if defined(LPC43XX_M0)
inline void assert() {
__SEV();
}
#endif
inline void clear() {
LPC_CREG->M0APPTXEVENT = 0;
}
} /* namespace */
} /* namespace creg */
namespace cgu {
enum class CLK_SEL {
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 & 3) << 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__*/
+260
View File
@@ -0,0 +1,260 @@
/*
* 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_H__
#define __MESSAGE_H__
#include <cstdint>
#include <cstddef>
#include <array>
#include <functional>
#include "utility.hpp"
class Message {
public:
enum class ID : uint16_t {
/* Assign consecutive IDs. IDs are used to index array. */
RSSIStatistics = 0,
BasebandStatistics = 1,
ChannelStatistics = 2,
ChannelSpectrum = 3,
AudioStatistics = 4,
BasebandConfiguration = 5,
FSKConfiguration = 6,
FSKPacket = 7,
TestResults = 8,
MAX
};
constexpr Message(
ID id
) : id { id },
state { State::Free }
{
}
enum class State : uint16_t {
Free,
InUse,
};
bool is_free() const {
return state == State::Free;
}
const ID id;
volatile State state;
};
struct RSSIStatistics {
uint32_t accumulator { 0 };
uint32_t min { 0 };
uint32_t max { 0 };
uint32_t count { 0 };
};
class RSSIStatisticsMessage : public Message {
public:
constexpr RSSIStatisticsMessage(
) : Message { ID::RSSIStatistics },
statistics { }
{
}
RSSIStatistics statistics;
};
struct BasebandStatistics {
uint32_t idle_ticks { 0 };
uint32_t baseband_ticks { 0 };
bool saturation { false };
};
class BasebandStatisticsMessage : public Message {
public:
constexpr BasebandStatisticsMessage(
) : Message { ID::BasebandStatistics },
statistics { }
{
}
BasebandStatistics statistics;
};
struct ChannelStatistics {
int32_t max_db;
size_t count;
constexpr ChannelStatistics(
) : max_db { -120 },
count { 0 }
{
}
constexpr ChannelStatistics(
int32_t max_db,
size_t count
) : max_db { max_db },
count { count }
{
}
};
class ChannelStatisticsMessage : public Message {
public:
constexpr ChannelStatisticsMessage(
) : Message { ID::ChannelStatistics },
statistics { }
{
}
ChannelStatistics statistics;
};
struct AudioStatistics {
int32_t rms_db;
int32_t max_db;
size_t count;
constexpr AudioStatistics(
) : rms_db { -120 },
max_db { -120 },
count { 0 }
{
}
constexpr AudioStatistics(
int32_t rms_db,
int32_t max_db,
size_t count
) : rms_db { rms_db },
max_db { max_db },
count { count }
{
}
};
class AudioStatisticsMessage : public Message {
public:
constexpr AudioStatisticsMessage(
) : Message { ID::AudioStatistics },
statistics { }
{
}
AudioStatistics statistics;
};
struct BasebandConfiguration {
int32_t mode;
uint32_t sampling_rate;
size_t decimation_factor;
};
class BasebandConfigurationMessage : public Message {
public:
constexpr BasebandConfigurationMessage(
BasebandConfiguration configuration
) : Message { ID::BasebandConfiguration },
configuration(configuration)
{
}
BasebandConfiguration configuration;
};
struct ChannelSpectrum {
std::array<uint8_t, 256>* db { nullptr };
size_t db_count { 256 };
uint32_t bandwidth { 0 };
};
class ChannelSpectrumMessage : public Message {
public:
constexpr ChannelSpectrumMessage(
) : Message { ID::ChannelSpectrum }
{
}
ChannelSpectrum spectrum;
};
struct FSKConfiguration {
uint32_t symbol_rate;
uint32_t access_code;
size_t access_code_length;
size_t access_code_tolerance;
size_t packet_length;
};
class FSKConfigurationMessage : public Message {
public:
constexpr FSKConfigurationMessage(
FSKConfiguration configuration
) : Message { ID::FSKConfiguration },
configuration(configuration)
{
}
FSKConfiguration configuration;
};
#include <bitset>
struct FSKPacket {
std::bitset<256> payload;
size_t bits_received;
FSKPacket(
) : bits_received { 0 }
{
}
};
class FSKPacketMessage : public Message {
public:
FSKPacketMessage(
) : Message { ID::FSKPacket }
{
}
FSKPacket packet;
};
class MessageHandlerMap {
public:
using MessageHandler = std::function<void(const Message* const p)>;
MessageHandler& operator[](Message::ID n) {
return map_[toUType(n)];
}
const MessageHandler& operator[](Message::ID n) const {
return map_[toUType(n)];
}
private:
using MapType = std::array<MessageHandler, toUType(Message::ID::MAX)>;
MapType map_;
};
#endif/*__MESSAGE_H__*/
+82
View File
@@ -0,0 +1,82 @@
/*
* 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 "ch.h"
#include "lpc43xx_cpp.hpp"
using namespace lpc43xx;
bool MessageQueue::push(Message* const message) {
/* Returns true if success:
* - Message not in use.
* - FIFO wasn't full.
*/
if( message->state == Message::State::Free ) {
message->state = Message::State::InUse;
if( enqueue(message) ) {
signal();
return true;
} else {
// Roll back message state.
message->state = Message::State::Free;
}
}
return false;
}
Message* MessageQueue::pop() {
/* TODO: Because of architecture characteristics, the two LSBs of the
* message pointer will always be 0. Other (non-pointer) message types
* could be encoded by setting these two bits to non-zero values.
* One of the bits could also be used as an "ack" flag... In fact, a
* pointer message could be turned into an "ack" message, or something
* like that...
* Might be better though to use formal operating structures in the
* message to do synchronization between processors.
*/
Message* message { nullptr };
const auto success = fifo.out(&message, 1);
return success ? message : nullptr;
}
#if defined(LPC43XX_M0)
bool MessageQueue::enqueue(Message* const message) {
return fifo.in(&message, 1);
}
void MessageQueue::signal() {
creg::m0apptxevent::assert();
}
#endif
#if defined(LPC43XX_M4)
bool MessageQueue::enqueue(Message* const message) {
return fifo.in(&message, 1);
}
void MessageQueue::signal() {
creg::m4txevent::assert();
}
#endif
+51
View File
@@ -0,0 +1,51 @@
/*
* 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"
class MessageQueue {
public:
bool push(Message* const message);
Message* pop();
size_t len() const {
return fifo.len();
}
bool is_empty() const {
return fifo.is_empty();
}
private:
FIFO<Message*, 8> fifo;
bool enqueue(Message* const message);
void signal();
};
#endif/*__MESSAGE_QUEUE_H__*/
+239
View File
@@ -0,0 +1,239 @@
/*
* 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, /*P3_3, P3_4, P3_5, P3_6, P3_7, P3_8,*/
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=1, .ifilt=1 } }, /* P1_1/P74: 10K PU, BOOT0 */
[P1_2] = { 1, 2, { .mode=0, .pd=0, .pu=0, .fast=0, .input=1, .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=1, .input=1, .ifilt=0 } }, /* SD_CMD: PortaPack SD.CMD(IO) */
[P1_7] = { 1, 7, { .mode=0, .pd=1, .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=1, .input=1, .ifilt=0 } }, /* SD_DAT0: PortaPack SD.DAT0(IO) */
[P1_10] = { 1, 10, { .mode=7, .pd=0, .pu=1, .fast=1, .input=1, .ifilt=0 } }, /* SD_DAT1: PortaPack SD.DAT1(IO) */
[P1_11] = { 1, 11, { .mode=7, .pd=0, .pu=1, .fast=1, .input=1, .ifilt=0 } }, /* SD_DAT2: PortaPack SD.DAT2(IO) */
[P1_12] = { 1, 12, { .mode=7, .pd=0, .pu=1, .fast=1, .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_Q_INVERT(I) */
[P1_19] = { 1, 19, { .mode=1, .pd=1, .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=1, .fast=0, .input=0, .ifilt=1 } }, /* CS_XCVR/P53: MAX2837.CS(I) */
[P2_0] = { 2, 0, { .mode=4, .pd=0, .pu=1, .fast=0, .input=1, .ifilt=1 } }, /* U0_TXD: PortaPack P2_0/IO_STBX */
[P2_1] = { 2, 1, { .mode=4, .pd=1, .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/<unused> */
[P2_5] = { 2, 5, { .mode=4, .pd=1, .pu=0, .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=1, .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/LCD_RD */
[P2_9] = { 2, 9, { .mode=0, .pd=0, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* P2_9: 10K PD, BOOT3, PortaPack P2_9/LCD_WR */
[P2_10] = { 2, 10, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* AMP_BYPASS/P50: U14.V2(I), U12.V2(I) */
[P2_11] = { 2, 11, { .mode=0, .pd=1, .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=1, .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=0, .ifilt=1 } }, /* I2S0_TX_SCK: PortaPack I2S0_TX_SCK(I) */
[P3_1] = { 3, 1, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* I2S0_RX_WS: PortaPack I2S0_TX_WS(I) */
[P3_2] = { 3, 2, { .mode=0, .pd=0, .pu=1, .fast=0, .input=0, .ifilt=1 } }, /* I2S0_RX_SDA: PortaPack I2S0_TX_SDA(I) */
//[P3_3] = { 3, 3, { .mode=3, .pd=1, .pu=0, .fast=1, .input=1, .ifilt=0 } }, /* SPIFI_SCK: W25Q80BV.CLK(I), enable input buffer for timing feedback */
//[P3_4] = { 3, 4, { .mode=3, .pd=0, .pu=1, .fast=1, .input=1, .ifilt=0 } }, /* SPIFI_SIO3/P82: W25Q80BV.HOLD(IO) */
//[P3_5] = { 3, 5, { .mode=3, .pd=0, .pu=1, .fast=1, .input=1, .ifilt=0 } }, /* SPIFI_SIO2/P81: W25Q80BV.WP(IO) */
//[P3_6] = { 3, 6, { .mode=3, .pd=0, .pu=1, .fast=1, .input=1, .ifilt=0 } }, /* SPIFI_MISO: W25Q80BV.DO(IO) */
//[P3_7] = { 3, 7, { .mode=3, .pd=0, .pu=1, .fast=1, .input=1, .ifilt=0 } }, /* SPIFI_MOSI: W25Q80BV.DI(IO) */
//[P3_8] = { 3, 8, { .mode=3, .pd=0, .pu=1, .fast=1, .input=0, .ifilt=1 } }, /* SPIFI_CS/P68: W25Q80BV.CS(I) */
[P4_0] = { 4, 0, { .mode=0, .pd=0, .pu=1, .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=1, .pu=0, .fast=0, .input=0, .ifilt=1 } }, /* TXENABLE/P55: MAX2837.TXENABLE(I) */
[P4_5] = { 4, 5, { .mode=0, .pd=1, .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::gpio_out_with_pullup(4) }, /* SGPIO13/BANK2F3M2: CPLD.90/HOST_DECIM_SEL0(I) */
[P4_9] = { 4, 9, PinConfig::gpio_out_with_pullup(4) }, /* SGPIO14/BANK2F3M4: CPLD.81/HOST_DECIM_SEL1(I) */
[P4_10] = { 4, 10, PinConfig::gpio_out_with_pullup(4) }, /* SGPIO15/BANK2F3M6: CPLD.78/HOST_DECIM_SEL2(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=1, .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=1, .fast=0, .input=0, .ifilt=1 } }, /* TX_MIX_BP/P46: U9.V1(I) */
[P5_3] = { 5, 3, { .mode=0, .pd=1, .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=1, .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=1, .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=1, .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=1, .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=1, .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=1, .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=1, .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=1, .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=3, .pd=0, .pu=1, .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=1, .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__*/
+42
View File
@@ -0,0 +1,42 @@
/*
* 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 __PORTAPACK_ADC_H__
#define __PORTAPACK_ADC_H__
#include <cstddef>
namespace portapack {
/* ADC0 */
constexpr size_t adc0_touch_yp_input = 0;
constexpr size_t adc0_touch_yn_input = 2;
constexpr size_t adc0_touch_xp_input = 5;
constexpr size_t adc0_touch_xn_input = 6;
/* ADC1 */
constexpr size_t adc1_rssi_input = 1;
} /* namespace portapack */
#endif/*__PORTAPACK_ADC_H__*/
+519
View File
@@ -0,0 +1,519 @@
/*
* 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 "portapack_cpld_data.hpp"
#include <cstdint>
#include <array>
namespace portapack {
namespace cpld {
/* 2015 Apr 23 19:34 PT */
const std::array<uint16_t, 3328> block_0 { {
0x7fff, 0xffff, 0xbffc, 0xf9e7, 0x79ff, 0xfffe, 0xaf9e, 0x7cff,
0x7fff, 0xfbe7, 0xb3f7, 0xffff, 0x7f3f, 0x7dfb, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbff7, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x67ff, 0xffff, 0xbfff, 0xfefd, 0x7fff, 0xff7f, 0xbfff, 0xe7f9,
0x623f, 0xfff9, 0xb77f, 0xcccf, 0x7fff, 0xb99f, 0xbccc, 0xcffe,
0x6fff, 0xffff, 0xbfff, 0xffeb, 0x77f3, 0xffff, 0xbfe6, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fbf, 0xffff, 0xbfff, 0xfbfe,
0x7fff, 0xffff, 0xbfff, 0xfffe, 0x6fff, 0xffff, 0xbfef, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x6fff, 0xffff, 0xbfff, 0xffdb, 0x7fff, 0xffff, 0xbff7, 0xffff,
0x7eff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7ff5, 0xffff, 0xbffd, 0xffff,
0x6fff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x6fff, 0xffff, 0xbfff, 0xfdbb, 0x77ef, 0xbfff, 0xbfff, 0xffff,
0x7eef, 0xefff, 0xbfff, 0xffff, 0x7dff, 0xffff, 0xbfff, 0xfffe,
0x7bff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbffd, 0xdfff,
0x7dff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffe,
0x7fff, 0xffff, 0xbfff, 0xff7f, 0x77ff, 0xffff, 0xbfff, 0xefff,
0x7dff, 0xefff, 0xbfff, 0xffff, 0x7dff, 0xffff, 0xbfff, 0xfffe,
0x7fff, 0xffff, 0xbfff, 0xfef7, 0x7ff7, 0xbfff, 0xbffd, 0xffff,
0x7ef7, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffe,
0x6fff, 0xffff, 0xbffe, 0xffdf, 0x7fff, 0xffbf, 0xbfff, 0xffff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7eff, 0xffff, 0xbfff, 0xffef,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xfebf, 0xbfff, 0xfeff,
0x7fff, 0xffff, 0xb5fd, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbdff, 0xffbf, 0x7ffe, 0xffff, 0xbfef, 0xff5f,
0x7fff, 0xffff, 0xbfff, 0xffef, 0x7fff, 0xffdf, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7dff, 0xfd7f, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfdf, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7ff7, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xf6ef, 0xbfcb, 0xffff,
0x77ff, 0xffff, 0xbfdf, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7ff7, 0xfdff, 0xbbff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xfbff, 0xbfd5, 0xffff,
0x77ff, 0xffff, 0xa55f, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fdf, 0xdeef, 0xbfff, 0xfdff,
0x7fff, 0xffff, 0xafff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7ffd, 0xffff, 0xbffb, 0xffeb,
0x6bff, 0xffff, 0xb55f, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbdff, 0xdff5,
0x77ff, 0xffff, 0xbabf, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7ffb, 0xf9bf, 0xbafe, 0xefff,
0x6fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7ffe, 0xffde, 0xbfdf, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7ff7, 0xdfff, 0xbffd, 0x35ff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fd2, 0xffff, 0xbfbc, 0xc7ff,
0x7fff, 0xffff, 0xb70f, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xddee, 0xb9ff, 0xbdff,
0x7bff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7ffd, 0xea9f, 0xbefb, 0x7bff,
0x7fff, 0xffff, 0xbeff, 0xffff, 0x7fdf, 0xffff, 0xbfff, 0xffef,
0x7fff, 0xffff, 0xbfff, 0x7fff, 0x7ffd, 0x0ddf, 0xb598, 0x5e74,
0x7fff, 0xffff, 0xb6ff, 0xffff, 0x7fbf, 0xffff, 0xbfff, 0xffdf,
0x7fff, 0xffff, 0xbffe, 0xffff, 0x7ffc, 0x0ddd, 0xbd99, 0x1e6a,
0x7fff, 0xffff, 0xbfaf, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7f08, 0x388f, 0xb89e, 0x887f,
0x7bff, 0xffff, 0xb7f7, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7f0c, 0x388f, 0xb89f, 0x983b,
0x67ff, 0xffff, 0xbfff, 0x3333, 0x63e6, 0x6667, 0xb333, 0x31f3,
0x6666, 0x7ccc, 0xb98f, 0x9999, 0x73e8, 0xc445, 0xb938, 0x88ff,
0x7fff, 0xffff, 0xb7ff, 0x7777, 0x6957, 0x7777, 0xb777, 0x74ab,
0x7777, 0x7ddd, 0xbba5, 0x5ddd, 0x7bcd, 0xdcca, 0xb19d, 0xddfb,
0x7bff, 0xffff, 0xbff7, 0xffff, 0x7fdf, 0xffff, 0xbfff, 0xffef,
0x7fff, 0xffff, 0xbfff, 0x7fff, 0x7fff, 0xe66f, 0xb37f, 0xffde,
0x7fff, 0xffff, 0xbffe, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffd,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7feb, 0xeedf, 0xbfdf, 0xfcff,
0x7fff, 0xffff, 0xbfff, 0xeeee, 0x7ffb, 0xfbbf, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7dfd, 0xffff, 0xbffd, 0xdfff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffd,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7ffa, 0xefdf, 0xbfff, 0xdfff,
0x7fff, 0xffff, 0xbbfe, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fef, 0xfeff, 0xbfdd, 0xfd7a,
0x77ff, 0xffff, 0xbebe, 0xfff7, 0x7fff, 0xfb7f, 0xbf9f, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfef, 0xfffb,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbaff, 0xfffd,
0x7fff, 0xedff, 0xbfff, 0xffde, 0x7ffb, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xb7fd, 0xfff7, 0x7fff, 0xfdfb, 0xb7ff, 0xffff,
0x7fff, 0xfdff, 0xbfff, 0xffff, 0x7ffe, 0xffff, 0xbff3, 0xbbf7,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xff7f, 0xbeaf, 0xfffe,
0x7fff, 0xffff, 0xbfff, 0xffbe, 0x7ffb, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfee, 0xf7f7, 0x7fff, 0xfbef, 0xbfff, 0xffff,
0x7fff, 0xfbfe, 0xbdff, 0xfadf, 0x7dff, 0xffff, 0xbfff, 0xffdf,
0x7fff, 0xffff, 0xb7ff, 0x6fff, 0x77ff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xfff7, 0xafff, 0xbfef, 0x7fff, 0xffff, 0xbfff, 0xfffb,
0x7fff, 0xffff, 0xbffd, 0xdfff, 0x7ff7, 0xfdff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffd7, 0x7eff, 0xffff, 0xbfff, 0xffdf,
0x7fff, 0xffff, 0xbbdf, 0xbbf7, 0x7fff, 0xffef, 0xbfff, 0xffff,
0x7fff, 0xfbf9, 0xb5ff, 0xfcff, 0x7fff, 0xffff, 0xbfff, 0xfffb,
0x7fff, 0xffff, 0xbeff, 0xff77, 0x7fff, 0xf7fd, 0xbfff, 0xffff,
0x7fff, 0xfeee, 0xbfbf, 0xfb3b, 0x77ff, 0xffff, 0xbfff, 0xffea,
0x7fff, 0xffff, 0xbbaf, 0xffff, 0x6fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xf77f, 0xbfff, 0xd7f7, 0x6eff, 0xffff, 0xbfff, 0xffff,
0x7bff, 0xffff, 0xbb5f, 0xffff, 0x7ff7, 0x7fff, 0xbfff, 0xffff,
0x7fff, 0xfff7, 0xaaff, 0xf77f, 0x7fff, 0xffff, 0xbfff, 0xfff4,
0x7fff, 0xffff, 0xbdaf, 0x7bff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xf7be, 0xbbff, 0xffff, 0x6dff, 0xffff, 0xbfff, 0xffff,
0x7bff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xfeff, 0xbfbf, 0xfff3, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7f7f, 0xff7f, 0xbfff, 0xffff,
0x7fff, 0xffef, 0xbfff, 0xffbf, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xff7f, 0x7fff, 0xfffd, 0xbfff, 0xffff,
0x7fff, 0xfcde, 0xbdbf, 0xdf8d, 0x7bff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xb5af, 0xbfff, 0x6ff7, 0x76ff, 0xbfff, 0xffff,
0x7fff, 0xfbad, 0xbfdf, 0xf77b, 0x7fff, 0xffff, 0xbfff, 0xffee,
0x77ff, 0xffff, 0xbfff, 0xfbf7, 0x7f7f, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xf77b, 0xb37f, 0xecf6, 0x6cff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbf5f, 0x3000, 0x67c0, 0x007f, 0xbfff, 0xffef,
0x7fff, 0xfccd, 0xbbb7, 0x7f99, 0x7cff, 0xffff, 0xb7ff, 0xfff5,
0x6bff, 0xffff, 0xb7af, 0x3000, 0x66e0, 0x0061, 0xbfff, 0xffdf,
0x7fff, 0xfccd, 0xbbbe, 0xd519, 0x7cff, 0xffff, 0xafff, 0xffff,
0x7dff, 0xffff, 0xbdff, 0x3000, 0x67e0, 0x007f, 0xbfff, 0xffff,
0x7fff, 0xfcc8, 0xb11f, 0xcc99, 0x7cff, 0xffff, 0xbfff, 0xfff5,
0x6bff, 0xffff, 0xbbbf, 0x3000, 0x67e0, 0x0061, 0xbfff, 0xffff,
0x7fff, 0xf698, 0xb11f, 0x8033, 0x66ff, 0xffff, 0xbfff, 0xffff,
0x77ff, 0xffff, 0xbff7, 0xbbbb, 0x73ee, 0x6ee7, 0xb333, 0x31f3,
0x6666, 0x78c6, 0xaccf, 0xb318, 0x7bcc, 0xccc7, 0xb999, 0x99ff,
0x7fff, 0xffff, 0xb77f, 0x3333, 0x6546, 0x6667, 0xb777, 0x74ab,
0x7777, 0x7d9c, 0xb995, 0x19cd, 0x79dd, 0xddd2, 0xb5dd, 0xddff,
0x7bff, 0xffff, 0xbffb, 0xfddd, 0x7fdd, 0xddff, 0xbfff, 0xffef,
0x7fff, 0xfff6, 0xacff, 0x337f, 0x7fff, 0xffff, 0xb7ff, 0xffff,
0x7fff, 0xffff, 0xbffd, 0x5fff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xfff9, 0xbbdf, 0xddff, 0x7bbf, 0xbfff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xfff7, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xfdff, 0xbfff, 0xfffd, 0x6fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbffe, 0xfffb, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfbf, 0xfffd, 0x6fff, 0xffff, 0xbfff, 0xffff,
0x7dff, 0xffff, 0xbbff, 0x5fff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xfef5, 0xbbff, 0xbdff, 0x77bf, 0xbfff, 0xbfff, 0xffef,
0x7dff, 0xffff, 0xbfbf, 0xffef, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7ffd, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xdfff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7ffb, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7ff7, 0xffbf, 0xbfff, 0xfdff,
0x7fff, 0xffff, 0xbff7, 0xffdf, 0x7ffe, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xeeff, 0xbfff, 0xffff, 0x7ff7, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7ffd, 0xffff, 0xbfff, 0xffff,
0x7ffd, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xdfbf, 0xbfff, 0xfdff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbf7f, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfbf, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfbf, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffd,
0x7bff, 0xffff, 0xb7ff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbf7f, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffd,
0x79ff, 0xffff, 0xb7bf, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x75ff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbebf, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffe,
0x77ff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xa95f, 0xffff, 0x7fdf, 0xffff, 0xbfff, 0xffef,
0x7fff, 0xffff, 0xbfff, 0x7fff, 0x7fff, 0xffff, 0xb7ff, 0xfff5,
0x69ff, 0xffff, 0xa7ff, 0xffff, 0x7fbf, 0xffff, 0xbfff, 0xffdf,
0x7fff, 0xffff, 0xbffe, 0xffff, 0x7fff, 0xffff, 0xafff, 0xffff,
0x7dff, 0xffff, 0xbd9f, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfff5,
0x6bff, 0xffff, 0xbaff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0x3333, 0x63e6, 0x6667, 0xb333, 0x31f3,
0x6666, 0x7ccc, 0xb98f, 0x9999, 0x73cc, 0xccc7, 0xb999, 0x99ff,
0x7fff, 0xffff, 0xb7ff, 0x7777, 0x6957, 0x7777, 0xb777, 0x74ab,
0x7777, 0x7ddd, 0xbba5, 0x5ddd, 0x7bdd, 0xddd2, 0xb5dd, 0xddff,
0x7fff, 0xffff, 0xbdff, 0xffff, 0x7fdf, 0xffff, 0xbfff, 0xffef,
0x7fff, 0xffff, 0xbfff, 0x7fff, 0x7fff, 0xffff, 0xb7ff, 0xffff,
0x7fff, 0xffff, 0xbffd, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xf7ff, 0x7fff, 0xfbff, 0xbfff, 0xf7ff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbffe, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xfbff, 0xbfff, 0xffff,
0x7dff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xefff, 0x7fff, 0xffff, 0xbfff, 0xf7ff,
0x7dff, 0xffff, 0xbbbf, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbeff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xefff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xfbff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbff7, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xf7ff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xefff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbeff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffbf,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffb,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffd,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffbf,
0x7fff, 0xffff, 0xaddf, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfff5,
0x69ff, 0xffff, 0xab7f, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7dff, 0xffff, 0xbddf, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfff5,
0x69ff, 0xffff, 0xb63f, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffe,
0x75ff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbf0f, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfff5,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xb6ff, 0xffff, 0x7fdf, 0xffff, 0xbfff, 0xffef,
0x7fff, 0xffff, 0xbfff, 0x7fff, 0x7fff, 0xffff, 0xb7ff, 0xfffe,
0x7bff, 0xffff, 0xb95f, 0xffff, 0x7fbf, 0xffff, 0xbfff, 0xffdf,
0x7fff, 0xffff, 0xbffe, 0xffff, 0x7fff, 0xffff, 0xafff, 0xffeb,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffe,
0x77ff, 0xffff, 0xb69f, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffef,
0x7fff, 0xffff, 0xbfff, 0x3333, 0x63e6, 0x6667, 0xb333, 0x31f3,
0x6666, 0x7ccc, 0xb98f, 0x9999, 0x73cc, 0xccc7, 0xb999, 0x99ff,
0x7fff, 0xffff, 0xb7bf, 0x7777, 0x6957, 0x7777, 0xb777, 0x74ab,
0x7777, 0x7ddd, 0xbba5, 0x5ddd, 0x7bdd, 0xddd2, 0xb5dd, 0xddff,
0x7fff, 0xffff, 0xbedf, 0xffff, 0x7fdf, 0xffff, 0xbfff, 0xffef,
0x7fff, 0xffff, 0xbfff, 0x7fff, 0x7fff, 0xffff, 0xb7ff, 0xfff7,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbeff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xfffe, 0x7ff7, 0xffbf, 0xbeff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xff5f,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x6ff7, 0xffff, 0xbf7f, 0xfeff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbdff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xff7f, 0xbfff, 0xffff,
0x77ff, 0xffff, 0xbffb, 0xff7f, 0x7fff, 0xbbf7, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xfffb, 0x7ff7, 0xffff, 0xbfff, 0xffbf,
0x7fff, 0xffff, 0xbffe, 0xffff, 0x7fff, 0xffff, 0xbffe, 0xffff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbdfd, 0xffff, 0x7fff, 0xdff7, 0xbfff, 0xffff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffbf, 0x7fff, 0xfdff, 0xbffe, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xfffb, 0x7ffb, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfee, 0x75ff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffdf,
0x7fff, 0xffff, 0xb7ff, 0xffff, 0x7ff7, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbffd, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xb7df, 0xb5ff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffbf,
0x7fff, 0xffff, 0xb65f, 0xefff, 0x7fff, 0x7fff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfff5,
0x6bff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7dff, 0xffff, 0xb7ff, 0xfdff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfff5,
0x6bff, 0xffff, 0xbd0f, 0xffff, 0x7ff7, 0xffdf, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffea,
0x77ff, 0xffff, 0xbbff, 0xffff, 0x7fff, 0xffff, 0x9fff, 0xffff,
0x5fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0x9fff, 0xffff, 0x4fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0x9fff, 0xffff,
0x5fff, 0xffff, 0xbfff, 0xdeff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbaff, 0xffff, 0x77ff, 0xffbf, 0x9fff, 0xffff,
0x5fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffe,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fef, 0x7fff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xa55f, 0xfebf, 0x67c6, 0x1ebf, 0xbfff, 0xffef,
0x7fff, 0xffff, 0x9fff, 0x7fff, 0x5fff, 0xffff, 0xb7ff, 0xfff5,
0x65ff, 0xffff, 0xafff, 0xc2bf, 0x47a6, 0x1ebf, 0xbfff, 0xffdf,
0x7fff, 0xffff, 0xbffe, 0xffff, 0x7fff, 0xffff, 0xafff, 0xffff,
0x5dff, 0xffff, 0xb55f, 0xfe7f, 0x67e6, 0x1f3f, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfff5,
0x67ff, 0xffff, 0x9fff, 0xc27f, 0x47e6, 0x1f3f, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0x3bb3, 0x73ee, 0xe6e7, 0xb333, 0x31f3,
0x4666, 0x7ccc, 0xb98f, 0x9999, 0x73cc, 0xccc7, 0xb999, 0x99ff,
0x7fff, 0xffff, 0xbfff, 0x7337, 0x4546, 0x7677, 0xb777, 0x74ab,
0x7777, 0x7ddd, 0xbba5, 0x5ddd, 0x7bdd, 0xddd2, 0xb5dd, 0xddff,
0x5fff, 0xffff, 0xbfff, 0xffff, 0x7fdf, 0xdfff, 0xbfff, 0xffef,
0x7fff, 0xffff, 0xbfff, 0x7fff, 0x7fff, 0xffff, 0xb7ff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xfeff, 0x77ff, 0xffff, 0xbfff, 0xefff,
0x7fff, 0xffff, 0xbf7f, 0xfff7, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0x9fff, 0xffff, 0x7ff7, 0xffff, 0xbfff, 0xffff,
0x7fdf, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xff7f, 0xbfff, 0xffff,
0x7fff, 0xffff, 0x8fff, 0xfdff, 0x4ff7, 0xffff, 0xbfff, 0xffff,
0x7fbf, 0xffff, 0xbfff, 0xffef, 0x7fff, 0xff7f, 0x9fff, 0xffff,
0x5dff, 0xffff, 0xafff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xefff,
0x7fff, 0xffff, 0x9f7f, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xffff,
0x7dff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0x9fff, 0xffff,
0x5fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffb,
0x77ff, 0xffff, 0x9fff, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xdfff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0x9fff, 0xffff,
0x5fff, 0xffff, 0xbfff, 0xffff, 0x77ee, 0xffff, 0xbfff, 0xdfff,
0x7fff, 0xefff, 0x9fff, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0x9fff, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xefff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xefff, 0x9fff, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0x9fff, 0xffff,
0x5fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0x9fff, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0x9fff, 0xffff,
0x5fff, 0xffff, 0xa55f, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0x9fff, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xfffd,
0x7bff, 0xffff, 0xafff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xa55f, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffd,
0x7bff, 0xffff, 0xaaff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfffb,
0x77ff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0x9fff, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0x9fff, 0xffff,
0x5fff, 0xffff, 0xbaff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0x9fff, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xffee,
0x77ff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0x9fff, 0xffff,
0x5fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0x855f, 0xffff, 0x5fdf, 0xffff, 0xbfff, 0xffef,
0x7fff, 0xffff, 0xbfff, 0x7fff, 0x7fff, 0xffff, 0x97ff, 0xfff5,
0x4bff, 0xffff, 0xafff, 0xffff, 0x7fbf, 0xffff, 0xbfff, 0xffdf,
0x7fff, 0xffff, 0xbffe, 0xffff, 0x7fff, 0xffff, 0xafff, 0xffff,
0x7fff, 0xffff, 0xb55f, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xfff5,
0x6bff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x5fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0x3333, 0x43e6, 0x6667, 0xb333, 0x31f3,
0x6666, 0x7ccc, 0xb98f, 0x9999, 0x73cc, 0xccc7, 0xb999, 0x99ff,
0x7fff, 0xffff, 0xbfff, 0x7777, 0x6957, 0x7777, 0xb777, 0x74ab,
0x7777, 0x7ddd, 0xbba5, 0x5ddd, 0x7bdd, 0xddd2, 0xb5dd, 0xddff,
0x7fff, 0xffff, 0x9fff, 0xffff, 0x5fdf, 0xffff, 0xbfff, 0xffef,
0x7fff, 0xffff, 0xbfff, 0x7fff, 0x7fff, 0xffff, 0xb7ff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0x9fff, 0xfeff, 0x7fff, 0xbfff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffbf, 0x9fff, 0xfff7,
0x7fff, 0xffff, 0xafff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0x9fff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7dff, 0xffff, 0xafff, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7dff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xf7ff,
0x7fff, 0xffff, 0xbfbf, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffef, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x5fff, 0xefff, 0xbfff, 0xffef, 0x7fff, 0xffbf, 0x9fff, 0xffff,
0x5fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xf7ff,
0x7fff, 0xefff, 0x9fff, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfdf, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fef, 0xffff, 0x9fff, 0xe7ff,
0x5fff, 0xefff, 0xbfff, 0xdfff, 0x7fff, 0xffff, 0x9fff, 0xffff,
0x5fff, 0xffff, 0xbfff, 0xffbe, 0x7fff, 0xbdff, 0xbfff, 0xffff,
0x7fff, 0xefff, 0x9fff, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xfffd, 0x7ff7, 0xfdff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xdfff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xff7f, 0x7fff, 0xdfff, 0xbfff, 0xd7ff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffef, 0x7ffd, 0xdfff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xefff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xfffb, 0x77ef, 0xffff, 0xbfdd, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xfffe, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0x9fff, 0xffef, 0x5ffd, 0xbfff, 0xbfef, 0xffff,
0x7fff, 0xffff, 0x9fff, 0xefff, 0x5fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xfef1, 0x67e7, 0xbfff, 0x9fed, 0xeffd,
0x53ff, 0xfff9, 0xb77f, 0xffff, 0x7fff, 0xb99f, 0xbccf, 0xffff,
0x7fff, 0xffff, 0x9fff, 0xffff, 0x5fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0x9fff, 0xffff,
0x5fff, 0xffff, 0xbffc, 0xffff, 0x7ff3, 0xfffe, 0xaf9e, 0x7cff,
0x7fff, 0xffe7, 0x93e7, 0xffff, 0x5f3e, 0x79f3, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0x9fff, 0xffff,
0x5fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
0x7fff, 0xffff, 0xbfff, 0xffff, 0x7fff, 0xffff, 0xbfff, 0xffff,
} };
const std::array<uint16_t, 512> block_1 { {
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
} };
} /* namespace cpld */
} /* namespace portapack */
+37
View File
@@ -0,0 +1,37 @@
/*
* 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 __PORTAPACK_CPLD_DATA_H__
#define __PORTAPACK_CPLD_DATA_H__
#include <cstdint>
#include <array>
namespace portapack {
namespace cpld {
extern const std::array<uint16_t, 3328> block_0;
extern const std::array<uint16_t, 512> block_1;
} /* namespace cpld */
} /* namespace portapack */
#endif/*__PORTAPACK_CPLD_DATA_H__*/
+67
View File
@@ -0,0 +1,67 @@
/*
* 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 __PORTAPACK_DMA_H__
#define __PORTAPACK_DMA_H__
#include <cstddef>
#include "gpdma.hpp"
using namespace lpc43xx;
namespace portapack {
/* GPDMA */
/* DMA channel 0 has the highest priority and DMA channel 7 has the lowest
* priority.
*/
/* Reserve channels 6 and 7 for memory-memory transfers. These channels
* can't saturate AHB by design. */
constexpr size_t sgpio_gpdma_channel_number = 0;
constexpr size_t i2s0_tx_gpdma_channel_number = 2;
constexpr size_t i2s0_rx_gpdma_channel_number = 3;
constexpr size_t adc1_gpdma_channel_number = 4;
constexpr size_t adc0_gpdma_channel_number = 5;
constexpr gpdma::mux::MUX gpdma_mux {
.peripheral_0 = gpdma::mux::Peripheral0::SGPIO14,
.peripheral_1 = gpdma::mux::Peripheral1::TIMER0_MATCH_0,
.peripheral_2 = gpdma::mux::Peripheral2::TIMER0_MATCH_1,
.peripheral_3 = gpdma::mux::Peripheral3::TIMER1_MATCH_0,
.peripheral_4 = gpdma::mux::Peripheral4::TIMER1_MATCH_1,
.peripheral_5 = gpdma::mux::Peripheral5::TIMER2_MATCH_0,
.peripheral_6 = gpdma::mux::Peripheral6::TIMER2_MATCH_1,
.peripheral_7 = gpdma::mux::Peripheral7::TIMER3_MATCH_0,
.peripheral_8 = gpdma::mux::Peripheral8::TIMER3_MATCH_1,
.peripheral_9 = gpdma::mux::Peripheral9::I2S0_DMAREQ_1,
.peripheral_10 = gpdma::mux::Peripheral10::I2S0_DMAREQ_2,
.peripheral_11 = gpdma::mux::Peripheral11::SSP1_RX,
.peripheral_12 = gpdma::mux::Peripheral12::SSP1_TX,
.peripheral_13 = gpdma::mux::Peripheral13::ADC0,
.peripheral_14 = gpdma::mux::Peripheral14::ADC1,
.peripheral_15 = gpdma::mux::Peripheral15::DAC,
};
} /* namespace portapack */
#endif/*__PORTAPACK_DMA_H__*/
+65
View File
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PORTAPACK_HAL_H__
#define __PORTAPACK_HAL_H__
#include <cstdint>
#include <cstddef>
#include <array>
#include "pins.hpp"
using namespace lpc43xx;
namespace portapack {
/* TODO: Make these GPIOs private and expose via appropriate functions. */
constexpr GPIO gpio_io_stbx = gpio[GPIO5_0]; /* P2_0 */
constexpr GPIO gpio_addr = gpio[GPIO5_1]; /* P2_1 */
constexpr GPIO gpio_lcd_te = gpio[GPIO5_3]; /* P2_3 */
constexpr GPIO gpio_unused = gpio[GPIO5_4]; /* P2_4 */
constexpr GPIO gpio_lcd_rd = gpio[GPIO5_7]; /* P2_8 */
constexpr GPIO gpio_lcd_wr = gpio[GPIO1_10]; /* P2_9 */
constexpr GPIO gpio_dir = gpio[GPIO1_13]; /* P2_13 */
constexpr std::array<GPIO, 8> gpios_data {
gpio[GPIO3_8],
gpio[GPIO3_9],
gpio[GPIO3_10],
gpio[GPIO3_11],
gpio[GPIO3_12],
gpio[GPIO3_13],
gpio[GPIO3_14],
gpio[GPIO3_15],
};
constexpr GPIO gpio_cpld_tms = gpio[GPIO1_1]; // P1_8
constexpr GPIO gpio_cpld_tdo = gpio[GPIO1_8]; // P1_5
constexpr GPIO gpio_cpld_tck = gpio[GPIO3_0]; // P6_1
constexpr GPIO gpio_cpld_tdi = gpio[GPIO3_1]; // P6_2
/* I2C0 */
constexpr uint8_t wm8731_i2c_address = 0x1a;
} /* namespace portapack */
#endif/*__PORTAPACK_HAL_H__*/
+105
View File
@@ -0,0 +1,105 @@
/*
* 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 "portapack_io.hpp"
#include "lpc43xx_cpp.hpp"
using namespace lpc43xx;
#include "utility.hpp"
#include <ch.h>
#include <cstdint>
namespace portapack {
void IO::init() {
data_mask_set();
data_write_high(0);
dir_read();
lcd_rd_deassert();
lcd_wr_deassert();
io_stb_deassert();
addr(0);
gpio_dir.output();
gpio_lcd_rd.output();
gpio_lcd_wr.output();
gpio_io_stbx.output();
gpio_addr.output();
gpio_rot_a.input();
gpio_rot_b.input();
}
void IO::lcd_backlight(const bool value) {
io_reg = (io_reg & 0x7f) | ((value ? 1 : 0) << 7);
io_write(1, io_reg);
}
void IO::lcd_reset_state(const bool active) {
/* NOTE: This overwrites the contents of the IO register, which for now
* have no significance. But someday...?
*/
io_reg = (io_reg & 0xfe) | ((active ? 1 : 0) << 0);
io_write(1, io_reg);
}
uint32_t IO::io_update(const TouchPinsConfig write_value) {
/* Very touchy code to save context of PortaPack data bus while the
* resistive touch pin drive is changed. Order of operations is
* important to prevent latching spurious data into the LCD or IO
* registers.
*/
const auto save_data = data_read();
const auto addr = gpio_addr.read();
const auto dir = gpio_dir.read();
io_stb_assert();
/* Switch to read */
dir_read();
addr_0();
__asm__("nop");
__asm__("nop");
__asm__("nop");
const auto switches_raw = data_read();
/* Switch to write */
data_write_low(toUType(write_value));
dir_write();
__asm__("nop");
__asm__("nop");
__asm__("nop");
io_stb_deassert();
data_write_low(save_data);
if( dir ) { /* 0 (write) -> 1 (read) */
dir_read();
}
gpio_addr.write(addr);
return switches_raw;
}
}
+381
View File
@@ -0,0 +1,381 @@
/*
* 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 __PORTAPACK_IO_H__
#define __PORTAPACK_IO_H__
#include <cstdint>
#include <cstddef>
#include <array>
#include "gpio.hpp"
#include "ui.hpp"
namespace portapack {
class IO {
public:
enum class TouchPinsConfig : uint8_t {
XN_BIT = (1 << 0),
XP_BIT = (1 << 1),
YN_BIT = (1 << 2),
YP_BIT = (1 << 3),
XN_OE = (1 << 4),
XP_OE = (1 << 5),
YN_OE = (1 << 6),
YP_OE = (1 << 7),
XN_IN = XN_BIT,
XN_OUT_1 = XN_OE | XN_BIT,
XN_OUT_0 = XN_OE,
XP_IN = XP_BIT,
XP_OUT_1 = XP_OE | XP_BIT,
XP_OUT_0 = XP_OE,
YN_IN = YN_BIT,
YN_OUT_1 = YN_OE | YN_BIT,
YN_OUT_0 = YN_OE,
YP_IN = YP_BIT,
YP_OUT_1 = YP_OE | YP_BIT,
YP_OUT_0 = YP_OE,
/* Allow pins to be pulled up by CPLD pull-ups. */
Float = XP_IN | XN_IN | YP_IN | YN_IN,
/* Drive one plane to 0V, other plane is pulled up. Watch for when pulled-up
* plane falls to ~0V.
*/
WaitTouch = XP_OUT_0 | XN_OUT_0 | YP_IN | YN_IN,
/* Create a voltage divider between X plane, touch resistance, Y plane. */
SensePressure = XP_IN | XN_OUT_0 | YP_OUT_1 | YN_IN,
/* Create a voltage divider across X plane, read voltage from Y plane. */
SenseX = XP_OUT_1 | XN_OUT_0 | YP_IN | YN_IN,
/* Create a voltage divider across Y plane, read voltage from X plane. */
SenseY = XP_IN | XN_IN | YP_OUT_1 | YN_OUT_0,
};
constexpr IO(
GPIO gpio_dir,
GPIO gpio_lcd_rd,
GPIO gpio_lcd_wr,
GPIO gpio_io_stbx,
GPIO gpio_addr,
GPIO gpio_rot_a,
GPIO gpio_rot_b
) : gpio_dir { gpio_dir },
gpio_lcd_rd { gpio_lcd_rd },
gpio_lcd_wr { gpio_lcd_wr },
gpio_io_stbx { gpio_io_stbx },
gpio_addr { gpio_addr },
gpio_rot_a { gpio_rot_a },
gpio_rot_b { gpio_rot_b }
{
};
void init();
void lcd_backlight(const bool value);
void lcd_reset_state(const bool active);
void lcd_data_write_command_and_data(
const uint_fast8_t command,
const std::initializer_list<uint8_t>& data
) {
lcd_command(command);
for(const auto d : data) {
lcd_write_data_fast(d);
}
}
void lcd_data_read_command_and_data(
const uint_fast8_t command,
uint16_t* const data,
const size_t data_count
) {
lcd_command(command);
for(size_t i=0; i<data_count; i++) {
data[i] = lcd_read_data_id();
}
}
void lcd_write_word(const uint32_t w) {
lcd_write_data_fast(w);
}
void lcd_write_words(const uint16_t* const w, size_t n) {
for(size_t i=0; i<n; i++) {
lcd_write_data_fast(w[i]);
}
}
void lcd_write_pixel(const ui::Color pixel) {
lcd_write_data_fast(pixel.v);
}
uint32_t lcd_read_word() {
return lcd_read_data_frame_memory();
}
/*
// NOTE: Pixels read in RGB24 format, not the RGB565 format used
// to write pixels to frame memory. This makes reading very tricky!
ui::Color lcd_read_pixel() {
return ui::Color { lcd_read_data_frame_memory() };
}
*/
void lcd_write_pixels(const ui::Color pixel, size_t n) {
while(n--) {
lcd_write_data_fast(pixel.v);
}
}
void lcd_write_pixels(const ui::Color* const pixels, size_t n) {
for(size_t i=0; i<n; i++) {
lcd_write_pixel(pixels[i]);
}
}
uint32_t io_read() {
io_stb_assert();
dir_read();
addr_0();
__asm__("nop");
__asm__("nop");
__asm__("nop");
const auto switches_raw = data_read();
io_stb_deassert();
return switches_raw;
}
uint32_t io_update(const TouchPinsConfig write_value);
uint32_t lcd_te() {
return gpio_rot_a.read();
}
private:
const GPIO gpio_dir;
const GPIO gpio_lcd_rd;
const GPIO gpio_lcd_wr;
const GPIO gpio_io_stbx;
const GPIO gpio_addr;
const GPIO gpio_rot_a;
const GPIO gpio_rot_b;
static constexpr ioportid_t gpio_data_port_id = 3;
static constexpr size_t gpio_data_shift = 8;
static constexpr ioportmask_t gpio_data_mask = 0xffU << gpio_data_shift;
uint8_t io_reg { 0x01 };
void lcd_rd_assert() {
gpio_lcd_rd.set();
}
void lcd_rd_deassert() {
gpio_lcd_rd.clear();
}
void lcd_wr_assert() {
gpio_lcd_wr.set();
}
void lcd_wr_deassert() {
gpio_lcd_wr.clear();
}
void io_stb_assert() {
gpio_io_stbx.clear();
}
void io_stb_deassert() {
gpio_io_stbx.set();
}
void addr(const bool value) {
gpio_addr.write(value);
}
void addr_1() {
gpio_addr.set();
}
void addr_0() {
gpio_addr.clear();
}
void data_mask_set() {
LPC_GPIO->MASK[gpio_data_port_id] = ~gpio_data_mask;
}
void dir_write() {
gpio_dir.clear();
LPC_GPIO->DIR[gpio_data_port_id] |= gpio_data_mask;
/* TODO: Manipulating DIR[3] makes me queasy. The RFFC5072 DATA pin
* is also on port 3, and switches direction periodically...
* Time to resort to bit-banding to enforce atomicity? But then, how
* to change direction on eight bits efficiently? Or do I care, since
* the PortaPack data bus shouldn't change direction too frequently?
*/
}
void dir_read() {
LPC_GPIO->DIR[gpio_data_port_id] &= ~gpio_data_mask;
gpio_dir.set();
}
void data_write_low(const uint32_t value) {
LPC_GPIO->MPIN[gpio_data_port_id] = (value << gpio_data_shift);
}
void data_write_high(const uint32_t value) {
LPC_GPIO->MPIN[gpio_data_port_id] = value;
}
uint32_t data_read() {
return (LPC_GPIO->MPIN[gpio_data_port_id] >> gpio_data_shift) & 0xffU;
}
void lcd_command(const uint32_t value) {
data_write_high(0); /* Drive high byte (with zero -- don't care) */
dir_write(); /* Turn around data bus, MCU->CPLD */
addr(0); /* Indicate command */
__asm__("nop");
__asm__("nop");
__asm__("nop");
lcd_wr_assert(); /* Latch high byte */
data_write_low(value); /* Drive low byte (pass-through) */
__asm__("nop");
__asm__("nop");
__asm__("nop");
lcd_wr_deassert(); /* Complete write operation */
addr(1); /* Set up for data phase (most likely after a command) */
}
void lcd_write_data_fast(const uint32_t value) __attribute__((always_inline)) {
// NOTE: Assumes and DIR=0 and ADDR=1 from command phase.
data_write_high(value); /* Drive high byte */
__asm__("nop");
lcd_wr_assert(); /* Latch high byte */
data_write_low(value); /* Drive low byte (pass-through) */
__asm__("nop");
__asm__("nop");
__asm__("nop");
lcd_wr_deassert(); /* Complete write operation */
}
uint32_t lcd_read_data_id() {
// NOTE: Assumes ADDR=1 from command phase.
dir_read();
/* Start read operation */
lcd_rd_assert();
/* Wait for passthrough data(15:8) to settle -- ~16ns (3 cycles) typical */
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
const auto value_high = data_read();
/* Latch data[7:0] */
lcd_rd_deassert();
/* Wait for latched data[7:0] to settle -- ~26ns (5 cycles) typical */
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
__asm__("nop");
const auto value_low = data_read();
return (value_high << 8) | value_low;
}
uint32_t lcd_read_data_frame_memory() {
// NOTE: Assumes ADDR=1 from command phase.
dir_read();
/* Start read operation */
lcd_rd_assert();
/* Wait for passthrough data(15:8) to settle -- ~16ns (3 cycles) typical */
/* Wait for read control L duration (355ns) */
halPolledDelay(71); // 355ns
const auto value_high = data_read();
/* Latch data[7:0] */
lcd_rd_deassert();
/* Wait for latched data[7:0] to settle -- ~26ns (5 cycles) typical */
/* Wait for read control H duration (90ns) */
halPolledDelay(18); // 90ns
const auto value_low = data_read();
return (value_high << 8) | value_low;
}
void io_write(const bool address, const uint_fast16_t value) {
data_write_low(value);
dir_write();
addr(address);
__asm__("nop");
__asm__("nop");
__asm__("nop");
io_stb_assert();
__asm__("nop");
__asm__("nop");
__asm__("nop");
io_stb_deassert();
}
/*
void lcd_data_write_command_and_data(
const uint_fast16_t command,
const uint8_t* const data,
const size_t count
) {
lcd_data_write_command(command);
for(size_t i=0; i<count; i++) {
lcd_data_write_data(data[i]);
}
}
*/
};
extern IO io;
} /* namespace portapack */
#endif/*__PORTAPACK_IO_H__*/
@@ -0,0 +1,24 @@
/*
* 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 "portapack_shared_memory.hpp"
SharedMemory& shared_memory = *reinterpret_cast<SharedMemory*>(0x10088000);
@@ -0,0 +1,52 @@
/*
* 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 __PORTAPACK_SHARED_MEMORY_H__
#define __PORTAPACK_SHARED_MEMORY_H__
#include <cstdint>
#include "message_queue.hpp"
struct TouchADCFrame {
uint32_t dr[8];
};
/* NOTE: These structures must be located in the same location in both M4 and M0 binaries */
struct SharedMemory {
MessageQueue baseband_queue;
MessageQueue application_queue;
// TODO: M0 should directly configure and control DMA channel that is
// acquiring ADC samples.
TouchADCFrame touch_adc_frame;
};
extern SharedMemory& shared_memory;
#if defined(LPC43XX_M0)
inline void init_message_queues() {
new (&shared_memory.baseband_queue) MessageQueue();
new (&shared_memory.application_queue) MessageQueue();
}
#endif
#endif/*__PORTAPACK_SHARED_MEMORY_H__*/
+62
View File
@@ -0,0 +1,62 @@
/*
* 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 "ui.hpp"
#include <algorithm>
namespace ui {
bool Rect::contains(const Point p) const {
return (p.x >= left()) && (p.y >= top()) &&
(p.x < right()) && (p.y < bottom());
}
Rect Rect::intersect(const Rect& o) const {
const auto x1 = std::max(left(), o.left());
const auto x2 = std::min(right(), o.right());
const auto y1 = std::max(top(), o.top());
const auto y2 = std::min(bottom(), o.bottom());
if( (x2 >= x1) && (y2 > y1) ) {
return {
x1, y1,
static_cast<Dim>(x2 - x1), static_cast<Dim>(y2 - y1) };
} else {
return { };
}
}
Rect& Rect::operator+=(const Rect& p) {
if( is_empty() ) {
*this = p;
}
if( !p.is_empty() ) {
const auto x1 = std::min(left(), p.left());
const auto y1 = std::min(top(), p.top());
pos = { x1, y1 };
const auto x2 = std::max(right(), p.right());
const auto y2 = std::max(bottom(), p.bottom());
size = { static_cast<Dim>(x2 - x1), static_cast<Dim>(y2 - y1) };
}
return *this;
}
} /* namespace ui */
+289
View File
@@ -0,0 +1,289 @@
/*
* 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 __UI_H__
#define __UI_H__
#include <cstdint>
namespace ui {
using Coord = int16_t;
using Dim = int16_t;
struct Color {
uint16_t v;
constexpr Color(
) : v { 0 }
{
}
/*
explicit constexpr Color(
const uint32_t value
) : v { static_cast<uint16_t>(value) }
{
}
*/
constexpr Color(
uint8_t r,
uint8_t g,
uint8_t b
) : v {
static_cast<uint16_t>(
((r & 0xf8) << 8)
| ((g & 0xfc) << 3)
| ((b & 0xf8) >> 3)
)}
{
}
static constexpr Color black() {
return { 0, 0, 0 };
}
static constexpr Color red() {
return { 255, 0, 0 };
}
static constexpr Color yellow() {
return { 255, 255, 0 };
}
static constexpr Color green() {
return { 0, 255, 0 };
}
static constexpr Color blue() {
return { 0, 0, 255 };
}
static constexpr Color white() {
return { 255, 255, 255 };
}
};
#if 0
enum class CardinalDirection : uint8_t {
West,
South,
North,
East,
};
#endif
struct Point {
Coord x;
Coord y;
constexpr Point(
) : x { 0 },
y { 0 }
{
}
constexpr Point(
Coord x,
Coord y
) : x { x },
y { y }
{
}
Point operator-() const {
return { static_cast<Coord>(-x), static_cast<Coord>(-y) };
}
Point operator+(const Point& p) const {
return { static_cast<Coord>(x + p.x), static_cast<Coord>(y + p.y) };
}
Point operator-(const Point& p) const {
return { static_cast<Coord>(x - p.x), static_cast<Coord>(y - p.y) };
}
Point& operator+=(const Point& p) {
x += p.x;
y += p.y;
return *this;
}
#if 0
uint32_t magnitude_squared() const {
return (x * x) + (y * y);
}
CardinalDirection cardinal_direction() const {
/* TODO: Doesn't handle 0,0 */
const auto rotated = sloppy_rotate_by_45_degrees();
if( rotated.x > 0 ) {
if( rotated.y > 0 ) {
return CardinalDirection::East;
} else {
// y<=0
return CardinalDirection::North;
}
} else {
// x<=0
if( rotated.y > 0 ) {
return CardinalDirection::South;
} else {
return CardinalDirection::West;
}
}
}
private:
Point sloppy_rotate_by_45_degrees() const {
/* Clockwise rotate (in screen coordinates), with a gain in
* magnitude of sqrt(2).
*/
return {
static_cast<Coord>(x - y),
static_cast<Coord>(x + y)
};
}
#endif
};
struct Size {
Dim w;
Dim h;
constexpr Size(
) : w { 0 },
h { 0 }
{
}
constexpr Size(
Dim w,
Dim h
) : w { w },
h { h }
{
}
bool is_empty() const {
return (w < 1) || (h < 1);
}
};
struct Rect {
Point pos;
Size size;
constexpr Rect(
) : pos { },
size { }
{
}
constexpr Rect(
Coord x, Coord y,
Dim w, Dim h
) : pos { x, y },
size { w, h }
{
}
constexpr Rect(
Point pos,
Size size
) : pos(pos),
size(size)
{
}
Coord top() const {
return pos.y;
}
Coord bottom() const {
return pos.y + size.h;
}
Coord left() const {
return pos.x;
}
Coord right() const {
return pos.x + size.w;
}
Dim width() const {
return size.w;
}
Dim height() const {
return size.h;
}
Point center() const {
return {
static_cast<Coord>(pos.x + size.w / 2),
static_cast<Coord>(pos.y + size.h / 2)
};
}
bool is_empty() const {
return size.is_empty();
}
bool contains(const Point p) const;
Rect intersect(const Rect& o) const;
Rect operator+(const Point& p) const {
return { pos + p, size };
}
Rect& operator+=(const Rect& p);
operator bool() const {
return !size.is_empty();
}
};
enum class KeyEvent {
/* Ordinals map to bit positions reported by CPLD */
Right = 0,
Left = 1,
Down = 2,
Up = 3,
Select = 4,
};
using EncoderEvent = int32_t;
struct TouchEvent {
enum class Type : uint32_t {
Start = 0,
Move = 1,
End = 2,
};
Point point;
Type type;
};
} /* namespace ui */
#endif/*__UI_H__*/
+188
View File
@@ -0,0 +1,188 @@
/*
* 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 "ui_focus.hpp"
#include "ui_widget.hpp"
#include <cstdint>
#include <algorithm>
#include <functional>
#include <utility>
#include <vector>
namespace ui {
Widget* FocusManager::focus_widget() const {
return focus_widget_;
}
void FocusManager::set_focus_widget(Widget* const new_focus_widget) {
// Widget already has focus.
if( new_focus_widget == focus_widget() ) {
return;
}
if( new_focus_widget ) {
// if( !new_focus_widget->visible() ) {
// if( new_focus_widget->hidden() ) {
// // New widget is not visible. Do nothing.
// // TODO: Should this be a debug assertion?
// return;
// }
if( !new_focus_widget->focusable() ) {
// New widget is not focusable. Does it have a preferred child that
// can receive focus?
set_focus_widget(new_focus_widget->last_child_focus());
return;
}
}
// Blur old widget.
if( focus_widget() ) {
focus_widget()->on_blur();
focus_widget()->set_dirty();
}
focus_widget_ = new_focus_widget;
if( focus_widget() ) {
focus_widget()->on_focus();
focus_widget()->set_dirty();
focus_widget()->parent()->set_last_child_focus(focus_widget());
}
}
using test_result_t = std::pair<Widget* const, const uint32_t>;
using test_fn = std::function<test_result_t(Widget* const)>;
using test_collection_t = std::vector<test_result_t>;
/* Walk all visible widgets in hierarchy, collecting those that pass test */
template<typename TestFn>
static void widget_collect_visible(Widget* const w, TestFn test, test_collection_t& collection) {
for(auto child : w->children()) {
if( !child->hidden() ) {
const auto result = test(child);
if( result.first ) {
collection.push_back(result);
}
widget_collect_visible(child, test, collection);
}
}
}
void FocusManager::update(
Widget* const top_widget,
const KeyEvent event
) {
if( focus_widget() ) {
const auto focus_screen_rect = focus_widget()->screen_rect();
const auto center = focus_screen_rect.center();
const auto test_fn = [&center, event](ui::Widget* const w) -> test_result_t {
// if( w->visible() && w->focusable() ) {
if( w->focusable() ) {
const Point p = w->screen_rect().center() - center;
/* Heuristic to compute closeness. */
/* TODO: Look at metric involving overlap of current
* widget rectangle in the direction of movement, with
* all the prospective widgets.
*/
switch(event) {
case KeyEvent::Right:
if( p.x > 0 ) {
return { w, p.x * (abs(p.y) + 1) };
}
break;
case KeyEvent::Left:
if( p.x < 0 ) {
return { w, -p.x * (abs(p.y) + 1) };
}
break;
case KeyEvent::Down:
if( p.y > 0 ) {
return { w, p.y * (abs(p.x) + 1) };
}
break;
case KeyEvent::Up:
if( p.y < 0 ) {
return { w, -p.y * (abs(p.x) + 1) };
}
break;
default:
break;
}
}
return { nullptr, 0 };
};
test_collection_t collection;
widget_collect_visible(top_widget, test_fn, collection);
const auto compare_fn = [](const test_result_t& a, const test_result_t& b) {
return a.second < b.second;
};
const auto nearest = std::min_element(collection.cbegin(), collection.cend(), compare_fn);
if( nearest != collection.cend() ) {
//focus->blur();
const auto new_focus = (*nearest).first;
set_focus_widget(new_focus);
}
}
}
#if 0
void FocusManager::update(
Widget* const top_widget,
const TouchEvent event
) {
const auto test_fn = [event](Widget* const w) -> test_result_t {
if( w->focusable() ) {
const auto r = w->screen_rect();
if( r.contains(event) ) {
return { w, 0 };
}
}
return { nullptr, { } };
};
test_collection_t collection;
widget_collect_visible(
top_widget, test_fn,
collection
);
if( !collection.empty() ) {
// Take the last object in the collection, it will be rendered last,
// therefore appear "on top".
const auto touched = collection.back().first;
touched->on_touch(event);
}
}
#endif
} /* namespace ui */
+45
View File
@@ -0,0 +1,45 @@
/*
* 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 __UI_FOCUS_H__
#define __UI_FOCUS_H__
#include "ui.hpp"
namespace ui {
class Widget;
class FocusManager {
public:
Widget* focus_widget() const;
void set_focus_widget(Widget* const new_focus_widget);
void update(Widget* const top_widget, const KeyEvent event);
//void update(Widget* const top_widget, const TouchEvent event);
private:
Widget* focus_widget_ { nullptr };
};
} /* namespace ui */
#endif/*__UI_FOCUS_H__*/
+71
View File
@@ -0,0 +1,71 @@
/*
* 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 "ui_painter.hpp"
namespace ui {
Style Style::invert() const {
return {
.font = font,
.background = foreground,
.foreground = background,
};
}
size_t Painter::draw_char(const Point p, const Style& style, const char c) {
const auto glyph = style.font.glyph(c);
display_.draw_glyph(p, glyph, style.foreground, style.background);
return glyph.advance().x;
}
size_t Painter::draw_string(Point p, const Style& style, const std::string text) {
size_t width = 0;
for(const auto c : text) {
const auto glyph = style.font.glyph(c);
display_.draw_glyph(p, glyph, style.foreground, style.background);
const auto advance = glyph.advance();
p += advance;
width += advance.x;
}
return width;
}
void Painter::draw_hline(Point p, size_t width, const Color c) {
display_.fill_rectangle({ p, { static_cast<Dim>(width), 1 } }, c);
}
void Painter::draw_vline(Point p, size_t height, const Color c) {
display_.fill_rectangle({ p, { 1, static_cast<Dim>(height) } }, c);
}
void Painter::draw_rectangle(const Rect r, const Color c) {
draw_hline(r.pos, r.size.w, c);
draw_vline({ r.pos.x, static_cast<Coord>(r.pos.y + 1) }, r.size.h - 2, c);
draw_vline({ static_cast<Coord>(r.pos.x + r.size.w - 1), static_cast<Coord>(r.pos.y + 1) }, r.size.h - 2, c);
draw_hline({ r.pos.x, static_cast<Coord>(r.pos.y + r.size.h - 1) }, r.size.w, c);
}
void Painter::fill_rectangle(const Rect r, const Color c) {
display_.fill_rectangle(r, c);
}
} /* namespace ui */
+69
View File
@@ -0,0 +1,69 @@
/*
* 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 __UI_PAINTER_H__
#define __UI_PAINTER_H__
#include "ui.hpp"
#include "ui_text.hpp"
#include "lcd_ili9341.hpp"
#include <string>
namespace ui {
struct Style {
const Font& font;
const Color background;
const Color foreground;
Style invert() const;
};
class Painter {
public:
Painter(
lcd::ILI9341& display
) : display_ { display }
{
}
Painter(const Painter&) = delete;
Painter(Painter&&) = delete;
size_t draw_char(const Point p, const Style& style, const char c);
size_t draw_string(Point p, const Style& style, const std::string text);
void draw_rectangle(const Rect r, const Color c);
void fill_rectangle(const Rect r, const Color c);
private:
lcd::ILI9341& display_;
void draw_hline(Point p, size_t width, const Color c);
void draw_vline(Point p, size_t height, const Color c);
};
} /* namespace ui */
#endif/*__UI_PAINTER_H__*/
+54
View File
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ui_text.hpp"
namespace ui {
Glyph Font::glyph(const char c) const {
if( c < c_start ) {
return { w, h, data };
}
const size_t index = c - c_start;
if( index >= c_count ) {
return { w, h, data };
} else {
return { w, h, &data[index * data_stride] };
}
}
Dim Font::line_height() const {
return h;
}
Size Font::size_of(const std::string s) const {
Size size;
for(const auto c : s) {
const auto glyph_data = glyph(c);
size.w += glyph_data.w();
size.h = std::max(size.h, glyph_data.h());
}
return size;
}
} /* namespace ui */
+104
View File
@@ -0,0 +1,104 @@
/*
* 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 __UI_TEXT_H__
#define __UI_TEXT_H__
#include <cstdint>
#include <cstddef>
#include <string>
#include "ui.hpp"
namespace ui {
class Glyph {
public:
constexpr Glyph(
Dim w,
Dim h,
const uint8_t* const pixels
) : w_ { static_cast<uint8_t>(w) },
h_ { static_cast<uint8_t>(h) },
pixels_ { pixels }
{
}
Dim w() const {
return w_;
}
Dim h() const {
return h_;
}
Size size() const {
return { w_, h_ };
}
Point advance() const {
return { w_, 0 };
}
const uint8_t* pixels() const {
return pixels_;
}
private:
const uint8_t w_;
const uint8_t h_;
const uint8_t* const pixels_;
};
class Font {
public:
constexpr Font(
Dim w,
Dim h,
const uint8_t* data,
char c_start,
size_t c_count
) : w { w },
h { h },
data { data },
c_start { c_start },
c_count { c_count },
data_stride { (w * h + 7U) >> 3 }
{
}
Glyph glyph(const char c) const;
Dim line_height() const;
Size size_of(const std::string s) const;
private:
const Dim w;
const Dim h;
const uint8_t* const data;
const char c_start;
const size_t c_count;
const size_t data_stride;
};
} /* namespace ui */
#endif/*__UI_TEXT_H__*/
+558
View File
@@ -0,0 +1,558 @@
/*
* 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 "ui_widget.hpp"
#include "ui_painter.hpp"
#include <cstdint>
#include <cstddef>
#include <algorithm>
namespace ui {
constexpr size_t to_string_max_length = 16;
static char* to_string_dec_uint_internal(
char* p,
uint32_t n
) {
*p = 0;
auto q = p;
do {
const uint32_t d = n % 10;
const char c = d + 48;
*(--q) = c;
n /= 10;
} while( n != 0 );
return q;
}
static char* to_string_dec_uint_pad_internal(
char* const term,
const uint32_t n,
const int32_t l,
const char fill
) {
auto q = to_string_dec_uint_internal(term, n);
if( fill ) {
while( (term - q) < l ) {
*(--q) = fill;
}
}
return q;
}
std::string to_string_dec_uint(
const uint32_t n,
const int32_t l,
const char fill
) {
char p[16];
auto term = p + sizeof(p) - 1;
auto q = to_string_dec_uint_pad_internal(term, n, l, fill);
// Right justify.
while( (term - q) < l ) {
*(--q) = ' ';
}
return q;
}
std::string to_string_dec_int(
const int32_t n,
const int32_t l,
const char fill
) {
const size_t negative = (n < 0) ? 1 : 0;
uint32_t n_abs = negative ? -n : n;
char p[16];
auto term = p + sizeof(p) - 1;
auto q = to_string_dec_uint_pad_internal(term, n_abs, l - negative, fill);
// Add sign.
if( negative ) {
*(--q) = '-';
}
// Right justify.
while( (term - q) < l ) {
*(--q) = ' ';
}
return q;
}
static void to_string_hex_internal(char* p, const uint32_t n, const int32_t l) {
const uint32_t d = n & 0xf;
p[l] = (d > 9) ? (d + 87) : (d + 48);
if( l > 0 ) {
to_string_hex_internal(p, n >> 4, l - 1);
}
}
std::string to_string_hex(const uint32_t n, const int32_t l) {
char p[16];
to_string_hex_internal(p, n, l - 1);
p[l] = 0;
return p;
}
/* Widget ****************************************************************/
Point Widget::screen_pos() {
return parent() ? (parent()->screen_pos() + parent_rect.pos) : parent_rect.pos;
}
Size Widget::size() const {
return parent_rect.size;
}
Rect Widget::screen_rect() {
return parent() ? (parent_rect + parent()->screen_pos()) : parent_rect;
}
void Widget::set_parent_rect(const Rect new_parent_rect) {
parent_rect = new_parent_rect;
set_dirty();
}
Widget* Widget::parent() const {
return parent_;
}
void Widget::set_parent(Widget* const widget) {
if( parent_ && !widget ) {
// We have a parent, but are losing it. Update visible status.
visible(false);
}
parent_ = widget;
}
void Widget::set_dirty() {
flags.dirty = true;
dirty_event();
}
bool Widget::dirty() const {
return flags.dirty;
}
void Widget::set_clean() {
flags.dirty = false;
}
void Widget::hidden(bool hide) {
if( hide != flags.hidden ) {
flags.hidden = hide;
// If parent is hidden, either of these is a no-op.
if( hide ) {
parent()->set_dirty();
/* TODO: Notify self and all non-hidden children that they're
* now effectively hidden?
*/
} else {
set_dirty();
/* TODO: Notify self and all non-hidden children that they're
* now effectively shown?
*/
}
}
}
void Widget::focus() {
context().focus_manager.set_focus_widget(this);
}
void Widget::on_focus() {
//set_dirty();
}
void Widget::blur() {
context().focus_manager.set_focus_widget(nullptr);
}
void Widget::on_blur() {
//set_dirty();
}
bool Widget::focusable() const {
return flags.focusable;
}
bool Widget::has_focus() {
return (context().focus_manager.focus_widget() == this);
}
Widget* Widget::last_child_focus() const {
return nullptr;
}
void Widget::set_last_child_focus(Widget* const child) {
// Ignore.
(void)child;
}
bool Widget::on_key(const KeyEvent event) {
(void)event;
return false;
}
bool Widget::on_encoder(const EncoderEvent event) {
(void)event;
return false;
}
bool Widget::on_touch(const TouchEvent event) {
(void)event;
return false;
}
const std::vector<Widget*> Widget::children() const {
return { };
}
Context& Widget::context() const {
return parent()->context();
}
void Widget::set_style(const Style* new_style) {
if( new_style != style_ ) {
style_ = new_style;
set_dirty();
}
}
const Style& Widget::style() const {
return style_ ? *style_ : parent()->style();
}
void Widget::visible(bool v) {
if( v != flags.visible ) {
flags.visible = v;
/* TODO: This on_show/on_hide implementation seems inelegant.
* But I need *some* way to take/configure resources when
* a widget becomes visible, and reverse the process when the
* widget becomes invisible, whether the widget (or parent) is
* hidden, or the widget (or parent) is removed from the tree.
*/
if( v ) {
on_show();
} else {
on_hide();
// Set all children invisible too.
for(const auto child : children()) {
child->visible(false);
}
}
}
}
/* View ******************************************************************/
void View::set_parent_rect(const Rect new_parent_rect) {
Widget::set_parent_rect(new_parent_rect);
dirty_screen_rect += screen_rect();
}
void View::paint(Painter& painter) {
painter.fill_rectangle(
screen_rect(),
style().background
);
}
void View::add_child(Widget* const widget) {
if( widget->parent() == nullptr ) {
widget->set_parent(this);
children_.push_back(widget);
widget->set_dirty();
}
}
void View::add_children(const std::vector<Widget*>& children) {
for(auto child : children) {
add_child(child);
}
}
void View::remove_child(Widget* const widget) {
children_.erase(std::remove(children_.begin(), children_.end(), widget), children_.end());
dirty_screen_rect += widget->screen_rect();
widget->set_parent(nullptr);
if( dirty_screen_rect ) {
set_dirty();
}
}
const std::vector<Widget*> View::children() const {
return children_;
}
Widget* View::initial_focus() {
return nullptr;
}
/* Rectangle *************************************************************/
void Rectangle::set_color(const Color c) {
color = c;
set_dirty();
}
void Rectangle::paint(Painter& painter) {
painter.fill_rectangle(
screen_rect(),
color
);
}
/* Text ******************************************************************/
void Text::set(const std::string value) {
text = value;
set_dirty();
}
void Text::paint(Painter& painter) {
painter.draw_string(
screen_pos(),
style(),
text
);
}
/* Button ****************************************************************/
void Button::set_text(const std::string value) {
text_ = value;
set_dirty();
}
std::string Button::text() const {
return text_;
}
void Button::paint(Painter& painter) {
const auto r = screen_rect();
const auto paint_style = (has_focus() || flags.highlighted) ? style().invert() : style();
painter.draw_rectangle(r, style().foreground);
painter.fill_rectangle(
{
static_cast<Coord>(r.pos.x + 1), static_cast<Coord>(r.pos.y + 1),
static_cast<Dim>(r.size.w - 2), static_cast<Dim>(r.size.h - 2)
},
paint_style.background
);
const auto label_r = paint_style.font.size_of(text_);
painter.draw_string(
{
static_cast<Coord>(r.pos.x + (r.size.w - label_r.w) / 2),
static_cast<Coord>(r.pos.y + (r.size.h - label_r.h) / 2)
},
paint_style,
text_
);
}
bool Button::on_key(const KeyEvent key) {
if( key == KeyEvent::Select ) {
if( on_select ) {
on_select(*this);
return true;
}
}
return false;
}
bool Button::on_touch(const TouchEvent event) {
switch(event.type) {
case TouchEvent::Type::Start:
flags.highlighted = true;
set_dirty();
return true;
case TouchEvent::Type::End:
flags.highlighted = false;
set_dirty();
if( on_select ) {
on_select(*this);
}
return true;
default:
return false;
}
#if 0
switch(event.type) {
case TouchEvent::Type::Start:
flags.highlighted = true;
set_dirty();
return true;
case TouchEvent::Type::Move:
{
const bool new_highlighted = screen_rect().contains(event.point);
if( flags.highlighted != new_highlighted ) {
flags.highlighted = new_highlighted;
set_dirty();
}
}
return true;
case TouchEvent::Type::End:
if( flags.highlighted ) {
flags.highlighted = false;
set_dirty();
if( on_select ) {
on_select(*this);
}
}
return true;
default:
return false;
}
#endif
}
/* OptionsField **********************************************************/
size_t OptionsField::selected_index() const {
return selected_index_;
}
void OptionsField::set_selected_index(const size_t new_index) {
if( new_index < options.size() ) {
if( new_index != selected_index() ) {
selected_index_ = new_index;
if( on_change ) {
on_change(selected_index(), options[selected_index()].second);
}
set_dirty();
}
}
}
void OptionsField::set_by_value(value_t v) {
size_t new_index { 0 };
for(const auto& option : options) {
if( option.second >= v ) {
set_selected_index(new_index);
break;
}
new_index++;
}
}
void OptionsField::paint(Painter& painter) {
const auto paint_style = has_focus() ? style().invert() : style();
if( selected_index() < options.size() ) {
const auto text = options[selected_index()].first;
painter.draw_string(
screen_pos(),
paint_style,
text
);
}
}
bool OptionsField::on_encoder(const EncoderEvent delta) {
set_selected_index(selected_index() + delta);
return true;
}
bool OptionsField::on_touch(const TouchEvent event) {
if( event.type == TouchEvent::Type::Start ) {
focus();
}
return true;
}
/* NumberField ***********************************************************/
int32_t NumberField::value() const {
return value_;
}
void NumberField::set_value(int32_t new_value) {
new_value = clip_value(new_value);
if( new_value != value() ) {
value_ = new_value;
if( on_change ) {
on_change(value_);
}
set_dirty();
}
}
void NumberField::paint(Painter& painter) {
const auto text = to_string_dec_int(value_, length_, fill_char);
const auto paint_style = has_focus() ? style().invert() : style();
painter.draw_string(
screen_pos(),
paint_style,
text
);
}
bool NumberField::on_encoder(const EncoderEvent delta) {
set_value(value() + (delta * step));
return true;
}
bool NumberField::on_touch(const TouchEvent event) {
if( event.type == TouchEvent::Type::Start ) {
focus();
}
return true;
}
int32_t NumberField::clip_value(int32_t value) {
if( value > range.second ) {
value = range.second;
}
if( value < range.first ) {
value = range.first;
}
return value;
}
} /* namespace ui */
+322
View File
@@ -0,0 +1,322 @@
/*
* 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 __UI_WIDGET_H__
#define __UI_WIDGET_H__
#include "ui.hpp"
#include "ui_text.hpp"
#include "ui_painter.hpp"
#include "ui_focus.hpp"
#include "utility.hpp"
#include "lcd_ili9341.hpp"
#include "message.hpp"
#include <memory>
#include <vector>
#include <string>
namespace ui {
extern void dirty_event();
std::string to_string_dec_uint(const uint32_t n, const int32_t l, const char fill = 0);
std::string to_string_dec_int(const int32_t n, const int32_t l, const char fill = 0);
std::string to_string_hex(const uint32_t n, const int32_t l);
struct Context {
FocusManager focus_manager;
lcd::ILI9341 display;
MessageHandlerMap message_map;
};
class Widget {
public:
constexpr Widget(
) : parent_rect { }
{
}
constexpr Widget(
Rect parent_rect
) : parent_rect { parent_rect }
{
}
Widget(const Widget&) = delete;
Widget(Widget&&) = delete;
virtual ~Widget() = default;
Point screen_pos();
Size size() const;
Rect screen_rect();
virtual void set_parent_rect(const Rect new_parent_rect);
Widget* parent() const;
void set_parent(Widget* const widget);
bool hidden() const { return flags.hidden; }
void hidden(bool hide);
virtual void focus();
virtual void on_focus();
virtual void blur();
virtual void on_blur();
bool focusable() const;
bool has_focus();
virtual Widget* last_child_focus() const;
virtual void set_last_child_focus(Widget* const child);
virtual void paint(Painter& painter) = 0;
virtual void on_show() { };
virtual void on_hide() { };
virtual bool on_key(const KeyEvent event);
virtual bool on_encoder(const EncoderEvent event);
virtual bool on_touch(const TouchEvent event);
virtual const std::vector<Widget*> children() const;
virtual Context& context() const;
void set_style(const Style* new_style);
const Style& style() const;
// State management methods.
void set_dirty();
bool dirty() const;
void set_clean();
void visible(bool v);
protected:
/* Widget rectangle relative to parent pos(). */
Rect parent_rect;
const Style* style_ { nullptr };
Widget* parent_ { nullptr };
struct flags_t {
bool dirty : 1; // Widget content has changed.
bool hidden : 1; // Hide widget and children.
bool focusable : 1; // Widget can receive focus.
bool highlighted : 1; // Show in a highlighted style.
bool visible : 1; // Object was visible during last paint.
};
flags_t flags {
.dirty = true,
.hidden = false,
.focusable = false,
.highlighted = false,
.visible = false,
};
};
class View : public Widget {
public:
View() {
}
View(Rect parent_rect) {
set_parent_rect(parent_rect);
}
// TODO: ~View() should on_hide() all children?
void set_parent_rect(const Rect new_parent_rect) override;
void paint(Painter& painter) override;
void add_child(Widget* const widget);
void add_children(const std::vector<Widget*>& children);
void remove_child(Widget* const widget);
const std::vector<Widget*> children() const override;
virtual Widget* initial_focus();
protected:
std::vector<Widget*> children_;
Rect dirty_screen_rect;
void invalidate_child(Widget* const widget);
};
class Rectangle : public Widget {
public:
constexpr Rectangle(
const Rect parent_rect,
const Color c
) : Widget { parent_rect },
color { c }
{
}
void paint(Painter& painter) override;
void set_color(const Color c);
private:
Color color;
};
class Text : public Widget {
public:
Text(
) : text { "" } {
}
Text(
Rect parent_rect,
std::string text
) : Widget { parent_rect },
text { text }
{
}
Text(
Rect parent_rect
) : Text { parent_rect, { } }
{
}
void set(const std::string value);
void paint(Painter& painter) override;
private:
std::string text;
};
class Button : public Widget {
public:
std::function<void(Button&)> on_select;
Button(
Rect parent_rect,
std::string text
) : Widget { parent_rect },
text_ { text }
{
flags.focusable = true;
}
Button(
) : Button { { }, { } }
{
}
void set_text(const std::string value);
std::string text() const;
void paint(Painter& painter) override;
bool on_key(const KeyEvent key) override;
bool on_touch(const TouchEvent event) override;
private:
std::string text_;
};
class OptionsField : public Widget {
public:
using name_t = std::string;
using value_t = int32_t;
using option_t = std::pair<name_t, value_t>;
using options_t = std::vector<option_t>;
std::function<void(size_t, value_t)> on_change;
OptionsField(
Point parent_pos,
size_t length,
options_t options
) : Widget { { parent_pos, { static_cast<ui::Dim>(8 * length), 16 } } },
length_ { length },
options { options }
{
flags.focusable = true;
}
size_t selected_index() const;
void set_selected_index(const size_t new_index);
void set_by_value(value_t v);
void paint(Painter& painter) override;
bool on_encoder(const EncoderEvent delta) override;
bool on_touch(const TouchEvent event) override;
private:
const size_t length_;
options_t options;
size_t selected_index_ { 0 };
};
class NumberField : public Widget {
public:
std::function<void(int32_t)> on_change;
using range_t = std::pair<int32_t, int32_t>;
NumberField(
Point parent_pos,
size_t length,
range_t range,
int32_t step,
char fill_char
) : Widget { { parent_pos, { static_cast<ui::Dim>(8 * length), 16 } } },
range { range },
step { step },
length_ { length },
fill_char { fill_char }
{
flags.focusable = true;
}
NumberField(const NumberField&) = delete;
NumberField(NumberField&&) = delete;
int32_t value() const;
void set_value(int32_t new_value);
void paint(Painter& painter) override;
bool on_encoder(const EncoderEvent delta) override;
bool on_touch(const TouchEvent event) override;
private:
const range_t range;
const int32_t step;
const size_t length_;
const char fill_char;
int32_t value_;
int32_t clip_value(int32_t value);
};
} /* namespace ui */
#endif/*__UI_WIDGET_H__*/
+128
View File
@@ -0,0 +1,128 @@
/*
* 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 <ch.h>
#include "utility.hpp"
#include <cstdint>
#if 0
uint32_t gcd(const uint32_t u, const uint32_t v) {
/* From http://en.wikipedia.org/wiki/Binary_GCD_algorithm */
if( u == v ) {
return u;
}
if( u == 0 ) {
return v;
}
if( v == 0 ) {
return u;
}
if( ~u & 1 ) {
if( v & 1 ) {
return gcd(u >> 1, v);
} else {
return gcd(u >> 1, v >> 1) << 1;
}
}
if( ~v & 1 ) {
return gcd(u, v >> 1);
}
if( u > v ) {
return gcd((u - v) >> 1, v);
}
return gcd((v - u) >> 1, u);
}
#endif
/* GCD implementation derived from recursive implementation at
* http://en.wikipedia.org/wiki/Binary_GCD_algorithm
*/
static constexpr uint32_t gcd_top(const uint32_t u, const uint32_t v);
static constexpr uint32_t gcd_larger(const uint32_t u, const uint32_t v) {
return (u > v) ? gcd_top((u - v) >> 1, v) : gcd_top((v - u) >> 1, u);
}
static constexpr uint32_t gcd_u_odd_v_even(const uint32_t u, const uint32_t v) {
return (~v & 1) ? gcd_top(u, v >> 1) : gcd_larger(u, v);
}
static constexpr uint32_t gcd_v_odd(const uint32_t u, const uint32_t v) {
return (v & 1)
? gcd_top(u >> 1, v)
: (gcd_top(u >> 1, v >> 1) << 1);
}
static constexpr uint32_t gcd_u_even(const uint32_t u, const uint32_t v) {
return (~u & 1)
? gcd_v_odd(u, v)
: gcd_u_odd_v_even(u, v)
;
}
static constexpr uint32_t gcd_v_zero(const uint32_t u, const uint32_t v) {
return (v == 0) ? u : gcd_u_even(u, v);
}
static constexpr uint32_t gcd_u_zero(const uint32_t u, const uint32_t v) {
return (u == 0) ? v : gcd_v_zero(u, v);
}
static constexpr uint32_t gcd_uv_equal(const uint32_t u, const uint32_t v) {
return (u == v) ? u : gcd_u_zero(u, v);
}
static constexpr uint32_t gcd_top(const uint32_t u, const uint32_t v) {
return gcd_uv_equal(u, v);
}
uint32_t gcd(const uint32_t u, const uint32_t v) {
return gcd_top(u, v);
}
/* Memory management, overriding toolchain new, which uses malloc */
/* TODO: Move to something like "memory.cpp"! Not utility.cpp. */
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);
}
+117
View File
@@ -0,0 +1,117 @@
/*
* 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 __UTILITY_H__
#define __UTILITY_H__
#include <type_traits>
#include <cstdint>
#include <cstddef>
#include <memory>
#include <hal.h>
#define LOCATE_IN_RAM __attribute__((section(".ramtext")))
template<typename E>
constexpr typename std::underlying_type<E>::type toUType(E enumerator) noexcept {
/* Thanks, Scott Meyers! */
return static_cast<typename std::underlying_type<E>::type>(enumerator);
}
inline uint32_t flp2(uint32_t v) {
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return v - (v >> 1);
}
uint32_t gcd(const uint32_t u, const uint32_t v);
template<class T>
inline constexpr T pow(const T base, unsigned const exponent) {
return (exponent == 0) ? 1 : (base * pow(base, exponent - 1));
}
#if defined(LPC43XX_M4)
static inline bool m4_flag_saturation() {
return __get_APSR() & (1U << 27);
}
static inline void clear_m4_flag_saturation() {
uint32_t flags = 1;
__asm volatile ("MSR APSR_nzcvqg, %0" : : "r" (flags));
}
#endif
/* 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);
namespace std {
/*! Stephan T Lavavej (STL!) implementation of make_unique, which has been accepted into the C++14 standard.
* It includes handling for arrays.
* Paper here: http://isocpp.org/files/papers/N3656.txt
*/
template<class T> struct _Unique_if {
typedef unique_ptr<T> _Single_object;
};
//! Specialization for unbound array
template<class T> struct _Unique_if<T[]> {
typedef unique_ptr<T[]> _Unknown_bound;
};
//! Specialization for array of known size
template<class T, size_t N> struct _Unique_if<T[N]> {
typedef void _Known_bound;
};
//! Specialization for normal object type
template<class T, class... Args>
typename _Unique_if<T>::_Single_object
make_unique(Args&& ... args) {
return unique_ptr<T>(new T(std::forward<Args>(args)...));
}
//! Specialization for unknown bound
template<class T>
typename _Unique_if<T>::_Unknown_bound
make_unique(size_t n) {
typedef typename remove_extent<T>::type U;
return unique_ptr<T>(new U[n]());
}
//! Deleted specialization
template<class T, class... Args>
typename _Unique_if<T>::_Known_bound
make_unique(Args&& ...) = delete;
} /* namespace std */
#endif/*__UTILITY_H__*/
+108
View File
@@ -0,0 +1,108 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Fvoranklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __VOLUME_H__
#define __VOLUME_H__
#include <cstdint>
class volume_t {
public:
constexpr volume_t operator-() const {
return { .cb = -cb };
}
constexpr volume_t operator+(const volume_t& other) const {
return { .cb = cb + other.cb };
}
constexpr volume_t operator-(const volume_t& other) const {
return { .cb = cb - other.cb };
}
volume_t& operator+=(const volume_t& other) {
cb += other.cb;
return *this;
}
constexpr bool operator<(const volume_t& other) const {
return cb < other.cb;
}
constexpr bool operator>(const volume_t& other) const {
return cb > other.cb;
}
static constexpr volume_t centibel(const int cb) {
return { .cb = cb };
}
static constexpr volume_t decibel(const int db) {
return { .cb = db * 10 };
}
int32_t centibel() const {
return cb;
}
int32_t decibel() const {
return cb / 10;
}
private:
int32_t cb;
constexpr volume_t(
const int cb
) : cb(cb)
{
}
};
constexpr volume_t operator"" _cB(long double v) {
return volume_t::centibel(v);
}
constexpr volume_t operator"" _dB(long double v) {
return volume_t::centibel(v * 10);
}
struct volume_range_t {
volume_t min;
volume_t max;
volume_t limit(const volume_t value) const {
if( value < min ) {
return min;
}
if( value > max ) {
return max;
}
return value;
}
volume_t normalize(const volume_t value) const {
/* Limit volume to specified range, and adjust minimum value to 0. */
return limit(value) - min;
}
};
#endif/*__VOLUME_H__*/
+40
View File
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2014 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include <cstdint>
#include <array>
#include "wm8731.hpp"
namespace wolfson {
namespace wm8731 {
void WM8731::write(const address_t reg_address, const reg_t value) {
const uint16_t word = (reg_address << 9) | value;
const std::array<uint8_t, 2> values {
static_cast<uint8_t>(word >> 8),
static_cast<uint8_t>(word & 0xff),
};
bus.transmit(bus_address, values.data(), values.size());
}
} /* namespace wm8731 */
} /* namespace wolfson */
+462
View File
@@ -0,0 +1,462 @@
/*
* 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 __WM8731_H__
#define __WM8731_H__
#include <cstdint>
#include "i2c_pp.hpp"
#include "wm8731.hpp"
#include "utility.hpp"
#include "volume.hpp"
namespace wolfson {
namespace wm8731 {
constexpr volume_range_t headphone_gain_range { -121.0_dB, 6.0_dB };
constexpr volume_range_t line_in_gain_range { -34.5_dB, 12.0_dB };
enum class ADCSource {
Line = 0,
Microphone = 1,
};
using address_t = uint8_t;
using reg_t = uint16_t;
constexpr size_t reg_count = 10;
enum class Register : address_t {
LeftLineIn = 0x00,
RightLineIn = 0x01,
LeftHeadphoneOut = 0x02,
RightHeadphoneOut = 0x03,
AnalogAudioPathControl = 0x04,
DigitalAudioPathControl = 0x05,
PowerDownControl = 0x06,
DigitalAudioInterfaceFormat = 0x07,
SamplingControl = 0x08,
ActiveControl = 0x09,
};
struct LeftLineIn {
reg_t linvol : 5;
reg_t reserved0 : 2;
reg_t linmute : 1;
reg_t lrinboth : 1;
reg_t reserved1 : 7;
};
static_assert(sizeof(LeftLineIn) == sizeof(reg_t), "LeftLineIn type wrong size");
struct RightLineIn {
reg_t rinvol : 5;
reg_t reserved0 : 2;
reg_t rinmute : 1;
reg_t rlinboth : 1;
reg_t reserved1 : 7;
};
static_assert(sizeof(RightLineIn) == sizeof(reg_t), "RightLineIn type wrong size");
struct LeftHeadphoneOut {
reg_t lhpvol : 7;
reg_t lzcen : 1;
reg_t lrhpboth : 1;
reg_t reserved0 : 7;
};
static_assert(sizeof(LeftHeadphoneOut) == sizeof(reg_t), "LeftHeadphoneOut type wrong size");
struct RightHeadphoneOut {
reg_t rhpvol : 7;
reg_t rzcen : 1;
reg_t rlhpboth : 1;
reg_t reserved0 : 7;
};
static_assert(sizeof(RightHeadphoneOut) == sizeof(reg_t), "RightHeadphoneOut type wrong size");
struct AnalogAudioPathControl {
reg_t micboost : 1;
reg_t mutemic : 1;
reg_t insel : 1;
reg_t bypass : 1;
reg_t dacsel : 1;
reg_t sidetone : 1;
reg_t sideatt : 2;
reg_t reserved0 : 8;
};
static_assert(sizeof(AnalogAudioPathControl) == sizeof(reg_t), "AnalogAudioPathControl type wrong size");
struct DigitalAudioPathControl {
reg_t adchpd : 1;
reg_t deemp : 2;
reg_t dacmu : 1;
reg_t hpor : 1;
reg_t reserved0 : 11;
};
static_assert(sizeof(DigitalAudioPathControl) == sizeof(reg_t), "DigitalAudioPathControl type wrong size");
struct PowerDownControl {
reg_t lineinpd : 1;
reg_t micpd : 1;
reg_t adcpd : 1;
reg_t dacpd : 1;
reg_t outpd : 1;
reg_t oscpd : 1;
reg_t clkoutpd : 1;
reg_t poweroff : 1;
reg_t reserved0 : 8;
};
static_assert(sizeof(PowerDownControl) == sizeof(reg_t), "PowerDownControl type wrong size");
struct DigitalAudioInterfaceFormat {
reg_t format : 2;
reg_t iwl : 2;
reg_t lrp : 1;
reg_t lrswap : 1;
reg_t ms : 1;
reg_t bclkinv : 1;
reg_t reserved0 : 8;
};
static_assert(sizeof(DigitalAudioInterfaceFormat) == sizeof(reg_t), "DigitalAudioInterfaceFormat type wrong size");
struct SamplingControl {
reg_t usb_normal : 1;
reg_t bosr : 1;
reg_t sr : 4;
reg_t clkidiv2 : 1;
reg_t clkodiv2 : 1;
reg_t reserved0 : 8;
};
static_assert(sizeof(SamplingControl) == sizeof(reg_t), "SamplingControl type wrong size");
struct ActiveControl {
reg_t active : 1;
reg_t reserved0 : 15;
};
static_assert(sizeof(ActiveControl) == sizeof(reg_t), "ActiveControl type wrong size");
struct Reset {
reg_t reset : 9;
reg_t reserved0 : 7;
};
static_assert(sizeof(Reset) == sizeof(reg_t), "Reset type wrong size");
struct Register_Type {
LeftLineIn left_line_in;
RightLineIn right_line_in;
LeftHeadphoneOut left_headphone_out;
RightHeadphoneOut right_headphone_out;
AnalogAudioPathControl analog_audio_path_control;
DigitalAudioPathControl digital_audio_path_control;
PowerDownControl power_down_control;
DigitalAudioInterfaceFormat digital_audio_interface_format;
SamplingControl sampling_control;
ActiveControl active_control;
};
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 {
.left_line_in = {
.linvol = 0b10111,
.reserved0 = 0b00,
.linmute = 0b1,
.lrinboth = 0b0,
.reserved1 = 0,
},
.right_line_in = {
.rinvol = 0b10111,
.reserved0 = 0b00,
.rinmute = 0b1,
.rlinboth = 0b0,
.reserved1 = 0,
},
.left_headphone_out = {
.lhpvol = 0b1111001,
.lzcen = 0b0,
.lrhpboth = 0b0,
.reserved0 = 0,
},
.right_headphone_out = {
.rhpvol = 0b1111001,
.rzcen = 0b0,
.rlhpboth = 0b0,
.reserved0 = 0,
},
.analog_audio_path_control = {
.micboost = 0b0,
.mutemic = 0b1,
.insel = 0b0,
.bypass = 0b1,
.dacsel = 0b0,
.sidetone = 0b0,
.sideatt = 0b00,
.reserved0 = 0,
},
.digital_audio_path_control = {
.adchpd = 0b0,
.deemp = 0b00,
.dacmu = 0b1,
.hpor = 0b0,
.reserved0 = 0,
},
.power_down_control = {
.lineinpd = 0b1,
.micpd = 0b1,
.adcpd = 0b1,
.dacpd = 0b1,
.outpd = 0b1,
.oscpd = 0b0,
.clkoutpd = 0b0,
.poweroff = 0b1,
.reserved0 = 0,
},
.digital_audio_interface_format = {
.format = 0b10,
.iwl = 0b10,
.lrp = 0b0,
.lrswap = 0b0,
.ms = 0b0,
.bclkinv = 0b0,
.reserved0 = 0,
},
.sampling_control = {
.usb_normal = 0b0,
.bosr = 0b0,
.sr = 0b0000,
.clkidiv2 = 0b0,
.clkodiv2 = 0b0,
.reserved0 = 0,
},
.active_control = {
.active = 0b0,
.reserved0 = 0,
},
} };
class WM8731 {
public:
constexpr WM8731(
I2C& bus,
const I2C::address_t bus_address
) : bus(bus),
bus_address(bus_address)
{
}
void init() {
reset();
write(PowerDownControl {
.lineinpd = 1,
.micpd = 0,
.adcpd = 0,
.dacpd = 0,
.outpd = 0,
.oscpd = 1,
.clkoutpd = 1,
.poweroff = 0,
.reserved0 = 0,
});
// write(SamplingControl {
// .usb_normal = 0,
// .bosr = 0,
// .sr = 0,
// .clkidiv2 = 0,
// .clkodiv2 = 0,
// .reserved0 = 0,
// });
write(DigitalAudioInterfaceFormat {
.format = 2,
.iwl = 0,
.lrp = 0,
.lrswap = 0,
.ms = 0,
.bclkinv = 0,
.reserved0 = 0,
});
write(DigitalAudioPathControl {
.adchpd = 0,
.deemp = 0,
.dacmu = 0,
.hpor = 0,
.reserved0 = 0,
});
write(AnalogAudioPathControl {
.micboost = 1, // Enable 20dB boost
.mutemic = 0, // Disable mute (unmute)
.insel = 1, // Microphone input to ADC
.bypass = 0,
.dacsel = 1,
.sidetone = 0,
.sideatt = 0,
.reserved0 = 0,
});
write(ActiveControl {
.active = 1,
.reserved0 = 0,
});
set_line_in_volume(0.0_dB);
headphone_mute();
}
void reset() {
write(0x0f, 0);
}
void set_line_in_volume(const volume_t volume) {
const auto normalized = line_in_gain_range.normalize(volume);
auto n = normalized.centibel() / 15;
write(LeftLineIn {
.linvol = static_cast<reg_t>(n),
.reserved0 = 0,
.linmute = 0,
.lrinboth = 1,
.reserved1 = 0,
});
}
void set_headphone_volume(const volume_t volume) {
const auto normalized = headphone_gain_range.normalize(volume);
auto n = normalized.centibel() / 10;
write(LeftHeadphoneOut {
.lhpvol = static_cast<reg_t>(n),
.lzcen = 1,
.lrhpboth = 1,
.reserved0 = 0,
});
}
void headphone_mute() {
set_headphone_volume(headphone_gain_range.min);
}
// void microphone_mute(const bool mute) {
// map.r.analog_audio_path_control.mutemic = (mute ? 0 : 1);
// write(Register::AnalogAudioPathControl);
// }
// void set_adc_source(const ADCSource adc_source) {
// map.r.analog_audio_path_control.insel = toUType(adc_source);
// write(Register::AnalogAudioPathControl);
// }
private:
I2C& bus;
const I2C::address_t bus_address;
RegisterMap map { default_after_reset };
void write(const Register reg) {
write(toUType(reg), map.w[toUType(reg)]);
}
void write(const address_t reg_address, const reg_t value);
void write(const LeftLineIn value) {
map.r.left_line_in = value;
write(Register::LeftLineIn);
}
void write(const RightLineIn value) {
map.r.right_line_in = value;
write(Register::RightLineIn);
}
void write(const LeftHeadphoneOut value) {
map.r.left_headphone_out = value;
write(Register::LeftHeadphoneOut);
}
void write(const RightHeadphoneOut value) {
map.r.right_headphone_out = value;
write(Register::RightHeadphoneOut);
}
void write(const AnalogAudioPathControl value) {
map.r.analog_audio_path_control = value;
write(Register::AnalogAudioPathControl);
}
void write(const DigitalAudioPathControl value) {
map.r.digital_audio_path_control = value;
write(Register::DigitalAudioPathControl);
}
void write(const PowerDownControl value) {
map.r.power_down_control = value;
write(Register::PowerDownControl);
}
void write(const DigitalAudioInterfaceFormat value) {
map.r.digital_audio_interface_format = value;
write(Register::DigitalAudioInterfaceFormat);
}
void write(const SamplingControl value) {
map.r.sampling_control = value;
write(Register::SamplingControl);
}
void write(const ActiveControl value) {
map.r.active_control = value;
write(Register::ActiveControl);
}
};
} /* namespace wm8731 */
} /* namespace wolfson */
#endif/*__WM8731_H__*/